PHP 为什么会引入 Trait

软件开发中的两种常用代码复用模式,继承和组合。

继承:强调 父类与子类 的关系,即子类是父类的一个特殊类型;

组合:强调 整体与局部 的关系,侧重的一种需要的关系;


软件开发中有一条原则,叫做组合优于继承。这是因为从耦合度来看,继承要高于组合。继承关系中,子类与父类保持着高度的依赖关系,加上 PHP 不支持多继承,为了避免重写编写代码,很多功能都被统一封装到父类中。这样做有两个坏处:一是随着继承的层数和子类的增加,代码复杂度不断增加,大量的方法都将面临着重写;二是这些功能对于一些子类来说可能是不必要的,破坏了代码的封装性。


trait ezcReflectionReturnInfo {
  function getReturnType() { /*1*/ }
  function getReturnDescription() { /*2*/ }
}

class ezcReflectionMethod extends ReflectionMethod {
  use ezcReflectionReturnInfo;
  /* ... */
}

class ezcReflectionFunction extends ReflectionFunction {
  use ezcReflectionReturnInfo;
  /* ... */
}



Trait 与类的冲突处理

当存在同名方法时,当前类的方法会覆盖 Trait 中的方法,而 Trait 中的方法会覆盖父类的方法。


当存在同名属性时,类的属性必须与 Trait 的属性兼容(相同的访问性、相同的初始值),否则会报致命错误。


当一个类包含多个 Trait 时,不同 Trait 之间可能会存在属性和方法的冲突。当存在相同属性时,属性必须兼容,跟 Trait 与类的冲突处理类似。当存在方法冲突时,需要使用 insteadof 来手动处理冲突,否则会报致命错误



参考:

https://www.php.net/traits

https://zhuanlan.zhihu.com/p/92380166