Thuộc tính (property) trong class PHP

    0

    Thuộc tính (property) và phương thức (method) là hai thành phần cơ bản tạo nên một class trong PHP. Trong đó, thuộc tính là thành phần chứa dữ liệu trong class PHP.

    Bài học này sẽ xem xét chi tiết các vấn đề liên quan đến khai báo và sử dụng property trong PHP class.

    Khai báo property trong PHP class

    Property là thành phần chứa dữ liệu của object. Khi xây dựng class, property được thể hiện như khai báo biến thông thường trong PHP. Tuy nhiên việc khai báo property trong class có những điểm khác biệt so với khai báo biến toàn cục / biến cục bộ.

    Hãy xem ví dụ sau:

    class Employee
    {
       public $name = "John";
       private $title;
       private $wage;
    }

    Trong class Employee trên chúng ta khai báo ba property, $name (tên), $title, và $wage (lương).

    Sự khác biệt đầu tiên giữa property và biến ở chỗ, property bắt buộc phải khai báo với một trong các từ khóa điều khiển truy cập: public, private, protected. Các biến trong PHP không có đặc điểm này. Chúng ta sẽ nói kỹ hơn về các từ khóa điểu khiển truy cập ở phần sau của bài học.

    Sự khác biệt thứ hai là property có thể không cần gán giá trị lúc khai báo, còn khi khai báo biến trong PHP bạn phải gán giá trị. Trong ví dụ trên bạn thấy property $wage đang không được gán giá trị nào.

    Sở dĩ có đặc điểm này là property trong class PHP chỉ đóng vai trò là khuôn mẫu về dữ liệu. Chỉ khi nào tạo object, property mới thực sự chứa dữ liệu. Do vậy, lúc khai báo property trong class thì không cần gán dữ liệu.

    Tuy nhiên, khi không gán giá trị lúc khai báo tiềm ẩn những hậu quả khi sử dụng object. Vì vậy, khi khai báo property trong class, người ta khuyến khích gán luôn giá trị đầu. Khi này, khi tạo object mà không gán giá trị khác, property vẫn có giá trị ban đầu.

    Đây là tình huống với property $name. Khi khai báo class Employee, $name được gán sẵn giá trị "John". Khi tạo object, $name sẽ tự động có ngay giá trị "John".

    Mặc dù không bắt buộc, bạn nên khai báo property tập trung ở phần đầu của class. Không nên khai báo property phân tán nhiều nơi trong class. Việc này giúp bạn quả lý code tốt hơn, nhất là khi khối lượng code trong class tăng lên.

    Tương tự như với biến, khi đặt tên cho property bạn có thể sử dụng các kiểu như camelCase hoặc snake_case.

    camelCase: viết thường chữ cái đầu tiên; nếu tên gồm nhiều từ thì các từ viết sát nhau và viết hoa chữ cái đầu các từ tiếp theo.
    snake_case: toàn bộ viết thường; nếu tên gồm nhiều từ thì viết tách các từ bởi dấu gạch chân _.

    Truy xuất property

    Truy xuất property, hiểu một cách đơn giản, chính là sử dụng giá trị lưu trong property đó. Truy xuất property có hai chiều: đọc giá trị từ property, ghi giá trị mới vào property.

    Bạn chỉ có thể truy xuất property thông qua object chứ không thể truy xuất property qua class. Nghĩa là, trước khi sử dụng property, bạn cần khai báo và khởi tạo object của class.

    Hãy xem ví dụ sau:

    class Employee
    {
       public $name;
       public $title;
       public $wage;
    }
    
    $joe = new Employee();
    $joe->name = "Joe Biden";
    $joe->title = "Mr.";
    $joe->wage = 100000;
    echo "Hello, my name is $joe->title $joe->name";

    Trong ví dụ này chúng ta tạo class Employee với ba property $name, $title và $wage. Object $joe được tạo ra từ class Employee qua lệnh $joe = new Employee();.

    Sau đó chúng ta ghi giá trị cho từng property của $joe qua các lệnh:

    $joe->name = "Joe Biden";
    $joe->title = "Mr.";
    $joe->wage = 100000;

    Cuối cùng chúng ta sử dụng (đọc) các giá trị từ property $title và $name trong lệnh echo "Hello, my name is $joe->title $joe->name";.

    Bạn có thể thấy, để truy xuất property, chúng ta sử dụng phép toán -> trên object (không phải trên class). Cũng lưu ý rằng, tên property trong phép toán truy cập này không chứa dấu $ nữa.

    Đây là cách thức truy cập property từ ngoài class (client code).

    Truy xuất property trong code của class, $this

    Như trên đã nói, property phải truy xuất từ object. Nếu code truy xuất property nằm ngoài class, chúng ta tạo object và truy xuất qua tên object.

    Hãy hình dung một tình huống khác. Trong class Employee bạn muốn khai báo một phương thức print() giúp in thông tin về nhân sự. Rõ ràng trong code của print() khi khai báo class sẽ phải truy xuất tới property $name.

    Do bản chất property là biến, nghĩa là chính bên trong object đó cũng có thể sử dụng property. Việc sử dụng property này hoàn toàn trong nội bộ của chính object đó và nó phải thể hiện ngay khi khai báo class.

    Vậy làm thế nào để thể hiện việc truy xuất property bên trong chính object khi khai báo class?

    Hãy cùng xem ví dụ sau:

    class Employee
    {
        public $name;
        public $title;
        public $wage;
    
        public function print(){
            echo "Hello, my name is $this->title $this->name";
        }
    }
    
    $joe = new Employee();
    $joe->name = "Joe Biden";
    $joe->title = "Mr.";
    $joe->wage = 100000;
    
    $joe->print();

    Trong ví dụ trên chúng ta khai báo phương thức (hàm) print trong class giúp in ra thông tin nhân sự. Với hàm print có sẵn này, client code không cần tự viết lại lệnh in nữa. Mặc dù chưa học chi tiết về phương thức, hãy nhìn nhần phương thức trong class tương tự như hàm thông thường.

    Hàm này cần sử dụng thông tin lưu trong property $name và $title. Nhưng do chưa xác định được object, chúng ta không dùng được cách thức truy xuất property như thường lệ.

    PHP cung cấp một cách thức để báo rằng code của object sẽ truy xuất property chứa trong nó: biến $this.

    Biến $this được sử dụng trong phương thức như sau: echo "Hello, my name is $this->title $this->name";

    Bạn có thể hiểu như thế này: $this là một biến đặc biệt chỉ dùng ở giai đoạn khai báo class và sẽ được tự động thay thế bằng object cụ thể khi gọi phương thức.

    Như vậy, đơn giản nhất bạn chỉ cần nhớ: nếu cần truy xuất property từ bên trong class method, bạn sử dụng $this thay cho tên biến thông thường. Khi client code tạo object và gọi phương thức, $this sẽ được thay bằng object đó.

    Điều khiển truy cập property

    Như trên đã nói, khi khai báo property trong PHP bạn phải chỉ định phạm vi sử dụng của property bằng một trong các từ khóa: public, private, protected.

    Các từ khóa này giới hạn phạm vi sử dụng property như sau:

    Từ khóa private giới hạn phạm vi sử dụng của property chỉ trong thân của class, chính xác hơn là trong thân các phương thức của class đó. Code ở bên ngoài class (còn gọi là client code của class đó) không nhìn thấy property này, và do đó, không thể sử dụng nó. Code của class khác cũng không thể kế thừa private property.

    class Employee {
        // trong thân class
        private $name;   
    
        public function print(){
            // có thể dùng $name ở đây được
            echo "Hello, my name is $this->name";
        }
        
    }
    
    // sau đây là vùng client code của Employee
    $joe = new Employee();
    $joe->name = "Joe Biden"; // báo lỗi ở đây.

    Từ khóa public không giới hạn phạm vi sử dụng của property. Nghĩa là một public property có thể được truy xuất bởi bất kỳ code nào, dù là trong class hay ngoài class.

    Từ khóa protected cũng giới hạn phạm vi sử dụng của property trong thân của class (tương tự như private), nhưng cho phép class khác kế thừa property này. Bạn sẽ gặp lại vấn đề kế thừa trong một bài học riêng.

    Kinh nghiệm trong lập trình hướng đối tượng chỉ ra rằng không nên sử dụng public property. Lý do là vì khi đó object không thể kiểm soát giá trị nhập vào cho property.

    Câu hỏi đặt ra là, vậy làm thế nào để truy xuất property từ client code (ngoài class) mà không sử dụng public property? Trong khi protected và private property đều cấm truy xuất từ ngoài class.

    Để giải quyết vấn đề này, trong PHP thường sử dụng một kỹ thuật: tạo phương thức getter/setter cho mỗi property. Do getter/setter là các phương thức, chúng ta sẽ xem xét trong một bài học riêng.

    Chỉ định kiểu cho property

    Mặc định, khai báo property giống khai báo biến ở chỗ, bạn không cần chỉ định kiểu dữ liệu. Đồng thời, cùng một property trong một object cũng có thể nhận giá trị thuộc về các kiểu khác nhau.

    Điều này có liên quan tới đặc điểm định kiểu yếu và định kiểu động của PHP. Đặc điểm này giúp PHP đơn giản dễ học với người mới bắt đầu nhưng lại tạo ra nhiều vấn đề trong các dự án lớn.

    Trong các dự án enterprise lớn người ta thường ưu tiên sử dụng các ngôn ngữ định kiểu tính và định kiểu mạnh như Java hay C#.

    Bắt đầu từ PHP 7.4 bạn có thể sử dụng lối viết như sau khi khai báo property trong PHP:

    class Employee {
        private string $name;
        private string $title;
        private float $wage;    
    }

    Lối viết này tạo ra một loại property gọi là typed property (thuộc tính có định kiểu). Theo đó, trong class Employee ở trên, $name và $title thuộc kiểu string, còn $wage thuộc kiểu float.

    Lối viết này giúp chỉ rõ ràng ý định sử dụng của property. Tuy nhiên, nó không có tác dụng định kiểu như trong C# hay Java. Nghĩa là mặc dù khai báo $name với kiểu string, bạn vẫn có thể gán giá trị số cho $name, hoặc có thể gán giá trị chuỗi cho $wage. Đây là chế độ hoạt động mặc định của PHP (còn gọi là chế độ coercive).

    Để typed property thể hiện tác dụng định kiểu – nghĩa là bắt buộc dữ liệu gán cho property phải đúng kiểu đã chỉ định – chúng ta phải chuyển sang chế độ strict với lệnh sau ở đầu file script:

    declare(strict_types=1);

    Khi này, việc gán giá trị cho typed property trong file script đó phải theo đúng kiểu đã chỉ định khi khai báo property. Nếu không PHP sẽ báo lỗi và dừng thực thi.

    <?php
    declare(strict_types=1);
    
    class Employee {
        private string $name;
        private string $title;
        private float $wage;    
    }
    
    $joe = new Employee();
    $joe->name = 1234; // sẽ báo lỗi ở đây

    Nếu bạn xuất phát từ một ngôn ngữ định kiểu mạnh, bạn sẽ thấy rất quen thuộc khi sử dụng chế độ strict.

    + Nếu bạn thấy site hữu ích, trước khi rời đi hãy giúp đỡ site bằng một hành động nhỏ để site có thể phát triển và phục vụ bạn tốt hơn.
    + Nếu bạn thấy bài viết hữu ích, hãy giúp chia sẻ tới mọi người.
    + Nếu có thắc mắc hoặc cần trao đổi thêm, mời bạn viết trong phần thảo luận cuối trang.
    Cảm ơn bạn!

    Kết luận

    Trong bài học này chúng ta đã học chi tiết về property – thành phần chứa dữ liệu của class.

    1. Property có thể xem là các biến nhưng được khai báo hơi khác với biến toàn cục hoặc biến cục bộ thông thường.
    2. Mỗi property bị giới hạn truy cập bởi từ khóa điều khiển public / private / protected.
    3. Việc truy xuất property thực hiện qua object với phép toán ->.
    4. PHP 7.4 về sau hỗ trợ property có định kiểu và chế độ strict tương tự như ở các ngôn ngữ định kiểu mạnh.
    Subscribe
    Notify of
    guest
    0 Thảo luận
    Inline Feedbacks
    View all comments