VANHIEP.NET - Làm web giá rẻ - Thiết Kế Website - Thiết Kế Ứng Dụng Mobile

Public, Protected, Private trong PHP: Hướng Dẫn Chi Tiết Kiểm Soát Quyền Truy Cập

Bạn muốn hiểu rõ cách kiểm soát quyền truy cập trong lập trình PHP hướng đối tượng? Khám phá Public, Protected, Private là gì, sự khác biệt giữa chúng và cách áp dụng hiệu quả vào thuộc tính và phương thức. Bài viết này sẽ hướng dẫn bạn chi tiết với các ví dụ cụ thể để xây dựng mã nguồn an toàn và dễ bảo trì hơn.

Trong lập trình hướng đối tượng (OOP) với PHP, việc kiểm soát quyền truy cập vào các thuộc tính (properties) và phương thức (methods) của một lớp (class) là vô cùng quan trọng. PHP cung cấp ba từ khóa quyền truy cập chính: public, protected, và private. Hiểu rõ và sử dụng đúng các từ khóa này giúp chúng ta xây dựng mã nguồn an toàn hơn, dễ bảo trì hơn và tuân thủ các nguyên tắc thiết kế tốt.

Bài viết này sẽ đi sâu vào từng loại quyền truy cập, cùng với các ví dụ minh họa để bạn có thể nắm vững cách sử dụng chúng.


1. Public (Công khai)

Khi một thuộc tính hoặc phương thức được khai báo là public, điều đó có nghĩa là nó có thể được truy cập từ bất cứ đâu:

  • Bên trong lớp mà nó được định nghĩa.
  • Bên trong các lớp kế thừa (subclasses).
  • Bên ngoài lớp thông qua một đối tượng của lớp đó.

Đây là quyền truy cập mặc định nếu bạn không chỉ định bất kỳ từ khóa quyền truy cập nào (mặc dù tốt nhất là nên chỉ định rõ ràng để mã nguồn dễ đọc hơn).

Ví dụ về public:

<?php

class Car {
    public $brand;
    public $model;

    public function __construct($brand, $model) {
        $this->brand = $brand;
        $this->model = $model;
    }

    public function getCarInfo() {
        return "Brand: " . $this->brand . ", Model: " . $this->model;
    }
}

$myCar = new Car("Toyota", "Camry");

// Truy cập thuộc tính public từ bên ngoài
echo $myCar->brand; // Output: Toyota
echo "<br>";

// Gọi phương thức public từ bên ngoài
echo $myCar->getCarInfo(); // Output: Brand: Toyota, Model: Camry
echo "<br>";

// Thay đổi thuộc tính public từ bên ngoài
$myCar->brand = "Honda";
echo $myCar->getCarInfo(); // Output: Brand: Honda, Model: Camry

?>

Khi nào sử dụng public?

  • Khi bạn muốn các thành viên của lớp có thể truy cập được từ mọi nơi.
  • Khi bạn muốn cung cấp giao diện công khai cho lớp của mình.
  • Đối với các phương thức getter/setter đơn giản (mặc dù có thể sử dụng protected hoặc private cho dữ liệu thực và cung cấp getter/setter public).

2. Protected (Được bảo vệ)

Khi một thuộc tính hoặc phương thức được khai báo là protected, nó chỉ có thể được truy cập:

  • Bên trong lớp mà nó được định nghĩa.
  • Bên trong các lớp kế thừa (subclasses).

không thể được truy cập từ bên ngoài lớp thông qua một đối tượng của lớp đó.

Ví dụ về protected:

<?php

class Vehicle {
    protected $maxSpeed;

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

    protected function getMaxSpeedInfo() {
        return "Max Speed: " . $this->maxSpeed . " km/h";
    }
}

class SportsCar extends Vehicle {
    public function getSportsCarDetails() {
        // Truy cập thuộc tính protected từ lớp con
        return "This is a sports car with " . $this->getMaxSpeedInfo();
    }

    public function accelerate() {
        // Gọi phương thức protected từ lớp con
        echo "Accelerating... " . $this->getMaxSpeedInfo();
    }
}

// $myVehicle = new Vehicle(200);
// echo $myVehicle->maxSpeed; // Lỗi: Cannot access protected property Vehicle::$maxSpeed
// echo $myVehicle->getMaxSpeedInfo(); // Lỗi: Call to protected method Vehicle::getMaxSpeedInfo()

$mySportsCar = new SportsCar(300);
echo $mySportsCar->getSportsCarDetails(); // Output: This is a sports car with Max Speed: 300 km/h
echo "<br>";
$mySportsCar->accelerate(); // Output: Accelerating... Max Speed: 300 km/h

?>

Khi nào sử dụng protected?

  • Khi bạn muốn các thuộc tính hoặc phương thức chỉ được sử dụng trong hệ thống phân cấp kế thừa của lớp.
  • Để ẩn đi các chi tiết triển khai nội bộ mà các lớp con có thể cần truy cập hoặc mở rộng.
  • Để định nghĩa các phương thức "hook" mà các lớp con có thể ghi đè (override) để thay đổi hành vi.

3. Private (Riêng tư)

Khi một thuộc tính hoặc phương thức được khai báo là private, nó chỉ có thể được truy cập:

  • Bên trong lớp mà nó được định nghĩa.

không thể được truy cập:

  • Từ bên trong các lớp kế thừa (subclasses).
  • Từ bên ngoài lớp thông qua một đối tượng của lớp đó.

Đây là quyền truy cập hạn chế nhất, đảm bảo tính đóng gói (encapsulation) cao nhất.

Ví dụ về private:

<?php

class BankAccount {
    private $accountNumber;
    private $balance;

    public function __construct($accountNumber, $initialBalance) {
        $this->accountNumber = $accountNumber;
        $this->balance = $initialBalance;
        $this->logTransaction("Account created with initial balance: " . $initialBalance);
    }

    private function logTransaction($message) {
        // Phương thức private chỉ dùng nội bộ
        echo "LOG: " . $message . " at " . date("Y-m-d H:i:s") . "<br>";
    }

    public function deposit($amount) {
        if ($amount > 0) {
            $this->balance += $amount;
            $this->logTransaction("Deposited: " . $amount . ", New balance: " . $this->balance);
        } else {
            $this->logTransaction("Attempted to deposit invalid amount: " . $amount);
        }
    }

    public function getBalance() {
        return $this->balance;
    }
}

class SavingsAccount extends BankAccount {
    // public function testPrivate() {
    //     // Lỗi: Cannot access private property BankAccount::$balance
    //     // echo $this->balance;
    //     // Lỗi: Call to private method BankAccount::logTransaction()
    //     // $this->logTransaction("Attempt to log from SavingsAccount");
    // }
}

$myAccount = new BankAccount("123456789", 1000);

// echo $myAccount->accountNumber; // Lỗi: Cannot access private property BankAccount::$accountNumber
// $myAccount->logTransaction("Test external log"); // Lỗi: Call to private method BankAccount::logTransaction()

$myAccount->deposit(500); // Hoạt động bình thường
echo "Current balance: " . $myAccount->getBalance();
echo "<br>";

$savings = new SavingsAccount("987654321", 5000);
// $savings->testPrivate(); // Sẽ gây lỗi nếu uncomment

?>

Khi nào sử dụng private?

  • Khi bạn muốn một thuộc tính hoặc phương thức chỉ được sử dụng nội bộ trong lớp đó, không cho phép truy cập từ bên ngoài hay từ các lớp con.
  • Để đảm bảo tính toàn vẹn của dữ liệu nội bộ lớp bằng cách không cho phép truy cập trực tiếp từ bên ngoài.
  • Khi bạn có các phương thức trợ giúp (helper methods) chỉ phục vụ cho hoạt động của lớp và không nên được hiển thị ra bên ngoài.

Tóm tắt sự khác biệt

Quyền truy cập Từ cùng lớp Từ lớp kế thừa Từ bên ngoài đối tượng
public
protected Không
private Không Không

Lời khuyên về cách sử dụng

  • Mặc định là private: Một quy tắc chung trong OOP là "mặc định là private". Bắt đầu với private cho tất cả các thuộc tính và phương thức, sau đó nâng cấp lên protected hoặc public khi thực sự cần thiết. Điều này giúp tăng cường tính đóng gói và giảm sự phụ thuộc giữa các thành phần.
  • Encapsulation (Đóng gói): Sử dụng private để bảo vệ dữ liệu nội bộ của đối tượng. Thay vì truy cập trực tiếp các thuộc tính, hãy cung cấp các phương thức public (getter/setter) để kiểm soát cách dữ liệu được đọc và ghi. Điều này cho phép bạn thêm logic kiểm tra hợp lệ hoặc xử lý dữ liệu khi cần.
  • Inheritance (Kế thừa): protected là lựa chọn lý tưởng khi bạn muốn chia sẻ một số chức năng hoặc dữ liệu với các lớp con mà không muốn chúng bị truy cập công khai.
  • API của lớp: Các phương thức và thuộc tính public định nghĩa giao diện (API) của lớp bạn. Chúng là cách mà các phần khác của ứng dụng tương tác với đối tượng của bạn.

Kết luận

Việc nắm vững và áp dụng đúng các từ khóa public, protected, và private là nền tảng của lập trình hướng đối tượng hiệu quả trong PHP. Chúng cho phép bạn kiểm soát chặt chẽ quyền truy cập vào các thành viên của lớp, tăng cường tính đóng gói, dễ dàng quản lý mã nguồn và xây dựng các ứng dụng mạnh mẽ, linh hoạt và dễ bảo trì hơn. Hãy luôn suy nghĩ về mức độ hiển thị cần thiết cho từng thuộc tính và phương thức khi thiết kế các lớp của bạn.