PHP - những điều cần biết

Mục lục

  • Các đặc điểm cơ bản của lập trình hướng đối tượng. Chúng được thể hiện như thế nào trong PHP
  • Sự khác biệt giữa Abstract Class và Interface.
  • Thế nào là một phương thức static. Phân biệt cách dùng từ khoá static::method() với self::method()
  • Thế nào là Trait
  • Thế nào là Namespaces
  • Thế nào là magic methods
  • Tìm hiểu về các quy tắc trong PSR2
  • Các phương pháp thiết kế hướng đối tượng (SOLID).

Nội dung

Các đặc điểm cơ bản của lập trình hướng đối tượng

1. Tính trừu tượng (Abstraction)

Việc bỏ qua hoặc ẩn đi những xử lý phức tạp bên dưới, chỉ đưa ra các chức năng hoặc tập trung vào các cốt lõi cần thiết được gọi là tính trừu tượng của dữ liệu.

Như vậy khi tương tác với đối tượng chỉ cần quan tâm đến các thuộc tính, phương thức cần thiết. Chi tiết về nội dung không cần chú ý đến.

PHP có abstract class và interface để trừu tượng hóa các đối tượng

2. Tính đóng gói (Encapsulation)

Tính chất này không cho phép người dùng trực tiếp tác động đến dữ liệu bên trong đối tượng mà phải thông qua các phương thức mà đối tượng cung cấp. Tính chất này đảm bảo tính toàn vẹn của đối tượng.

Trong PHP, có các access modifier quy định phạm vi sử dụng của thuộc tính và phương th:

  • private: các thuộc tính và phương thức private chỉ có thể truy cập từ bên trong class
  • protected: các thuộc tính và phương thức protected có thể truy cập từ bên trong class và các class kế thừa nó
  • public: các thuộc tính và phương thức public có thể truy cập từ bên ngoài

3. Tính kế thừa (Inheritance)

Đặc tính này cho phép một đối tượng có thể có sẵn các thuộc tính, phương thức mà đối tượng khác đã có thông qua kế thừa. Điều này cho phép các đối tượng có thể tái sử dụng hay mở rộng các đặc tính sẵn có mà không phải tiến hành định nghĩa lại.

Trong PHP, một lớp có thể kế thừa từ một lớp khác. Đối tượng thuộc lớp con sẽ có các thuộc tính và phương thức protected và public của lớp mà nó kế thừa.

4. Tính đa hình (Polymorphism)

Thể hiện qua việc có thể định nghĩa một đặc tính, hoặc phương thức cho một loạt các đối tượng gần giống nhau. Nhưng khi thực hiện thì các đối tượng khác nhau sẽ có cách thực hiện khác nhau và cho ra kết quả khác nhau.

Ví dụ: Đối tượng "hình vuông" và "hình tròn" có chung 1 phương thức là "chu_vi". Khi gọi phương thức này thì với mỗi đối tượng sẽ có 1 công thức tính khác nhau và cho ra kết quả khác nhau.

Trong PHP:

  • Các lớp con có thể viết lại hoặc mở rộng phương thức của lớp cha mà nó kế thừa.
  • Các class cùng implement một interface nhưng chúng có cách thức thực hiện khác nhau cho các method của interface đó. Qua đó cùng 1 phương thức sẽ cho kết quả khác nhau khi được gọi bởi các đối tượng thuộc lớp khác nhau.

Sự khác biệt giữa Abstract Class và Interface

|===============|=======================================|===============================================|
|               | Abstract Class                        |   Interface                                   |
|===============|=======================================|===============================================|
|  Khái niệm    |  Abstract Class là  một class cha cho |  Interface được xem như một mặt nạ cho tất cả |
|               |  tất cả các Class có cùng bản chất    |  các Class cùng cách thức hoạt động nhưng     |
|               |                                       |  có thể khác nhau về bản chất.                |
|---------------|---------------------------------------|-----------------------------------------------|
|               | - Không thể khởi tạo đối tượng từ Abstract Class và Interface                         |
| Giống nhau    | - Có thể khai báo các phương thức Abstract                                            |
|               |   (Chỉ khai báo phương thức mà không thực hiện chúng)                                 |
|               | - Các lớp kế thừa Abstract Class và Interface phải định nghĩa tất cả các phương thức  |
|               |   Abstract của chúng                                                                  |
|               |                                                                                       |
|---------------|---------------------------------------|-----------------------------------------------|
| Khác nhau     | - Các lớp con chỉ có thể kế thừa      | - Các lớp con có thể implement nhiều interface|
|               |   (extend) 1 Abstract Class           |   (Đa kế thừa)                                |
|               | - Có thể chứa các phương thức,        | - Chỉ chứa phương thức Abstract               |
|               |   thuộc tính và hằng bình thường      |                                               |
|               | - Có thể chứa các phương thức static, | - Không thể chứa các phương thức static,      |
|               |   constructor                         |   constructor                                 |
|               | - Có thể implements interface         | - Có thể extends interface khác               |
|               |   và extends class khác như           |                                               |
|               |   class bình thường                   |                                               |
|               |                                       |                                               |
|---------------|---------------------------------------|-----------------------------------------------|
|  Khi nào      | - Khi cần tạo 1 lớp cơ sở cho các lớp | - Khi cần khai báo 1 bộ khung cho             |
|    nên dùng   |   khác mà cần có một số phương thức   |   một số class                                |
|               |   hoàn chỉnh trong lớp cơ sỏ đó       | - Tất cả các phương thức đều dang dở          |
|               |                                       |                                               |
|---------------|---------------------------------------|-----------------------------------------------|

Chú ý:

  • Nếu một class implements nhiều interface mà các interface có những phương thức cùng tên thì sẽ không lỗi nếu các phương thức đó truyền vào số lượng biến bằng nhau. Còn nếu các phương thức đó khác số lượng biến truyền vào thì sẽ sinh ra lỗi "Fatal error".

Phương thức static

Khái niệm

Phương thức Static là phương thức có thể truy cập mà không cần khởi tạo một đối tượng của class.

Khai báo:

    public static function aStaticMethod() {
        // ...
    }

Lưu ý:

  • Trong 1 phương thức static không thể gọi 1 phương thức hoặc thuộc tính non-static. Nhưng 1 phương thức non-static có thể gọi 1 phương thức hoặc thuộc tính static. Vì hàm static có thể thực thi khi chưa khởi tạo đối tượng. Nếu hàm static gọi được 1 hàm non-static thì hàm non-static sẽ không thực thi được do chưa có đối tượng nên biến $this sẽ không tồn tại. Ngược lại thì được vì hàm static có thể được thực thi cả khi có hoặc không có đối tượng. Việc thực thi hàm static trong đối tượng có thể thực hiện bằng lệnh: static::method(), self::method() hoặc $this->method()

Phân biệt static::method() với self::method()

|===============|======================================================================================|
|               | static::method()                     |   self::method()                              |
|===============|======================================================================================|
|  Giống nhau   | - Sử dụng cho các phương thức static trong class                                     |
|---------------|--------------------------------------------------------------------------------------|
|  Khác nhau    | - Gọi method static của lớp hiện tại | - Gọi method của lớp gốc. Nếu lớp cha mà nó   |
|               |                                      |   kế thừa có khai báo method này thì method   |
|               |                                      |   của lớp cha sẽ gọi đến ngay cả khi lớp con  |
|               |                                      |   (lớp hiện tại) có khai báo ghi đè method đó.|
|               |                                      |                                               |
|---------------|--------------------------------------|-----------------------------------------------|

Trait

Trong PHP khái niệm Traits được đưa vào để giải quyết các vấn đề của đa kế thừa. PHP là ngôn ngữ không hỗ trợ đa kế thừa, với 1 lớp được mở rộng từ 2 hay nhiều lớp khác thì ta phải sử dụng đến Traits. Nếu mỗi lớp được kế thừa cài đặt cùng 1 phương thức thì PHP không biết phương thức nào được ưu tiên thực thi nên kết quả trả về sẽ là lỗi "Fatal error".

Namespaces (không gian tên)

Namespace là một cơ chế cho phép chúng ta phân nhóm các Class, function thành những nhóm riêng biệt. Mỗi nhóm đó đặt đặt cho 1 cái tên gọi là namespace. Mỗi namespace có thể chứa 1 hay 1 số namespace khác. Việc dùng Namespace sẽ để tránh xung đột khi sử dụng nhiều thư viện, trong code có các class với tên giống nhau.

Magic methods

Magic methods là các hàm đặc biệt được tự động thực thi khi thực hiện một số hành động nhất định lên đối tượng của class đó. Magic methods luôn có dạng __<method_name>.

Một số Magic methods:

  • __construct(): Thực hiện khi khởi tạo đối tượng
  • __destruct(): Thực hiện khi hủy bỏ đối tượng
  • __get(), __set(), __unset(): Khi cố gắng truy cập, thay đổi, xóa thuộc tính không có sẵn trong đối tượng
  • __call(), __callStatic(): Khi gọi hàm không có sẵn
  • __toString(): Thực hiện khi được sử dụng như string
  • __invoke(): Khi đối tượng được sử dụng như một hàm
  • __sleep(), __awake(): Khi gọi hàm serialize, unserialize lên đối tượng
  • __clone(): Khi clone đối tượng
  • __set_state(), __debugInfo(): Khi gọi var_export, var_dump lên đối tượng

Quy tắc trong PSR2

Code theo chuẩn PSR2 phải tuân thủ các quy tắc sau

  • Code PHẢI tuân thủ PSR-1.
  • Code PHẢI sử dụng 4 ký tự space để lùi khối (không dùng tab).
  • Mỗi dòng code PHẢI dưới 120 ký tự, NÊN dưới 80 ký tự.
  • PHẢI có 1 dòng trắng sau namespace, và PHẢI có một dòng trắng sau mỗi khối code.
  • Ký tự mở lớp { PHẢI ở dòng tiếp theo sau tên class, và đóng lớp } PHẢI ở dòng tiếp theo của thân class.
  • Ký tự { cho hàm PHẢI ở dòng tiếp theo sau tên hàm, và ký tự } kết thúc hàm PHẢI ở dòng tiếp theo của thân hàm.
  • Các visibility (public, private, protected) PHẢI được khai báo cho tất cả các hàm và các thuộc tính của lớp.
  • Các từ khóa điều khiển khối(if, elseif, else) PHẢI có một khoảng trống sau chúng, hàm và lớp thì KHÔNG ĐƯỢC làm như vậy.
  • Mở khối { cho cấu trúc điều khiển PHẢI trên cùng một dòng và đóng khối này } với ở dòng tiếp theo của thân khối.
  • Hằng số true, false, null PHẢI viết với chữ thường.
  • Từ khóa extendsimplements PHẢi cùng dòng với class.
  • Implements nhiều lớp, thì mỗi lớp trên một dòng.
  • Keyword var KHÔNG ĐƯỢC dùng sử dụng khai báo property.
  • Tên property KHÔNG NÊN có tiền tố _ nhằm thể hiện thuộc protect hay private.
  • Tham số cho hàm, phương thức: KHÔNG được thêm space vào trước dấu , và PHẢI có một space sau ,.
  • Các tham số CÓ THỂ trên nhiều dòng, nếu làm như vậy thì PHẢI mỗi dòng 1 tham số.
  • abstract, final PHẢI đứng trước visibility, còn static PHẢI đứng sau.

Các quy tắc liên quan

  • Tiêu chuẩn PSR-1 chuẩn cơ bản:
    • Các file code PHẢI sử dụng thẻ <?php hoặc <?
    • File code PHP sử dụng encode: UTF-8 without BOOM
    • Các Files NÊN hoặc dùng để khai báo các thành phần PHP (các lớp, hàm, hằng ...) hoặc dùng với mục đích làm hiệu ứng phụ (như include, thiết lập ini cho PHP ...), nhưng KHÔNG NÊN dùng cả 2 cùng lúc trong 1 file
    • Các Namespace và classes PHẢI theo chuẩn "autoloading" PSR: [PSR-0 và PSR-4]
    • Tên lớp PHẢI có dạng NameClass (chữ không nameclass, Nameclass, namClass ...)
    • Hằng số trong class tất cả PHẢI viết HOA và chia ra bởi dấu _
    • Tên phương thức của lớp PHẢI ở dạng camelCase (từ đầu viết thường, ví dụ: helloWorld)
  • Tiêu chuẩn PSR-0 chuẩn Autoloading:
    • Một namespace và class đầy đủ điều kiện (fully qualified) PHẢI có cấu trúc như sau \<Vendor Name>\(<Namespace>\)*<Class Name>
    • Mỗi namespace PHẢI có một top-level namespace ("Vendor name" - có thể hiểu là namespace gốc)
    • Mỗi namespace CÓ THỂ có nhiều sub-namespace (namespace con)
    • Mỗi namespace phân biệt được chuyển đến thư mục phân biệt khi load từ hệ thống.
    • Mỗi kí tự _ trong TÊN CLASS được chuyển đến một thư mục riêng biệt. Kí tự _ không có ý nghĩa đặc biệt gì trong namespace.
    • Namespace và class đầy đủ điều kiện có hậu tố .php khi load từ hệ thống
    • Kí tự chữ cái trong Vendor name, namespaces, và class CÓ THỂ là tổ hợp của kí tự thường và hoa.
  • Tiêu chuẩn PSR-4 quy tắc lưu trữ file được load:
    • "Class" ở đây ám chỉ cho classes, interface, traits và những cấu trúc tương tự khác.
    • Tên xác định đầy đủ của 1 "class" có dạng: \<NamespaceName>(\<SubNamespaceNames>)*\<ClassName>
      • Tên xác định đầy đủ PHẢI có một namespace gốc (hiểu là tên vendor).
      • Tên xác định đầy đủ CÓ THỂ có một hoặc nhiều namespace con.
      • Tên đầy đủ nó PHẢI có một tên class kết thúc (ClassName).
      • Kí tự _ không có ý nghĩa đặc biệt trong tên class đầy đủ.
      • Kí tự chữ cái trong tên class đầy đủ CÓ THỂ là tổ hợp của kí tự thường và hoa.
      • Tất cả tên class PHẢI được tham chiếu trong một cách phù hợp.
    • Khi nạp một file thì nó phải tương ứng với một tên xác định đầy đủ của class.
      • Một loạt liên tiếp của 1 hoặc nhiều leading namespace và sub-namespace không bao gồm các dấu phân cách trong tên class đầy đủ (có thể hiểu là "namespace prefix") tương ứng với ít nhất 1 "thư mục cơ sở".
      • Một loạt liên tiếp sub-namespace sau "namespace prefix" tương ứng với 1 thư mục con trong "thư mục cơ sở", mỗi namespace riêng biệt tương ứng với thư mục riêng biệt. Tên thư mục con PHẢI phù hợp với sub-namespace.
      • Tên class kết thúc tương ứng với tên file <ClassName>.php
      • Triển khai tự động nạp PHẢI KHÔNG throw exception, PHẢI KHÔNG gây ra lỗi ở bất kì level, và KHÔNG NÊN trả về giá trị.

Kết luận

Trên đây là một số khái niệm và quy tắc cơ bản khi lập trình PHP. Hi vọng sẽ giúp ích được cho mọi người.


All Rights Reserved