IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Laravel tap 用法

    jcc发表于 2017-02-22 22:33:30
    love 0

    本文参照转译:

    http://derekmd.com/2017/02/la...

    https://murze.be/2017/02/lara...

    Laravel 5.3 中增加了一个新的全局帮助函数 tap(),改进了框架的声明能力。这个微妙的语法是从 Ruby 和 Lodash 借鉴而来,允许你去 tap 成链。

    先看看 tap() 帮助函数的代码,只有短短的几行:

    function tap($value, $callback)
    {
       $callback($value);
    
       return $value;
    }

    你需要传一个值和一个回调到方法中,值作为回调的参数,回调将执行,最后值被返回。

    执行中间操作

    从一个简单的例子开始,提取 Laravel 的 AuthenticateSession@handle() 的一些代码,一些 PHP 开发者非常熟悉的解决方案:

    $response = $next($request);
     
    $this->storePasswordHashInSession($request);
     
    return $response;

    使用 tap() 帮助函数:

    return tap($next($request), function () use ($request) {
        $this->storePasswordHashInSession($request);
    });

    另外的一个简单的例子,让我们看看 Illuminate\Cache\Repository 下的 pull 方法,此函数将从指定键的缓存中获取值,并将其删除。pull 方法的实现:

    public function pull($key, $default = null)
    {
       $value = $this->get($key, $default);
    
       $this->forget($key) // returns a boolean;
    
       return $value;
    }

    上面的例子中,$this-> forget() 返回一个布尔值,所以要使我们的函数返回原始值,需要将其储存到临时变量 $value 中。以下是 tap() 的实现,不再需要临时变量:

    public function pull($key, $default = null)
    {
       return tap($this->get($key, $default), function ($value) use ($key) {
          $this->forget($key);
       });
    }

    恢复状态

    Eloquent 的 create 和 update 方法支持 ['timestamps' => false] 选项。如果这被实现成链式方法,结果的可读性会更好。

    // Method defined in App\Model that App\Message extends.
    public function keepingTimestamps(callable $callback)
    {
        try {
            $timestamps = $this->timestamps;
            $this->timestamps = false;
     
            return tap($this, $callback);
        } finally {
            $this->timestamps = $timestamps;
        }
    }

    现在 Message 模型可以链式使用以上的方法:

    request()->user()->latestMessage->keepingTimestamps(function ($message) {
        $message->markRead(); // updates a 'read_at' timestamp instead
    }); // returns the latestMessage

    如果你写的代码有 DB::transaction() 相同的模式,你可以在 Laravel 5.4 使用 tap() 帮助函数重写。

    Collection

    Laravel 5.4 中也可以在 Collection 类中使用 tap() 方法。你可以在任何地方使用,而不需要破坏链式。对于 Laravel 5.3 及更早的版本,你只需要复制粘贴五行代码的方法作为 Collection macro 到你项目的 AppServiceProvider@boot() 即可。

    这里有一个例子,用于 Laravel 网站支持英语和法语。取代月份的语言翻译文件,使用 Carbon 列出一年每个月份的 <option>。因此这个模型的修饰方法:

    public function monthOptions()
    {
        return collect(range(1, 12))
            ->keyByValue() // custom Collection macro
            ->tap(function () {
                if (App::getLocale() === 'fr') {
                    setlocale(LC_TIME, 'fr_CA');
                }
            })
            ->map(function ($month) {
                return sprintf('%02d - %s', $month,
                    Carbon::now()->month($month)->formatLocalized('%B'));
            })
            ->tap(function () {
                if (App::getLocale() === 'fr') {
                    setlocale(LC_TIME, '');
                }
            });
    }

    对于更多的语言支持,设置/恢复状态将提取到其他方法,使其更加可读。

    使用 Collection tap() 处理控制台命令进度条

    这是在集合中最典型的用例。你甚至可以在 handle() 处理过程中保持其方法链。

    public function handle()
    {
        Club::findOrFail($this->option('club'))
            ->members()
            ->subscribed()
            ->get()
            ->tap(function ($members) {
                $this->output->progressStart($members->count());
            })
            ->each(function ($member) {
                Mail::to($member)->queue(new Newsletter($member, $this->matchReport());
     
                $this->output->progressAdvance();
            })
            ->tap(function () {
                $this->output->progressFinish();
            });
    }
     
    public function matchReport()
    {
         return once(function () {
              return MatchReport::ofRound($this->option('round'))->firstOrFail();
         });
    }


沪ICP备19023445号-2号
友情链接