访问控制(可见性)
对属性或方法的访问控制(PHP 7.1后支持常量),是通过在前面添加关键字public (公有)、protected 、 private 来实现。公有的任意可见,受保护的可被自身及其子类和父类访问,私有的只能被其定义所在的类访问
属性的访问控制
类属性可以定义为public,private或者protected 。在没有任何访问控制关键字的情况下,属性声明为public

不对称属性可见性
从PHP 8.4开始,属性也可以设置不对称的可见性,读取(get)和写入(set)可以有不同的范围,准确的说可以单独指定set可见性,只要它不比默认可见性更宽。


当一个类继承另一个类时,子类可以重新定义任何不是final的属性。这样做时,可以扩大主要可见性或set可见性,只要新的可见性和父类相同或者更宽,需要注意的是,若一个private属性被重写,它实际上并没有改变父类的属性,而是创建了一个具有不同内部名称的新属性。

方法的访问控制
类中的方法可以被定义为public、private、protected。如果没设置默认为public


魔术方法与可见性
通过实现
__get()、__set()等魔术方法,可以动态访问private或未定义的属性。魔术方法不会改变实际的属性可见性,但会提供访问入口,常用于封装和懒加载。
抽象方法与可见性
抽象方法只能声明为
public或protected,不能是private。抽象方法必须在抽象类中定义,由子类实现具体功能。
常量的控制访问
自PHP 7.1后 , 类的常量可以定义为,public、private 或 protected ,没设置就默认public

其它对象的访问控制
同一个类的对象即使不是同一个实例也可以互相访问对方的private与protected成员。

接口中的方法可见性
接口中的方法默认都是
public,不能声明为protected或private。实现接口时,方法必须保持为
public,否则会报错。
对象继承
PHP的对象模型使用了继承,继承可以影响到类与类,对象与对象之间的关系。
比如,当扩展一个类,子类就会继承父类所有public和protected的方法,属性和常量。除非子类覆盖了父类的方法,被继承的方法都会保留其原有功能。
继承有助于功能的设计和抽象,在实现类似的对象、增加新功能时,无须重复编写这些公用的功能
子类无法访问父类的私有方法。因此,子类无需考虑正常的继承规则而重新实现私有方法。然而,在PHP 8.0前,final和static 的限制会应用于private方法。自PHP 8.0起,仅private final 的构造器是唯一受限的private方法;想要“禁用”构造器,通常使用静态工厂方法作为代替。
方法,属性和常量的可见性可以放宽,例如protected方法可以标记为public,但不能增加限制,例如标记public属性为private。


使用 final 限制继承或重写
使用
final可以防止某个方法被子类覆盖,或防止整个类被继承。final不改变可见性,但会影响继承层级的可扩展性。从 PHP 8.0 起,
private方法(除构造器外)不会受final约束。
Trait(特征)与可见性
Trait 可用于多个类共享属性或方法。
Trait 中可以使用
public、protected、private来声明方法可见性。如果多个 Trait 有同名方法,需使用
insteadof或as解决冲突,且可改变方法可见性。
返回类型与内部类兼容
PHP 8.1前,大多数内部类或方法没有声明其返回类型,并且在继承它们是允许返回任何类型。
自PHP 8.1起 大多数内部方法开始“暂时”声明其返回类型,在这种情况下,方法的返回类型应该与继承的父级方法兼容,否则,将发出弃用通知。注意,没有指定返回声明也会视为签名不匹配,从而导致弃用通知。


反射 API 可突破可见性
PHP 的
ReflectionProperty、ReflectionMethod等允许在运行时读取和修改private或protected成员。通过
setAccessible(true)可访问原本不可见的属性或方法,适用于单元测试或框架内部。
封装示例(Best Practice)
展示如何组合 private + getter/setter + readonly
class Product {
private float $price;
public function __construct(float $price) {
$this->price = $price;
}
public function getPrice(): float {
return $this->price;
}
protected function setPrice(float $price): void {
$this->price = $price;
}
}