如何理解 php trait,简述我所理解的 PHP Trait

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 期待您关注

你可能感兴趣的:(如何理解,php,trait)