Menu
CoddyTech

私有和受保护属性

本课属于 Coddy PHP 学习旅程的“面向对象编程”单元。第 18 课,共 91 课。

到目前为止,我们一直使用可以从任何地方访问的 public 属性。但有时你需要限制访问,以保护数据。PHP 还提供了两种可见性修饰符:private 和 protected。

private 属性只能在定义它的类内部访问:

<?php
class BankAccount {
    private $balance = 0;
    
    public function deposit($amount) {
        $this->balance += $amount;
    }
    
    public function getBalance() {
        return $this->balance;
    }
}

$account = new BankAccount();
$account->deposit(100);
echo $account->getBalance();

输出:

100

如果尝试在类外部直接访问 $account->balance,就会导致错误。这样可以保护余额,避免它未通过 deposit 方法就被更改。

protected 属性的作用类似,但扩展父类的子类也可以访问它:

<?php
class User {
    protected $email;
    
    public function __construct($email) {
        $this->email = $email;
    }
}

class Admin extends User {
    public function showEmail() {
        return $this->email;
    }
}

$admin = new Admin("admin@example.com");
echo $admin->showEmail();

输出:

admin@example.com

要点:只有定义该属性的类应该访问它时,使用 private。子类也需要访问时,使用 protected。这两者都能阻止外部直接访问,保护对象的内部状态。

challenge icon

挑战

简单

我们来构建一个安全的员工管理系统,演示如何使用 private 和 protected 属性保护敏感数据。

你将创建三个协同工作的文件,通过适当的访问控制来管理员工信息:

  • Employee.php:定义一个作为所有员工基类的 Employee 类。它应有一个 protected $name 属性(这样子类就能访问它),以及一个 private $salary 属性(只有这个类才能直接修改薪水)。构造函数接收姓名和薪水,并设置这两个属性。添加一个返回姓名的 public getName() 方法、一个返回薪水的 public getSalary() 方法,以及一个按给定金额增加薪水的 public giveRaise($amount) 方法。
  • Manager.php:定义一个继承 Employee 的 Manager 类。在文件顶部引入 Employee 文件。添加一个 private $department 属性。构造函数应接收姓名、薪水和部门:使用 parent::__construct($name, $salary) 调用父类构造函数,然后设置部门。创建一个 getDetails() 方法,通过直接访问 protected $name 属性,返回 "[name] manages [department]"。另外,添加一个返回部门的 getDepartment() 方法。
  • main.php:引入这两个类文件。创建一个 Manager,姓名为 "Sarah",薪水为 75000,部门为 "Engineering"。使用 getDetails() 输出经理的详细信息。然后给经理加薪 5000,并使用 getSalary() 输出加薪后的薪水。每条输出都应单独占一行。

注意,Manager 类可以直接访问 protected $name 属性,但必须使用 getSalary() 方法来访问 private 薪水。这展示了 protected 和 private 可见性的关键区别:protected 允许子类访问,而 private 会将数据真正隐藏起来。

亲手试试

<?php
require_once 'Employee.php';
require_once 'Manager.php';

// TODO: 创建一个 Manager,姓名为 "Sarah",薪资为 75000,部门为 "Engineering"

// TODO: 使用 getDetails() 输出经理的详细信息

// TODO: 给经理加薪 5000

// TODO: 使用 getSalary() 输出新薪资
?>
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: PHP 在线编译器