Trong lập trình hướng đối tượng (OOP) của PHP, class trừu tượng (abstract class) là một khái niệm quan trọng giúp định nghĩa các cấu trúc cho các class con, nhưng không thể tạo ra đối tượng từ chính nó. Class trừu tượng cho phép bạn xây dựng các mô hình chung cho các class khác, đồng thời buộc các class con phải triển khai một số phương thức cụ thể.

Trong bài viết này, chúng ta sẽ tìm hiểu về cách hoạt động của abstract classes trong PHP, cách khai báo và sử dụng chúng, cũng như các tình huống nên sử dụng class trừu tượng.

1. Class trừu tượng là gì?

Class trừu tượng là một class không thể khởi tạo đối tượng từ chính nó, mà chỉ có thể được sử dụng như một class cơ sở cho các class khác kế thừa. Class trừu tượng có thể chứa các phương thức trừu tượng (phương thức không có phần thân, chỉ định nghĩa) và các phương thức thông thường (phương thức có phần thân). Class con kế thừa class trừu tượng bắt buộc phải triển khai tất cả các phương thức trừu tượng của class cha.

Một class trừu tượng thường được sử dụng khi bạn muốn định nghĩa các hành vi chung cho nhiều class, nhưng mỗi class có thể thực hiện hành vi đó theo các cách khác nhau.

2. Cú pháp khai báo class trừu tượng

php
abstract class ClassName {
    // Phương thức trừu tượng
    abstract protected function methodName();
    
    // Phương thức thông thường
    public function normalMethod() {
        // Nội dung phương thức
    }
}
  • abstract: Từ khóa để khai báo class hoặc phương thức trừu tượng.
  • Phương thức trừu tượng: Là phương thức chỉ có khai báo, không có phần thân (nội dung phương thức), và phải được triển khai (implement) trong các class con.
  • Phương thức thông thường: Là phương thức có phần thân và có thể được kế thừa hoặc ghi đè bởi các class con.

3. Ví dụ về class trừu tượng

Hãy xem một ví dụ đơn giản về cách sử dụng class trừu tượng trong PHP:

php
abstract class Animal {
    // Phương thức trừu tượng, không có phần thân
    abstract public function makeSound();

    // Phương thức thông thường
    public function sleep() {
        echo "The animal is sleeping\n";
    }
}

class Dog extends Animal {
    // Triển khai phương thức trừu tượng
    public function makeSound() {
        echo "Bark!\n";
    }
}

class Cat extends Animal {
    // Triển khai phương thức trừu tượng
    public function makeSound() {
        echo "Meow!\n";
    }
}

// Tạo đối tượng từ class con
$dog = new Dog();
$dog->makeSound();  // Output: Bark!
$dog->sleep();      // Output: The animal is sleeping

$cat = new Cat();
$cat->makeSound();  // Output: Meow!
$cat->sleep();      // Output: The animal is sleeping

Giải thích:

  • Class Animal là một class trừu tượng với phương thức trừu tượng makeSound(). Phương thức này không có phần thân và yêu cầu các class con phải triển khai nó.
  • Class DogCat kế thừa từ class Animal và bắt buộc phải triển khai phương thức makeSound().
  • Phương thức sleep() là một phương thức thông thường trong class Animal và có thể được sử dụng trực tiếp bởi các class con mà không cần triển khai lại.

4. Phương thức trừu tượng

Phương thức trừu tượng là phương thức không có phần thân và chỉ định nghĩa trong class trừu tượng. Khi class con kế thừa từ class trừu tượng, class con phải cung cấp phần thân cho tất cả các phương thức trừu tượng được định nghĩa trong class cha.

4.1. Cú pháp khai báo phương thức trừu tượng

php
abstract protected function methodName($param1, $param2);
  • Một phương thức trừu tượng chỉ được định nghĩa với phần khai báo và không có phần thân.
  • Phương thức trừu tượng có thể sử dụng các từ khóa truy cập như protected, public, hoặc private.
  • Các class con bắt buộc phải triển khai phương thức trừu tượng với đầy đủ các tham số giống như trong class trừu tượng.

4.2. Ví dụ về phương thức trừu tượng:

php
abstract class Shape {
    // Phương thức trừu tượng
    abstract protected function calculateArea();
}

class Circle extends Shape {
    private $radius;

    public function __construct($radius) {
        $this->radius = $radius;
    }

    // Triển khai phương thức trừu tượng
    public function calculateArea() {
        return pi() * $this->radius * $this->radius;
    }
}

$circle = new Circle(5);
echo $circle->calculateArea();  // Output: 78.539816339745

Giải thích:

  • Class Shape là một class trừu tượng với phương thức trừu tượng calculateArea().
  • Class Circle kế thừa class Shape và phải triển khai phương thức calculateArea() để tính diện tích hình tròn.

5. Class trừu tượng và Kế thừa

Khi một class kế thừa từ một class trừu tượng, nó phải triển khai tất cả các phương thức trừu tượng trong class cha. Nếu class con không triển khai tất cả các phương thức trừu tượng, thì bản thân nó cũng phải được khai báo là một class trừu tượng.

Ví dụ về kế thừa với class trừu tượng:

php
abstract class Vehicle {
    abstract protected function startEngine();
}

class Car extends Vehicle {
    public function startEngine() {
        echo "Car engine started!\n";
    }
}

class ElectricCar extends Vehicle {
    public function startEngine() {
        echo "Electric car engine started silently!\n";
    }
}

$car = new Car();
$car->startEngine(); // Output: Car engine started!

$electricCar = new ElectricCar();
$electricCar->startEngine(); // Output: Electric car engine started silently!

Giải thích:

  • Class Vehicle là class trừu tượng với phương thức startEngine() chưa được triển khai.
  • Class CarElectricCar kế thừa từ class Vehicle và bắt buộc phải triển khai phương thức startEngine() theo cách riêng của chúng.

6. Khi nào nên sử dụng class trừu tượng?

Class trừu tượng được sử dụng khi:

  • Bạn có một nhóm class có các đặc điểm và hành vi chung, nhưng bạn muốn mỗi class con triển khai những hành vi đó theo cách riêng.
  • Bạn muốn định nghĩa một giao diện chung cho các class con, đồng thời buộc các class này phải triển khai các phương thức cụ thể.
  • Bạn muốn tạo ra một khuôn mẫu chung mà không tạo được đối tượng từ class trừu tượng.

So sánh Abstract Class và Interface

Class trừu tượng (Abstract Class)Interface
Có thể có các phương thức trừu tượng và phương thức thông thường.Chỉ có các phương thức trừu tượng.
Class con chỉ kế thừa từ một class trừu tượng.CLass có thể triển khai nhiều interface cùng lúc.
Có thể có thuộc tính.Không thể có thuộc tính.
Thích hợp cho quan hệ "is a".Thích hợp cho quan hệ "can do" hoặc để định nghĩa hành vi.

7. Lưu ý khi sử dụng class trừu tượng

  • Không thể khởi tạo: Bạn không thể tạo đối tượng trực tiếp từ class trừu tượng. Class trừu tượng chỉ đóng vai trò làm class cơ sở cho các class con kế thừa.
php
abstract class Example {
    abstract protected function test();
}

// $example = new Example(); // Lỗi: Không thể khởi tạo class trừu tượng
  • Triển khai tất cả các phương thức trừu tượng: Khi một class kế thừa class trừu tượng, class đó bắt buộc phải triển khai tất cả các phương thức trừu tượng của class cha, nếu không nó cũng phải được khai báo là class trừu tượng.
  • Class trừu tượng không bắt buộc phải có phương thức trừu tượng: Một class trừu tượng có thể chỉ chứa các phương thức thông thường. Tuy nhiên, nếu bạn muốn đảm bảo rằng class không thể khởi tạo trực tiếp, bạn có thể khai báo nó là abstract.

Kết luận

Class trừu tượng là một tính năng mạnh mẽ trong lập trình hướng đối tượng PHP. Chúng giúp bạn định nghĩa các phương thức cơ bản và đảm bảo rằng các class con phải triển khai những phương thức đó theo cách riêng của mình. Điều này giúp xây dựng mã dễ bảo trì, nhất quán và tái sử dụng hiệu quả.

Trong bài học tiếp theo, chúng ta sẽ khám phá interface trong PHP, một công cụ khác để xây dựng các cấu trúc linh hoạt và mạnh mẽ trong OOP.