看过了一些trait的介绍,也在框架中看到了。但是感觉trait做的事情,用interface是不是也能做呢?
个人感觉每个trait实现的功能都非常集中,也非常轻量,这个很赞,但是相对的有些class可能要同时用好几个trait,而且假如同时继承了类,实现了接口,并且其中包含覆盖,那理清这个类的关系感觉会很困难,这是我最困惑的地方,当然也可能是我技术还不够。
但是既然出了这个语法,肯定还是有他的道理的,所以就想问一下,项目中使用trait的意义是什么呢?
PHP
和Java
等大多数面向对象的语言一样是单继承,既一个类只能继承于一个父类。虽然单继承是公认使代码清晰准确的方式,但有时候多继承也有自己的优势。trait
的出现就是一种解决需要多继承场景的方式。多继承的好处就是让一个类继承多个父类的功能,虽然这违反了类单一职责原则,但是在某些场合下,一些小功能使用多继承是最合适不过的。比如Laravel
中定义了一个宏trait
,只是很简单的让类实现一些类似C
宏定义的方法,因为这其中含有一些实体方法和属性,所以通过interface
定义是不能实现的,而需要使用这个功能的类又有可能已经继承于其他类,所以通过abstract class
定义也是不能实现的,所以这种场合下trait
就能体现它的优势了。
trait和interface恰好相反,interface关心的是接口,把实现丢给其他人,而trait完全不关心接口(约定),只提供实现。不那么准确地说的话,trait = abstract class - interface,提供了另一个维度的灵活性
一个常见的应用场景是为接口提供“默认实现”,比如经典的\Psr\Log\LoggerInterface
接口,有一堆方法(critical/emerg/info/debug)等等,但实际实现的时候,大家都会把这些方法都转发到log()
方法里去,所以PSR提供了\Psr\Log\LoggerTrait
,这样既保持了接口的完整(每个错误等级都有独立的方法),又方便了实现者