ZetCode

PHP protected 关键字

最后修改于 2025 年 4 月 16 日

PHP protected 关键字是面向对象编程中使用的可见性修饰符。它控制对类成员(属性和方法)的访问。受保护的成员可以在类及其子类中访问。

基本定义

protected 关键字使类成员对类本身及其扩展的任何类都可用。这比 public 具有更严格的限制,但比 private 可见性限制更少。

受保护的成员无法从类层次结构外部访问。它们是为子类可能需要访问的内部类实现细节而设计的。

语法:protected $property;protected function method() {}。protected 修饰符可以应用于属性和方法。

基本受保护属性

此示例演示了父类中的一个简单受保护属性。

basic_protected.php
<?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。该属性无法直接从这些类外部访问。

受保护的方法继承

此示例显示了如何在继承中使用受保护的方法。

protected_method.php
<?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()。这强制了封装,同时允许继承。

从子类访问受保护成员

此示例演示了从子类访问受保护成员。

child_access.php
<?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() 方法提供了对这些受保护成员的受控访问。

受保护的构造函数

此示例显示了在单例模式中使用受保护的构造函数。

protected_constructor.php
<?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() 方法控制对象创建。这是一种常见的单例类模式。

重写受保护的方法

此示例演示了在子类中重写受保护的方法。

method_override.php
<?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 中使用的受保护属性。

trait_protected.php
<?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 可见性。

protected_vs_private.php
<?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 仅限于定义类。

最佳实践

来源

PHP 可见性文档

本教程通过实际示例介绍了 PHP protected 关键字,展示了各种面向对象场景中的受保护属性和方法。

作者

我叫 Jan Bodnar,是一位充满激情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。到目前为止,我撰写了 1,400 多篇文章和 8 本电子书。我拥有超过十年的编程教学经验。

列出 所有 PHP 教程