PHP的面向对象特性经历了漫长而曲折的演进。PHP 4首次引入了类和对象,但对象模型极为简陋——对象在赋值时被复制(与资源不同),没有访问控制,没有抽象类和接口。PHP 5彻底重写了对象模型,引入了引用语义、访问修饰符、抽象类、接口和异常。PHP 7和PHP 8在此基础上继续完善,增加了匿名类、类型属性、构造器属性提升和枚举。这场进化使PHP从一个“带对象的脚本语言”成长为成熟的面向对象语言。
参考:https://xrzqr.cn/category/city-forecast.html
PHP 4的对象模型:PHP 4的“对象”实际上只是关联数组的语法糖。使用new创建对象时,返回的是资源,但在赋值给变量时,对象被完整复制(不是引用)。这意味着$a = new Person(); $b = $a; $b->name = 'Bob';不会改变$a->name。这种行为与所有其他语言都不同,是无数bug的来源。PHP 4也没有private、protected、abstract、interface等概念。
PHP 5的里程碑:PHP 5重写了对象模型,引入了对象句柄(object handle)。对象变量不再持有对象本身,而是持有一个指向对象句柄的标识符。对象句柄包含指向对象数据的指针和引用计数。赋值时复制的是句柄,而不是对象数据——这与大多数面向对象语言一致。PHP 5还引入了construct和destruct魔术方法,以及parent::关键字。
访问控制(public、protected、private)是PHP 5的另一重要特性。public成员可以在任何地方访问;protected成员可以在类内部和子类中访问;private成员只能在定义它们的类内部访问。访问控制是封装的基础,也是设计健壮API的关键。
抽象类和接口:抽象类(abstract)可以包含抽象方法(无实现)和具体方法。接口(interface)只能声明方法签名,不能包含实现。PHP支持单继承类和多实现接口。接口使PHP的类型系统更加灵活,支持策略模式和依赖注入。
异常处理:PHP 5引入了try-catch-finally和Exception类。与Java不同,PHP的异常可以不捕获,此时会触发致命错误。Throwable接口(PHP 7)是Exception和Error的超类型,统一了可抛出的错误。
参考:https://xrzqr.cn/category/city-forecast.html
PHP 5.3的后期静态绑定:在PHP 5.3之前,静态方法中的self总是在编译期绑定到定义该方法的类。后期静态绑定使用static关键字,在运行时绑定到实际调用的类。这对于建造者模式和单表继承非常有用。
PHP 5.4的特征(Traits)是水平代码复用的机制。Traits允许类重用方法集合,而无需继承。Traits解决了PHP单继承的限制,使代码复用更加灵活。Traits可以有抽象方法、静态方法和属性,但不能有类常量。
PHP 5.5的::class:ClassName::class返回类的完整命名空间名称字符串。这个特性消除了使用类名字符串时的硬编码问题,使IDE的重构功能能够正确工作。
PHP 7的匿名类:匿名类允许在运行时动态创建一次性类。new class($arg) extends SomeClass { ... }。匿名类常用于测试(创建mock对象)和简单的DTO(数据传输对象)。
PHP 7.4的类型属性:类属性现在可以声明类型。public int $id;。类型属性在赋值时被检查,包括初始化时。未初始化的类型属性在被读取时抛出Error。类型属性支持int、float、string、bool、array、object、可空类型(?int)、以及类和接口类型。
PHP 7.4的箭头函数:箭头函数提供更简洁的闭包语法,自动捕获外部变量。$fn = fn($x) => $x * $x;。箭头函数与类方法的结合更加自然。
PHP 8的构造器属性提升:这是PHP 8最受欢迎的语法糖。在构造器参数前加上public、protected或private修饰符,PHP会自动将参数提升为同名的类属性,并在构造器中赋值。public function __construct(public string $name, public int $age) {}。这消除了大量的样板代码。
参考:https://xrzqr.cn/category/national-weather.html
PHP 8的枚举(Enumerations)是面向对象的类型安全枚举。enum Status: string { case PENDING = 'pending'; case ACTIVE = 'active'; }。枚举可以有方法,可以实现接口,可以有回退值(backed enum)。枚举与switch语句完美配合,提供穷尽性检查。
PHP 8.1的只读属性:public readonly string $id;。只读属性只能在初始化时赋值一次,之后不可修改。只读属性与构造器属性提升结合使用,可以创建不可变对象。
PHP 8.2的只读类:readonly class Person { ... }。只读类的所有属性自动成为只读的,不能有静态属性。只读类是创建值对象的最佳方式。
PHP 8.2的析取范式类型:允许更复杂的类型组合,如(A&B)|C(A和B的交集,或者C)。这主要用于更精确的类型系统表达,实际使用较少。
魔术方法的演进:get、set、call、callStatic、toString、invoke等魔术方法在PHP 5中引入,并在后续版本中保持稳定。serialize和unserialize(PHP 7.4)替代了旧的sleep和wakeup,提供了更安全的序列化控制。
对象比较:==比较两个对象是否属性相同(值相等),===比较是否引用同一个对象。PHP 8引入了__equals(尚未标准化)来定制值相等的语义。
反射API:ReflectionClass、ReflectionMethod、ReflectionProperty等类提供了运行时检查类结构的能力。反射用于文档生成、依赖注入容器、序列化框架等。
最佳实践:优先使用组合而非继承;使用接口定义契约;使用抽象类提供默认实现;使用trait复用跨层次的行为;使用枚举替代常量类;使用只读属性和构造器提升创建不可变对象;以及始终在类型声明中使用严格模式。
PHP的面向对象演进证明了PHP社区对现代软件工程实践的拥抱。从PHP 4的原始对象到PHP 8的企业级对象模型,PHP已经准备好构建任何规模的应用。
参考:https://xrzqr.cn