Bài 31: Tìm hiểu Class và Object trong PHP

“Hãy hòa nhã với những kẻ dở hơi. Ai biết được ngày sau bạn có thể phải làm việc cho một kẻ như vậy.”

Bill Gates

Microsoft

Trong bài hướng dẫn này, bạn sẽ được học cách lập trình theo kiểu hướng đối tượng (OOP) trong PHP. Tìm hiểu về cách khai báo Class, Object và truy cập thuộc tính, phương thức của chúng…

Tìm hiểu về Class và Object trong PHP
Tìm hiểu về Class và Object trong PHP

Lập trình hướng đối tượng là gì

Lập trình hướng đối tượng (OOP) là một mô hình lập trình dựa trên khái niệm về các lớp và các đối tượng.

Trái ngược với lập trình thủ tục trong đó trọng tâm là viết các thủ tục hoặc hàm thực hiện các thao tác trên dữ liệu. Trong lập trình hướng đối tượng, trọng tâm là tạo các đối tượng chứa cả dữ liệu và hàm cùng nhau.

Lập trình hướng đối tượng có một số lợi thế so với phong cách lập trình thông thường hoặc theo thủ tục. Những cái quan trọng nhất được liệt kê dưới đây:

  • Hướng đối tượng cung cấp một cấu trúc mô-đun rõ ràng cho chương trình
  • Nó giúp bạn tuân thủ nguyên tắc ‘không lặp lại chính mình’ (DRY) và do đó làm cho mã của bạn dễ dàng hơn nhiều để duy trì, sửa đổi và gỡ lỗi
  • Nó có thể tạo ra hành vi phức tạp hơn với ít mã hơn và thời gian phát triển ngắn hơn và mức độ tái sử dụng cao

Các phần sau đây sẽ mô tả cách các lớp và các đối tượng hoạt động trong PHP.

Mẹo nhanh: Ý tưởng đằng sau nguyên tắc Đừng lặp lại chính mình (DRY) là giảm việc lặp lại code bằng cách trừu tượng hóa các đoạn code tương tự, phổ biến cho ứng dụng và đặt chúng tại một nơi duy nhất và sử dụng lại chúng thay vì viết đi viết lại nhiều lần.

Hiểu về Lớp và Đối tượng trong PHP

Các Lớp (Class) và các Đối tượng (Object) là hai khía cạnh chính của Lập trình hướng đối tượng.

Một lớp là một container tập hợp các biến và hàm độc lập, hoạt động cùng nhau để thực hiện một hoặc nhiều tác vụ cụ thể, trong khi các đối tượng là các thể hiện riêng lẻ của một lớp.

Một lớp hoạt động như một khuôn mẫu hoặc bản thiết kế mà từ đó có thể tạo ra rất nhiều đối tượng riêng lẻ.

Khi các đối tượng riêng lẻ được tạo, chúng kế thừa các thuộc tínhhành vi chung giống nhau, mặc dù mỗi đối tượng có thể có các giá trị khác nhau cho các thuộc tính nhất định.

Ví dụ, hãy nghĩ về một lớp học như một bản thiết kế cho một ngôi nhà. Bản thân bản thiết kế chi tiết không phải là một ngôi nhà, mà là một kế hoạch chi tiết để xây dựng ngôi nhà.

Chúng ta có thể xây dựng một số ngôi nhà giống hệt nhau từ cùng một bản thiết kế, nhưng mỗi ngôi nhà có thể có màu sơn khác nhau, nội thất và gia đình khác nhau bên trong, như trong hình minh họa dưới đây.

Minh họa Class và Object
Minh họa Class và Object

Một lớp có thể được khai báo bằng từ khóa class, theo sau là tên của lớp và một cặp dấu ngoặc nhọn ({}), như trong ví dụ sau.

Chúng ta hãy tạo một tệp PHP có tên là Rectangle.php và đặt code ví dụ sau vào bên trong. Chúng ta tách chúng khỏi phần còn lại của chương trình. Sau đó, chúng ta có thể sử dụng nó bất cứ nơi nào cần thiết bằng cách bao include tệp Rectangle.php

<?php
class Rectangle
{
    // Khai báo thuộc tính
    public $length = 0;
    public $width = 0;
    
    // Phương thức tính chu vi
    public function getPerimeter(){
        return (2 * ($this->length + $this->width));
    }
    
    // Phương thức tính diện tích
    public function getArea(){
        return ($this->length * $this->width);
    }
}
?>

Từ khóa public trước các thuộc tính và phương thức trong ví dụ trên, là một cách để điều chỉnh cấp độ truy cập, nó cho biết thuộc tính hoặc phương thức này có thể truy cập được từ mọi nơi.

Chúng ta sẽ tìm hiểu thêm về các cấp độ truy cập trong các bài học sau này.

Lưu ý: Về mặt cú pháp, các biến trong một lớp được gọi là các thuộc tính, trong khi các hàm được gọi là các phương thức. Ngoài ra, các tên lớp theo quy ước được viết bằng PascalCase, tức là mỗi từ được ghép bắt đầu bằng một chữ cái viết hoa (ví dụ: MyClass).

Khi một lớp đã được xác định, các đối tượng có thể được tạo từ lớp với từ khóa new. Các phương thức và thuộc tính lớp có thể được truy cập trực tiếp thông qua thể hiện đối tượng này.

Tạo một tệp PHP tên là test.php khác và đặt đoạn mã sau vào bên trong nó.

<?php
// Include Lớp Rectangle
require "Rectangle.php";
 
// Tạo một đối tượng mới từ class Rectangle
$obj = new Rectangle;
 
// Lấy các giá trị thuộc tính của đối tượng
echo $obj->length; // 0utput: 0
echo $obj->width; // 0utput: 0
 
// Thiết lập giá trị thuộc tính
$obj->length = 30;
$obj->width = 20;
 
/* Đọc các giá trị thuộc tính đối tượng một lần nữa để hiển thị sự thay đổi*/
echo $obj->length; // 0utput: 30
echo $obj->width; // 0utput: 20
 
 
// Gọi phương thức của đối tượng
echo $obj->getPerimeter(); // 0utput: 100
echo $obj->getArea(); // Output: 600
?>

Ký hiệu mũi tên (->) là cấu trúc OOP được sử dụng để truy cập các thuộc tính và phương thức chứa của một đối tượng nhất định. Trong khi đó, biến giả $this cung cấp một tham chiếu đến đối tượng gọi tức là đối tượng mà phương thức thuộc về.

Sức mạnh thực sự của lập trình hướng đối tượng trở nên rõ ràng khi sử dụng nhiều phiên bản của cùng một lớp, như trong ví dụ sau:

<?php
// Include lớp Rectangle
require "Rectangle.php";
 
// Tạo nhiều đối tượng mới từ Lớp Rectangle
$obj1 = new Rectangle;
$obj2 = new Rectangle;
 
// Tính diện tích của cả 2 đối tượng
echo $obj1->getArea(); // Output: 0
echo $obj2->getArea(); // Output: 0
 
// Thiết lập thuộc tính cho đối tượng $obj1
$obj1->length = 30;
$obj1->width = 20;
 
// Thiết lập thuộc tính cho đối tượng $obj2
$obj2->length = 35;
$obj2->width = 50;
 
// Gọi phương thức tính diện tích của cả 2 đối tượng 1 lần nữa
echo $obj1->getArea(); // Output: 600
echo $obj2->getArea(); // Output: 1750
?>

Như bạn có thể thấy trong ví dụ trên, việc gọi phương thức getArea() trên các đối tượng khác nhau khiến phương thức đó hoạt động trên một tập hợp dữ liệu khác nhau.

Mỗi đối tượng là hoàn toàn độc lập, với các thuộc tính và phương thức riêng của nó và do đó có thể được thao tác độc lập, ngay cả khi chúng cùng loại.

Sử dụng Constructors và Destructors

Để làm cho việc lập trình hướng đối tượng trở nên dễ dàng hơn, PHP cung cấp một số phương thức được thực thi tự động khi một số hành động nhất định xảy ra trong một đối tượng.

Ví dụ, phương thức __construct() (được gọi là hàm tạo / hàm khởi tạo) được thực thi tự động bất cứ khi nào một đối tượng mới được tạo.

Tương tự, phương thức __destruct() (được gọi là hàm hủy) được thực thi tự động khi đối tượng bị hủy. Hàm hủy diệt sẽ dọn sạch mọi tài nguyên được phân bổ cho một đối tượng sau khi đối tượng bị hủy.

<?php
class MyClass
{
    // Constructor
    public function __construct(){
        echo 'Lớp "' . __CLASS__ . '" đã được khởi tạo!<br>';
    }
    
    // Destructor
    public function __destruct(){
        echo 'Lớp "' . __CLASS__ . '" đã được phá hủy.<br>';
    }
}
 
// Tạo một đối tượng mới
$obj = new MyClass;
 
// Xuất một in nhắn ở cuối file
echo "Kết thúc tập tin.";
?>

Chạy đoạn code PHP trên chúng ta sẽ nhận được kết quả sau:

Lớp MyClass đã được khởi tạo!
Kết thúc tập tin.
Lớp MyClass đã được phá hủy.

Hàm hủy được gọi tự động khi tập lệnh kết thúc. Tuy nhiên, để kích hoạt rõ ràng hàm hủy, bạn có thể hủy đối tượng bằng hàm unset() của PHP, như sau:

<?php
class MyClass
{
    // Constructor
    public function __construct(){
        echo 'Lớp "' . __CLASS__ . '" đã được khởi tạo!<br>';
    }
    
    // Destructor
    public function __destruct(){
        echo 'Lớp "' . __CLASS__ . '" đã được phá hủy.<br>';
    }
}
 
// Tạo một đối tượng mới
$obj = new MyClass;

// Phá hủy đối tượng
unset($obj);
 
// Xuất một in nhắn ở cuối file
echo "Kết thúc tập tin.";
?>

Bây giờ, chạy tập tin trên và nhận được kết quả:

Lớp MyClass đã được khởi tạo!
Lớp MyClass đã được phá hủy.
Kết thúc tập tin.

Mẹo nhanh: PHP tự động dọn sạch tất cả các tài nguyên được phân bổ trong khi thực thi khi tập lệnh kết thúc, ví dụ: Đóng kết nối cơ sở dữ liệu, phá hủy các đối tượng, vv

Lưu ý: __CLASS__ là hằng số chứa tên của lớp mà nó xảy ra. Nó trống rỗng, nếu nó xảy ra bên ngoài lớp học.

Mở rộng (Extend) Lớp thông qua Kế thừa (Inheritance)

Các lớp có thể kế thừa các thuộc tínhphương thức của một lớp khác bằng cách sử dụng từ khóa extends. Quá trình mở rộng này được gọi là thừa kế.

Đây có lẽ là lý do việc sử dụng mô hình lập trình hướng đối tượng phổ biến như thế.

<?php
// Include lớp Rectangle
require "Rectangle.php";
 
// Xác định một lớp mới dựa trên một lớp hiện có
class Square extends Rectangle
{   
    /* Phương pháp kiểm tra xem hình chữ nhật có phải là hình vuông không */
    public function isSquare(){
        if($this->length == $this->width){
            return true; // Hình Vuông
        } else{
            return false; // Hình Chữ Nhật
        }
    }
}
 
// Tạo một đối tượng mới từ Lớp Square
$obj = new Square;
 
// Thiết lập giá trị thuộc tính đối tượng
$obj->length = 20;
$obj->width = 20;
 
// Gọi phương thức
if($obj->isSquare()){
    echo "Diện tích hình Vuông là ";
} else{
    echo "Diện tích hình Chữ Nhật là ";
};
echo $obj->getArea();
?>

Đoạn mã PHP trong ví dụ trên sẽ cho ra kết quả như sau:

Diện tích hình Vuông là 400

Như bạn có thể thấy trong ví dụ trên, mặc dù định nghĩa lớp của Square không rõ ràng chứa phương thức getArea() cũng như thuộc tính $length và $width, các thể hiện của lớp Square vẫn có thể sử dụng chúng, vì chúng được kế thừa từ Lớp cha của nó là Rectangle.

Mẹo nhanh: Vì một lớp con có nguồn gốc từ một lớp cha, nên nó cũng được gọi là lớp dẫn xuất và lớp cha của nó được gọi là lớp cơ sở.

Kiểm soát mức độ hiển thị của các thuộc tính và phương thức

Khi làm việc với các lớp, bạn có thể hạn chế quyền truy cập vào các thuộc tính và phương thức của nó bằng cách sử dụng các từ khóa hiển thị để kiểm soát tốt hơn.

Có ba từ khóa hiển thị (từ dễ thấy nhất đến ít nhìn thấy nhất): public, protected, private.

Từ đó các thuộc tính và phương thức có thể được kiểm soát mức độ truy cập và sửa đổi.

  • public: Một thuộc tính hoặc phương thức công khai có thể được truy cập ở bất cứ đâu, từ trong lớp đến bên ngoài lớp. Đây là khả năng hiển thị mặc định cho tất cả các thành viên lớp trong PHP.
  • protected: Một thuộc tính hoặc phương thức được bảo vệ chỉ có thể được truy cập từ bên trong chính lớp đó hoặc trong các lớp con hoặc các lớp được kế thừa, tức là các lớp mở rộng lớp đó.
  • private: Một thuộc tính hoặc phương thức riêng tư chỉ có thể truy cập được từ bên trong lớp định nghĩa nó. Ngay cả các lớp con hoặc lớp thừa kế cũng không thể truy cập các thuộc tính hoặc phương thức private.

Ví dụ sau đây sẽ cho bạn thấy khả năng hiển thị / mức độ truy cập này thực sự hoạt động như thế nào.

<?php
// Định nghĩa class
class Automobile
{
    // Khai báo thuộc tính
    public $fuel;
    protected $engine;
    private $transmission;
}
class Car extends Automobile
{
    // Constructor
    public function __construct(){
        echo 'Lớp "' . __CLASS__ . '" đã được khởi tạo!<br>';
    }
}
 
// Tạo một đối tượng từ lớp Automobile
$automobile = new Automobile;
 
// Thiết lập thuộc tính cho đối tượng $automobile
$automobile->fuel = 'Petrol'; // ok
$automobile->engine = '1500 cc'; // fatal error
$automobile->transmission = 'Manual'; // fatal error
 
// Tạo một đối tượng từ Lớp Car
$car = new Car;
 
// Thiết lập thuộc tính cho đối tượng $car
$car->fuel = 'Diesel'; // ok
$car->engine = '2200 cc'; // fatal error
$car->transmission = 'Automatic'; // undefined
?>

Phương thức static và thuộc tính stactic

Ngoài khả năng hiển thị trên, các thuộc tính và phương thức cũng có thể được khai báo là static, điều này làm cho chúng có thể truy cập được mà không cần phải khởi tạo lớp.

Các thuộc tính và phương thức tĩnh có thể được truy cập bằng toán tử phân giải phạm vi (: :), như thế này: ClassName::$property và ClassName::method().

Một thuộc tính được khai báo là static không thể được truy cập thông qua đối tượng của lớp đó mặc dù có thể là một phương thức tĩnh, như được minh họa trong ví dụ sau:

<?php
// Định nghĩa Lớp
class HelloClass
{
    // Khai báo thuộc tính static
    public static $greeting = "Hello World!";
    
    // Khai báo phương thức static
    public static function sayHello(){
        echo self::$greeting;
    }
}
// Cố gắng truy cập vào thuộc tính và phương thức static
echo HelloClass::$greeting; // Output: Hello World!
HelloClass::sayHello(); // Output: Hello World!
 
// Cố gắng truy cập thuộc tính và phương thức tĩnh thông qua đối tượng
$hello = new HelloClass;
echo $hello->greeting; // Strict Warning
$hello->sayHello(); // Output: Hello World!
?>

Từ khóa self trong ví dụ trên có nghĩa là ‘lớp hiện tại’. Nó không bao giờ đi trước ký hiệu đô la ($) và luôn được theo sau bởi toán tử :: (ví dụ: self::$name).

Từ khóa self khác với từ khóa this có nghĩa là ‘đối tượng hiện tại’ hoặc ‘thể hiện hiện tại của một lớp’. Từ khóa this luôn đi trước ký hiệu đô la ($) và theo sau là toán tử -> (ví dụ: $this -> name).

Lưu ý: Vì các phương thức static có thể được gọi mà không có phiên bản của một lớp (tức là đối tượng), biến giả $this không có sẵn bên trong phương thức được khai báo là static.

Lời kết

Chúng tôi hy vọng bạn đã hiểu các khái niệm cơ bản về lập trình hướng đối tượng. Bạn sẽ tìm thấy nhiều ví dụ về OOP trong phần cơ sở dữ liệu PHP và MySQL.

Có thể bạn muốn xem

CSS Box Model

Trong hướng dẫn tự học CSS này, bạn sẽ tìm hiểu về CSS Box Model. Hiểu làm thế nào các phần tử có thể trình bày trực quan trên trang web.

Cách CSS Bảng (Table)

Trong bài hướng dẫn tự học CSS này, bạn sẽ tìm hiểu toàn tập cách CSS bảng đẹp, CSS table một cách dễ hiểu nhất.

Leave a reply

Please enter your comment!
Please enter your name here