Trait 概念
在常规的 PHP 开发中,我们都习惯于先编写一个通用的基类,实现基本的功能,然后扩展这个基类,创建更具体的子类,直接从父类继承实现。很多编程语言都使用这个继承层次结构模式。大多数时候这种典型的继承模型能够良好运作,但是如果想让两个无关的PHP 类具有类似的行为,而不是采用继承的模式,应该怎么做呢?
Trait 就是为了解决这种问题而诞生的。Trait能够把模块化的实现方式注入多个无关的类中,从而提高代码复用,符合 DRY(Don’t Repeat Yourself)原则。
自 PHP 5.4.0 起,PHP 实现了一种代码复用的方法,称为 trait。
Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。Trait 为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用 method。Trait 和 Class 组合的语义定义了一种减少复杂性的方式,避免传统多继承和 Mixin 类相关典型问题。
Trait 和 Class 相似,但仅仅旨在用细粒度和一致的方式来组合功能。 无法通过 trait 自身来实例化。它为传统继承增加了水平特性的组合;也就是说,应用的几个 Class 之间不需要继承。
Trait 简单的来说,就是将一些通用的,可重复的方法独立出去,拆分成为可复用的组件,最后只要在需要的地方 use 组件,所有代码以【插件】的形式引入,这样的代码可读性更高。
如何将一个完整的代码进行拆分,分解出一些可复用的组件,就是我们实际写代码的场景决定了。如 Laravel 队列。
Laravel 队列
Laravel 队列为不同的后台队列服务提供统一的 API , 例如 Beanstalk,Amazon SQS, Redis,甚至其他基于关系型数据库的队列。 队列的目的是将耗时的任务延时处理,比如发送邮件,从而大幅度缩短Web请求和相应的时间。
队列配置文件存放在 config/queue.php。 每一种队列驱动的配置都可以在该文件中找到, 包括数据库, Beanstalkd, Amazon SQS, Redis, 以及同步(本地使用)驱动。 其中还包含了一个 null 队列驱动用于那些放弃队列的任务
创建 Laravel 队列也很简单,只需要在 Jobs 目录下创建类,集成 ShouldQueue 接口即可,如:
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class SendLogMpMessage implements ShouldQueue
{
use InteractsWithQueue, Queueable, SerializesModels;
// 0:表示接收, 1:表示回复
private $message;
public function __construct($message) {
$this->message = $message;
}
public function handle() {
$options = [
'tag' => 'wechat',
'text' => $this->message
];
$this->sendRequest("url", $options, "", "POST");
}
}
其它的根据需要,通过引入 Trait 即可,如上述代码的三个 Trait: InteractsWithQueue, Queueable, SerializesModels,每个 Trait 各司其职:
namespace Illuminate\Queue;
use ReflectionClass;
use ReflectionProperty;
trait SerializesModels
{
use SerializesAndRestoresModelIdentifiers;
/**
* Prepare the instance for serialization.
*
* @return array
*/
public function __sleep()
{
$properties = (new ReflectionClass($this))->getProperties();
foreach ($properties as $property) {
$property->setValue($this, $this->getSerializedPropertyValue(
$this->getPropertyValue($property)
));
}
return array_map(function ($p) {
return $p->getName();
}, $properties);
}
/**
* Restore the model after serialization.
*
* @return void
*/
public function __wakeup()
{
foreach ((new ReflectionClass($this))->getProperties() as $property) {
$property->setValue($this, $this->getRestoredPropertyValue(
$this->getPropertyValue($property)
));
}
}
/**
* Get the property value for the given property.
*
* @param \ReflectionProperty $property
* @return mixed
*/
protected function getPropertyValue(ReflectionProperty $property)
{
$property->setAccessible(true);
return $property->getValue($this);
}
}
这个 SerializesModels Trait 的主要作用是,如果你的消息队列的构造器中接收了 Eloguent 模型,那么就可识别出该模型的属性会被序列化到队列里。当任务被实际运行时,队列系统便会自动从数据库中重新取回完整的模型。这整个过程对这个任务类来说,完全透明,根本上就不用去关心和 Eloguent 模型序列化和反序列化的问题。如果任务队列中,如果不需要引入 Eloquent 模型,可以不需要 use SerializesModels。
同样的道理,根据引入不同的 Trait 来完成对应的功能。
总结
Laravel 框架大量使用了 traits。只要有心观察,还是能看出这种写法所带来的好处,和代码的可扩展性。
参考
听说最美的人和最帅的人,都会给作者打赏,以资鼓励
coding01 期待您关注