PHP protected 关键字
最后修改于 2025 年 4 月 16 日
PHP protected 关键字是面向对象编程中使用的可见性修饰符。它控制对类成员(属性和方法)的访问。受保护的成员可以在类及其子类中访问。
基本定义
protected 关键字使类成员对类本身及其扩展的任何类都可用。这比 public 具有更严格的限制,但比 private 可见性限制更少。
受保护的成员无法从类层次结构外部访问。它们是为子类可能需要访问的内部类实现细节而设计的。
语法:protected $property; 或 protected function method() {}。protected 修饰符可以应用于属性和方法。
基本受保护属性
此示例演示了父类中的一个简单受保护属性。
<?php
declare(strict_types=1);
class Vehicle {
protected $model;
public function setModel(string $model): void {
$this->model = $model;
}
}
class Car extends Vehicle {
public function getModel(): string {
return $this->model;
}
}
$car = new Car();
$car->setModel("Toyota");
echo $car->getModel();
$model 属性在 Vehicle 类中受保护。Car 类可以访问它,因为它继承了 Vehicle。该属性无法直接从这些类外部访问。
受保护的方法继承
此示例显示了如何在继承中使用受保护的方法。
<?php
declare(strict_types=1);
class Animal {
protected function makeSound(): string {
return "Some generic animal sound";
}
}
class Dog extends Animal {
public function bark(): string {
return $this->makeSound() . " - Woof!";
}
}
$dog = new Dog();
echo $dog->bark();
makeSound 方法在 Animal 中受保护。Dog 类可以在内部调用此方法。外部代码无法直接调用 makeSound()。这强制了封装,同时允许继承。
从子类访问受保护成员
此示例演示了从子类访问受保护成员。
<?php
declare(strict_types=1);
class BankAccount {
protected $balance = 0;
protected function deposit(int $amount): void {
$this->balance += $amount;
}
}
class SavingsAccount extends BankAccount {
public function addMoney(int $amount): void {
$this->deposit($amount);
echo "New balance: " . $this->balance;
}
}
$account = new SavingsAccount();
$account->addMoney(100);
SavingsAccount 可以从其父类访问受保护的属性 $balance 和方法 deposit。公共的 addMoney() 方法提供了对这些受保护成员的受控访问。
受保护的构造函数
此示例显示了在单例模式中使用受保护的构造函数。
<?php
declare(strict_types=1);
class Logger {
protected function __construct() {
echo "Logger initialized";
}
public static function getInstance(): self {
static $instance = null;
if (null === $instance) {
$instance = new static();
}
return $instance;
}
}
$logger = Logger::getInstance();
构造函数受到保护以防止直接实例化。静态的 getInstance() 方法控制对象创建。这是一种常见的单例类模式。
重写受保护的方法
此示例演示了在子类中重写受保护的方法。
<?php
declare(strict_types=1);
class Shape {
protected function calculateArea(): float {
return 0;
}
public function getArea(): float {
return $this->calculateArea();
}
}
class Circle extends Shape {
protected float $radius;
public function __construct(float $radius) {
$this->radius = $radius;
}
protected function calculateArea(): float {
return pi() * $this->radius * $this->radius;
}
}
$circle = new Circle(5);
echo $circle->getArea();
Circle 类重写了 Shape 类的受保护的 calculateArea 方法。公共的 getArea() 方法提供对计算的访问。这显示了具有受保护方法的多态行为。
Trait 中的受保护属性
此示例显示了在 traits 中使用的受保护属性。
<?php
declare(strict_types=1);
trait Loggable {
protected $logMessages = [];
protected function addLog(string $message): void {
$this->logMessages[] = $message;
}
public function getLogs(): array {
return $this->logMessages;
}
}
class User {
use Loggable;
public function login(): void {
$this->addLog("User logged in");
}
}
$user = new User();
$user->login();
print_r($user->getLogs());
该 trait 定义了受保护的属性 $logMessages 和方法 addLog。使用该 trait 的 User 类可以访问这些受保护的成员。 Traits 通过可见性控制提供水平代码重用。
Protected vs Private
此示例比较了 protected 和 private 可见性。
<?php
declare(strict_types=1);
class ParentClass {
private $privateVar = "private";
protected $protectedVar = "protected";
}
class ChildClass extends ParentClass {
public function showProtected(): string {
return $this->protectedVar;
}
public function showPrivate(): string {
return $this->privateVar; // This will cause an error
}
}
$child = new ChildClass();
echo $child->showProtected();
// echo $child->showPrivate(); // Would cause fatal error
子类可以访问受保护的属性,但不能访问私有属性。这演示了 protected 和 private 可见性之间的关键区别。protected 允许继承访问,而 private 仅限于定义类。
最佳实践
- 封装: 对子类需要实现的细节使用 protected。
- 文档: 为继承类清晰地记录受保护的成员。
- 访问控制: 对于内部类 API,优先使用 protected 而不是 public。
- 测试: 通过公共接口或反射测试受保护的方法。
- 设计: 考虑使用 protected abstract 方法进行模板方法。
来源
本教程通过实际示例介绍了 PHP protected 关键字,展示了各种面向对象场景中的受保护属性和方法。
作者
列出 所有 PHP 教程。