简述我所理解的 PHP Trait

作者: Coding01 | 来源:发表于2017-08-26 21:18 被阅读46次

    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

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

    qrcode

    coding01 期待您关注

    qrcode

    相关文章

      网友评论

        本文标题:简述我所理解的 PHP Trait

        本文链接:https://www.haomeiwen.com/subject/hwuvdxtx.html