Kế thừa trong PHP

Kế thừa là gì?

Kế thừa (inheritance) là khả năng tạo một lớp mới dựa trên một lớp có sẵn. Lớp có sẵn là lớp cha, lớp mới là lớp con và lớp con thừa kế các thành phần được định nghĩa ở lớp cha.

Lớp con sẽ kế thừa tất cả các thuộc tính và phương thức có chỉ thị truy cập là public và protected từ lớp cha. Ngoài ra, nó có thể có các thuộc tính và phương thức của riêng nó.

Một lớp kế thừa được định nghĩa bằng cách sử dụng từ khóa extends.

Ví dụ sau minh họa kế thừa trong PHP:

<?php
    class Fruit {
        public $name;
        public $color;
        
        public function __construct($name, $color) {
            $this->name = $name;
            $this->color = $color;
        }
        
        public function intro() {
            echo "The fruit is {$this->name} and the color is {$this->color}.";
        }
    }

    // Strawberry is inherited from Fruit
    class Strawberry extends Fruit {
        public function message() {
            echo "Am I a fruit or a berry? ";
        }
    }
    $strawberry = new Strawberry("Strawberry", "red");
    $strawberry->message();
    $strawberry->intro();
?>

Đây là kết quả:

Am I a fruit or a berry? The fruit is Strawberry and the color is red.

Như bạn đã thấy ở ví dụ trên, lớp Strawberry được kế thừa từ lớp Fruit.

Điều này có nghĩa là lớp Strawberry có thể sử dụng các thuộc tính public là $name$color  cũng như các phương thức public __construct() và intro() từ lớp Fruit vì tính kế thừa.

Lớp Strawberry cũng có phương thức riêng của nó là message().

Từ khóa protected trong PHP

Trong phần trước, chúng ta đã tìm hiểu các thuộc tính hoặc phương thức có chỉ thị truy cập protected có thể được truy cập trong lớp và các lớp có nguồn gốc từ lớp đó. Điều đó nghĩa là gì?

Hãy xem ví dụ sau:

<?php
    class Fruit {
        public $name;
        public $color;
        
        public function __construct($name, $color) {
            $this->name = $name;
            $this->color = $color;
        }
        
        protected function intro() {
            echo "The fruit is {$this->name} and the color is {$this->color}.";
        }
    }

    class Strawberry extends Fruit {
        public function message() {
            echo "Am I a fruit or a berry?";
        }
    }

    // Try to call all three methods from outside class
    $strawberry = new Strawberry("Strawberry", "red");  // OK. __construct() is public
    $strawberry->message(); // OK. message() is public
    echo "<br />";
    $strawberry->intro(); // ERROR. intro() is protected
?>

Đây là kết quả:

Am I a fruit or a berry?
Fatal error: Uncaught Error: Call to protected method Fruit::intro() from context ...

Trong ví dụ trên, chúng ta thấy rằng nếu chúng ta cố gắng gọi một phương thức protected (phương thức intro()) từ bên ngoài lớp, chúng ta sẽ nhận được một lỗi. Trong khi đó phương thức public (phương thức message()) sẽ hoạt động tốt!

Hãy xem một ví dụ khác:

<?php
    class Fruit {
        public $name;
        public $color;
        
        public function __construct($name, $color) {
            $this->name = $name;
            $this->color = $color;
        }
        
        protected function intro() {
            echo "The fruit is {$this->name} and the color is {$this->color}.";
        }
    }

    class Strawberry extends Fruit {
        public function message() {
            echo "Am I a fruit or a berry?";
            echo "<br />";
            // Call protected method from within derived class - OK
            $this -> intro();
        }
    }

    $strawberry = new Strawberry("Strawberry", "red"); // OK. __construct() is public
    $strawberry->message(); // OK. message() is public and it calls intro() (which is protected) from within the derived class
?>

Đây là kết quả:

Am I a fruit or a berry?
The fruit is Strawberry and the color is red.

Trong ví dụ trên chúng ta thấy rằng tất cả đều hoạt động tốt! Đó là bởi vì chúng ta gọi phương thức protected (phương thức intro()) từ bên trong lớp con.

Ghi đè phương thức trong PHP

Các phương thức được kế thừa có thể được ghi đè bằng cách định nghĩa lại các phương thức (sử dụng cùng tên phương thức) trong lớp con.

Hãy xem ví dụ dưới đây. Các phương thức __construct() và intro() trong lớp con (lớp Strawberry) sẽ ghi đè các phương thức __construct() và intro() trong lớp cha (lớp Fruit):

<?php
    class Fruit {
        public $name;
        public $color;
        
        public function __construct($name, $color) {
            $this->name = $name;
            $this->color = $color;
        }
        
        public function intro() {
            echo "The fruit is {$this->name} and the color is {$this->color}.";
        }
    }

    class Strawberry extends Fruit {
        public $weight;
        
        public function __construct($name, $color, $weight) {
            $this->name = $name;
            $this->color = $color;
            $this->weight = $weight;
        }
        
        public function intro() {
            echo "The fruit is {$this->name}.";
            echo "<br />";
            echo "The color is {$this->color}.";
            echo "<br />";
            echo "The weight is {$this->weight} gram.";
        }
    }

    $strawberry = new Strawberry("Strawberry", "red", 50);
    $strawberry->intro();
?>

Đây là kết quả:

The fruit is Strawberry.
The color is red.
The weight is 50 gram.

Từ khóa final trong PHP

Từ khóafinal được sử dụng để ngăn chặn lớp thừa kế hoặc để ngăn chặn ghi đè phương thức.

Ví dụ sau đây cho thấy cách ngăn chặn kế thừa lớp:

<?php
    final class Fruit {
        // some code
    }

    // will result in error
    class Strawberry extends Fruit {
        // some code
    }
?>

Trong ví dụ trên, có từ khóa final trong khai báo lớp Fruit nên lớp Strawberry không thể kế thừa lớp Fruit được.

Ví dụ sau đây cho thấy cách ngăn chặn ghi đè phương thức:

<?php
    class Fruit {
        final public function intro() {
            // some code
        }
    }

    class Strawberry extends Fruit {
        // will result in error
        public function intro() {
            // some code
        }
    }
?>

Trong ví dụ trên, phương thức intro của lớp Fruit có sử dụng từ khóa final nên lớp Strawberry kế thừa từ lớp Fruit không thể ghi đè phương thức intro được.



Bài viết liên quan:

Hướng dẫn lập trình PHP toàn tập sẽ giúp bạn từng bước tìm hiểu và nắm vững ngôn ngữ lập trình PHP.

Hướng dẫn cách truy xuất, lọc, sắp xếp dữ liệu MySQL trong PHP sử dụng MySQLi và PDO.

MySQL prepared statements trong PHP rất hữu ích để chống lại các cuộc tấn công SQL Injection.