Laravel 在哪些地方用了 trait?

laravel 框架大量使用了traits. 简单举几个例子:

在Eloquent中使用了trait 。然后在model初始化的时候,有个boot方法,会自动判断当前的类用了哪些trait。然后得到一个数组。程序会遍历这个数组,寻找有没有符合 "bootTraitName"的方法(在trait中定义),如果有就执行。

/**
 * Boot all of the bootable traits on the model.
 *
 * @return void
 */
protected static function bootTraits()
{
    foreach (class_uses_recursive(get_called_class()) as $trait) {
        if (method_exists(get_called_class(), $method = 'boot'.class_basename($trait))) {
            forward_static_call([get_called_class(), $method]);
        }
    }
}

Eloquent用这种方法,在初始化一个model的时候,就可以做许多自动加载. laravel自带的功能中,softDelete就是通过trait来实现的。简单来说,use了softDelete的model,会在boot的时候自动执行bootSoftDelete,然后该方法在model所有的查询都默认加入一个判断deleted_at 字段的环节,以只调取未被删除的数据。

/**
 * Boot the soft deleting trait for a model.
 *
 * @return void
 */
public static function bootSoftDeletes()
{
    static::addGlobalScope(new SoftDeletingScope);
}

这种做法提供了很多便利,也提供了trait的使用示范。

举个简单的例子: 我们可以用这种方法 , 给model加载一个自动清除缓存的trait . 在每一个模型每次saved之后,自动刷新它的缓存:

trait ModelCache {

    public static function bootModelCache(){
        static::saved(function($model){
            $cacheKey = get_class($model).'_'.$model->id;
            Cache::forget($cacheKey);
        });
    }

}

trait在laravel的其它场景中也经常使用。例如User模型,是Laravel用来做身份验证的驱动。与身份验证的相关方法就是用一个trait来加载的。

<?php

namespace Illuminate\Auth;

trait Authenticatable
{
    /**
     * Get the unique identifier for the user.
     *
     * @return mixed
     */
    public function getAuthIdentifier()
    {
        return $this->getKey();
    }

    .................

    /**
     * Get the token value for the "remember me" session.
     *
     * @return string
     */
    public function getRememberToken()
    {
        return $this->{$this->getRememberTokenName()};
    }

}

这样当我们需要换别的模型,别的控制器做验证驱动,只要写一行use 代码,就自动得到了相关方法。

laravel使用trait还有一个比较典型的,就是dispatch。主要在laravel的controller中调用了这个trait。这样laravel的控制器就可以用$this->dispatch() 直接来调度任务。

trait DispatchesJobs
{
    /**
     * Dispatch a job to its appropriate handler.
     *
     * @param  mixed  $job
     * @return mixed
     */
    protected function dispatch($job)
    {
        return app('Illuminate\Contracts\Bus\Dispatcher')->dispatch($job);
    }

    ...........
}

任何一个类只要use了这个DispatchJob的trait,都能用同样的调度方法(其实就是用app()得到了一个dispatch的单例)。

灵活使用trait , 还是能创造各种魔法 . 我有一个设想就是通过模仿laravel的trait机制实现的 .

简单来说 , 在做一个复杂的资讯站时 , 可能要创建许多种model . 然而每个model 总有一部分模块是一样的,例如:

  • 文章(标题,作者,正文)
  • 图片组(图片,简介)
  • 视频(标题,来源,源码,简介)
  • 添加到tag
  • 相关专题
  • 等等

创建model时,重复添加这些字段是一个很头疼的工作. 而现在,我们可以用trait:

abstract class Installer {

    //引用文章,图片,视频相关字段的构造trait
    use ArticleTrait,ImageTrait,VideoTrait;

    /**
     *  创建数据表
     */
    protected function CreateTable()
    {

        //用Schema创建数据表
        Schema::Create($this->table,function(Blueprint $table){

            //生成默认字段
            $table = $this->makeDefaultFields($table);

            //生成trait中的字段
            $table = $this->makeTraitFields($table);

        });

    }

    /**
     *   生成默认字段
     */
    protected function makeDefaultFields(Blueprint $table)
    {
        $table->increaments('id');
        $table->timestamps();
        return $table;
    }

    /**
     *   按照trait内的方法,生成模块的字段
     */
    protected function makeTraitFields(Blueprint $table)
    {
        foreach (class_uses_recursive(get_called_class()) as $trait) {

            //如果trait内有 makeTraitNameFields方法, 就用该方法生成字段
            if (method_exists($this, $method = 'make'.class_basename($trait).'Fields')) {
                $table = $this->{$method}($table);
            }

        }

        return $table;
    }

}

这样 , 建完几个标准的trait后, 要建其它复杂的模型,代码上就非常简单了

本帖已被设为精华帖!
BrightRed
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 2
(= ̄ω ̄=)··· 暂无内容!

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!

社区文档:

将托管在 packagist.org 和 github.com 的扩展包使用国内 CDN 加速
GitHub Laravel 扩展包 TOP 250
速查表方便快速查询框架功能,支持手机访问,支持中英文版本
Laravel 中文文档,由社区用户翻译和维护,将会保持一直更新
此文档的目的,就是为了提高技术团队的凝聚力、一致性和生产效率。
开发环境的部署,开发者工具的选择,适用于 Mac 和 Windows。
浓缩过后的精华
Laravel Nova 后台管理面板文档的中文翻译
Lumen 中文文档,由社区用户翻译和维护,将会保持一直更新
Laravel 下知名扩展包 Dingo API 的中文文档,Laravel API 开发必知必会