公有、受保护、私有
本课属于 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。
挑战
简单让我们构建一个安全的员工管理系统,演示访问修饰符如何保护敏感数据。你将创建一个类层次结构,根据代码的运行位置来控制不同级别信息的访问权限:在类内部、子类中或从外部访问。
你将把代码分成 3 个文件:
Employee.php:创建一个管理员工数据的Employee类,并为属性设置适当的可见性级别。这个类应包含:- 一个
public属性$name,用于存储员工姓名(任何人都可以安全地查看) - 一个
protected属性$employeeId,用于存储内部 ID(子类需要用到) - 一个
private属性$salary,用于存储敏感的薪酬信息(只有这个类可以直接访问)
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() 的结果
?>这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: PHP 在线编译器