Menu

Lớp và đối tượng trong PHP: thuộc tính, phương thức, $this

Lớp trong PHP là một bản thiết kế khai báo bằng class Name { }, còn new Name() tạo ra một đối tượng từ lớp đó. Tìm hiểu thuộc tính, phương thức, $this, public/private/protected, thuộc tính có kiểu và readonly, __toString, và vì sao gán đối tượng không tạo bản sao.

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

Lớp (class) trong PHP được khai báo bằng class Name { ... } và chứa các thuộc tính (biến) cùng các phương thức (hàm). new Name() tạo ra một đối tượng (object) từ lớp đó, còn -> dùng để đọc thuộc tính hoặc gọi phương thức: $user->name, $user->greet().

Lớp là bản thiết kế, đối tượng là một thứ cụ thể được tạo ra từ bản thiết kế đó. Bạn có thể tạo bao nhiêu đối tượng từ một lớp tùy ý, và mỗi đối tượng có giá trị thuộc tính riêng.

Thuộc tính và phương thức

Thuộc tính được khai báo với một từ khóa phạm vi truy cập, một kiểu (không bắt buộc) và một giá trị mặc định (không bắt buộc). Phương thức là một hàm nằm trong lớp. Bên trong phương thức, $this là đối tượng mà phương thức đang được gọi trên đó, nên $this->balance đọc số dư của chính đối tượng ấy.

Mỗi đối tượng giữ $balance của riêng nó: nạp tiền vào $a không ảnh hưởng tới $b. Gán từng thuộc tính sau new thì khá mất công; hàm khởi tạo nhận các giá trị ban đầu làm đối số thay cho việc đó.

public, private và protected

Phạm vi truy cập quyết định ai được đụng tới một thuộc tính hoặc gọi một phương thức:

Từ khóaTruy cập được từ
publicmọi nơi
protectedchính lớp đó và các lớp kế thừa nó
privatechỉ lớp khai báo nó

Đặt thuộc tính là private và chỉ mở ra các phương thức là cách một lớp bảo vệ quy tắc của chính nó. Ở đây số dư chỉ thay đổi được qua deposit() và withdraw(), hai phương thức này từ chối số tiền không hợp lệ:

Đọc thuộc tính private từ bên ngoài lớp không chỉ là cảnh báo, mà là một Error:

Thuộc tính có kiểu và giá trị chưa khởi tạo

Một thuộc tính có kiểu mà không có giá trị mặc định sẽ bắt đầu ở trạng thái chưa khởi tạo, khác với null. Đọc nó trước khi gán gì sẽ ném ra Error. Hãy cho nó một giá trị mặc định, gán nó trong hàm khởi tạo, hoặc cho phép null bằng ?Type và = null.

Kiểu được kiểm tra khi gán. Ở chế độ mặc định (không strict), $p->stock = '7' chuyển chuỗi số thành 7, còn $p->stock = 'many' ném ra TypeError.

Thuộc tính readonly

Thuộc tính readonly (PHP 8.1) chỉ được ghi một lần, từ bên trong lớp, rồi không bao giờ ghi lại được nữa. Đây là cách thông dụng để tạo value object như số tiền hay ID. PHP 8.2 bổ sung readonly class, biến mọi thuộc tính của lớp thành readonly.

Thuộc tính readonly bắt buộc phải có kiểu và không được có giá trị mặc định. Nếu cần một bản sao đã thay đổi, hãy tạo đối tượng mới (new Order('B-2002')) thay vì sửa đối tượng cũ.

In đối tượng với __toString

echo $object chỉ dùng được khi lớp định nghĩa __toString(). Phương thức này trả về chuỗi mà PHP dùng mỗi khi đối tượng được xem như văn bản: trong echo, khi nối chuỗi, trong "{$object}".

Không có __toString, echo $object sẽ ném ra Error ("Object of class Money could not be converted to string"). Khi gỡ lỗi, print_r() và var_dump() dùng được với mọi đối tượng và hiện cả thuộc tính private; xem var_dump và print_r.

Gán đối tượng không tạo bản sao

Đây là lỗi hay gặp nhất với người quen làm việc với mảng. Gán một mảng sẽ sao chép mảng. Gán một đối tượng chỉ sao chép handle: hai biến lúc đó cùng trỏ tới một đối tượng.

clone tạo một bản sao nông: nếu một thuộc tính chứa đối tượng khác, cả hai bản sao vẫn dùng chung đối tượng bên trong đó. === chỉ đúng khi là cùng một đối tượng, còn == so sánh giá trị thuộc tính của hai đối tượng cùng lớp. Truyền một đối tượng vào hàm cũng hoạt động giống phép gán, nên hàm có thể thay đổi đối tượng mà nó nhận được.

Câu hỏi thường gặp

Làm sao tạo đối tượng từ một lớp trong PHP?

Dùng new với tên lớp: $user = new User();. Nếu lớp có hàm khởi tạo, truyền đối số của nó trong cặp ngoặc, như new User('Ada'). Sau đó bạn gọi phương thức và đọc thuộc tính bằng toán tử mũi tên: $user->name, $user->greet().

$this trong PHP nghĩa là gì?

$this là đối tượng mà phương thức hiện tại đang được gọi trên đó. Bên trong $ada->greet(), $this chính là $ada, nên $this->name đọc tên của Ada. Nó chỉ tồn tại bên trong các phương thức không static.

public, private và protected trong PHP khác nhau thế nào?

Thành phần public dùng được ở mọi nơi, thành phần private chỉ dùng được bên trong lớp khai báo nó, còn thành phần protected dùng được trong lớp đó và các lớp con. Đọc một thuộc tính private từ bên ngoài sẽ ném ra Error: Cannot access private property.

Đối tượng trong PHP có được truyền theo tham chiếu không?

Biến giữ một handle trỏ tới đối tượng, không phải bản thân đối tượng. $b = $a; sao chép handle, nên cả hai biến trỏ tới cùng một đối tượng và thay đổi qua $b cũng hiện ra ở $a. Dùng $b = clone $a; để có một bản sao độc lập.

Thuộc tính readonly trong PHP là gì?

Một thuộc tính khai báo public readonly string $id; (PHP 8.1 trở lên) chỉ được gán một lần, từ bên trong lớp, và không bao giờ thay đổi được nữa. Ghi vào nó lần thứ hai sẽ ném ra Error: Cannot modify readonly property.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu