Menu
CoddyTech

公有、受保护、私有

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

欢迎来到封装这一章!封装是指控制对类内部数据的访问。PHP 提供了 3 种访问修饰符,用来确定可以从哪里访问属性和方法:public、protected 和 private。

下面介绍每个修饰符的作用:

<?php
class BankAccount {
    public $accountHolder;    // 可以从任何地方访问
    protected $accountNumber; // 可以在此类及其子类中访问
    private $balance;         // 只能在此类中访问
    
    public function __construct($holder, $number, $balance) {
        $this->accountHolder = $holder;
        $this->accountNumber = $number;
        $this->balance = $balance;
    }
    
    public function getBalance() {
        return $this->balance;
    }
}

$account = new BankAccount("John", "12345", 1000);

echo $account->accountHolder . "\n";  // 可以运行,因为它是公有的
echo $account->getBalance();          // 可以运行,因为它是公有方法

输出:

John
1000

直接访问 $account->balance 会导致错误,因为它是私有的。在类层次结构之外访问 $account->accountNumber 也是如此。这种保护机制确保敏感数据只能通过受控的方法进行修改。

修饰符同一个类子类外部
public是是是
protected是是否
private是否否

要点:对于不应被直接访问的内部数据,使用 private;对于子类需要的数据,使用 protected;只有在允许安全地从外部访问时,才使用 public。

challenge icon

挑战

简单

让我们构建一个安全的员工管理系统,演示访问修饰符如何保护敏感数据。你将创建一个类层次结构,根据代码的运行位置来控制不同级别信息的访问权限:在类内部、子类中或从外部访问。

你将把代码分成 3 个文件:

  • Employee.php:创建一个管理员工数据的 Employee 类,并为属性设置适当的可见性级别。这个类应包含:
    • 一个 public 属性 $name,用于存储员工姓名(任何人都可以安全地查看)
    • 一个 protected 属性 $employeeId,用于存储内部 ID(子类需要用到)
    • 一个 private 属性 $salary,用于存储敏感的薪酬信息(只有这个类可以直接访问)
    构造函数应接收这 3 个值并赋值。添加一个公共方法 getSalary(),用于返回私有薪水。这是访问受保护数据的受控方式。还要添加一个公共方法 getPublicInfo(),用于返回 "[name] works here"。
  • Manager.php:创建一个继承 Employee 的 Manager 类。引入 Employee 文件。构造函数应接收姓名、employeeId、薪水和部门名称。用前三个值调用父类构造函数,然后将部门存储在一个私有属性中。添加一个公共方法 getTeamInfo(),用于返回 "Manager [name] (ID: [employeeId]) leads [department]"。注意,子类可以访问受保护的 $employeeId,但要访问私有薪水则需要使用 getSalary()。
  • main.php:引入 Manager 文件。你会收到 4 个输入:姓名、员工 ID、薪水(以字符串形式提供,你需要将其转换为整数)和部门名称。用这些值创建一个 Manager 实例。打印 3 行:
    • 直接访问经理的姓名(公共属性)
    • 调用 getTeamInfo() 的结果
    • 调用 getSalary() 的结果

这个挑战展示了封装的实际应用:姓名可以自由访问,员工 ID 通过受保护的可见性与子类共享,而薪水则保留在父类中,只能通过受控的公共方法访问。

亲手试试

<?php
require_once 'Manager.php';

// 读取输入
$name = trim(fgets(STDIN));
$employeeId = trim(fgets(STDIN));
$salary = intval(trim(fgets(STDIN)));
$department = trim(fgets(STDIN));

// TODO:使用输入值创建一个 Manager 实例

// TODO:输出经理的姓名(直接访问其公共属性)

// TODO:输出调用 getTeamInfo() 的结果

// TODO:输出调用 getSalary() 的结果
?>
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: PHP 在线编译器