简述我所理解的 PHP Trait

6302-5acc833d33ecde18

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 接口即可,如:

<?php

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 各司其职:

<?php

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。只要有心观察,还是能看出这种写法所带来的好处,和代码的可扩展性。

参考

  1. http://php.net/manual/zh/language.oop5.traits.php
  2. http://d.laravel-china.org/docs/5.4/queues

听说最美的人和最帅的人,都会给作者打赏,以资鼓励

6302-8bf89c2093f959d2.jpeg
qrcode

coding01 期待您关注

6302-2fd5d39237c2f965.jpeg
qrcode
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值