轻松理解laravel的Pipeline("管道"模式)

本文来自pilishen.com----原文连接; 欢迎来和pilishen一块儿学习php&Laravel;学习群:109256050php

该篇属于《Laravel底层核心技术实战揭秘》这一课程《laravel底层核心概念解析》这一章的扩展阅读。考虑到学员们的基础差别,为了不视频当中过于详细而连篇累牍,故将一些laravel底层实现相关的PHP知识点以文章形式呈现,供你们预习和随时查阅。laravel

基本上,使用laravel pipelines你能够将一个实例对象(object)在多个类之间传递,就像流水顺着管道依次流淌通常,最终呢,层层传递,你就获得了从头到尾一系列执行操做的“最终”结果。数据库

固然,laravel里pipeline(管道、通道)相关的,最直接的例子就是Middleware了。借助这种通道方式,Middleware能够很方便地层层“过滤”(filter)进入你程序中的request。json

下面是一个基本的Middleware例子:bootstrap

<?php
namespace App\Http\Middleware;
use Closure;
class TestMiddleware
{
    
    public function handle($request, Closure $next)
    {
        // 这里添加本身的逻辑
        return $next($request);
    }
}
复制代码

middleware就像是咱们的request请求流经的“管道”,这期间能够执行必要的操做,好比判断当前请求是一个http请求呢,仍是一个json请求呢,或者也能够检查一下用户的权限,或许这个时候你就会想到咱们laratrust(或Entrust)插件一系列经典的Middleware。bash

《Laravel底层核心技术实战揭秘》课程里,涉及到service provider的加载注册原理和源码解读的时候,咱们一块儿看过Illuminate\Foundation\Http\Kernel这个class,期间呢详细分析了sendRequestThroughRouter这个方法:app

protected function sendRequestThroughRouter($request)
{
    $this->app->instance('request', $request);
    Facade::clearResolvedInstance('request');
	// 视频里咱们重点分析了启动过程
    $this->bootstrap();
		
	// 下面的这个返回过程咱们没有详细展开
    return (new Pipeline($this->app))
                    ->send($request)
                    ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
						->then($this->dispatchToRouter());
}
复制代码

注意return后面的那段,看字面意思都很好理解:ide

一个new Pipeline发送了(send)request请求,经过了(through)咱们的Middleware,而后(then)提交给了路由。函数

例子:实现一个须要依次处理多个任务的类(class)逻辑

假设呢你在写一个论坛功能,用户呢能够建立话题、评论话题,可是呢,你的客户要求你实现一个能自动替换删除某些内容、符号的功能,数据处理了之后呢才能写入数据库,好比说具体的需求列表是这样的:post

  1. 删除那些没有href的空的连接
  2. 将一些敏感词汇替换成星号*
  3. 删掉用户提交可能危险的script tag

极可能最后呢,你须要实现下面的这个处理过程:

$pipes = [
    RemoveBadWords::class
    ReplaceLinkTags::class
    RemoveScriptTags::class
];
复制代码

咱们须要的是,将须要处理的内容依次传递到这三个class中,上一个class的执行结果要传给下一个class来继续处理,那么相似的需求,咱们就可使用pipeline来实现:

<?php

public function create(Request $request)
{
    $pipes = [
        RemoveBadWords::class,
        ReplaceLinkTags::clas,
        RemoveScriptTags::class
    ];
    $post = app(Pipeline::class)
        ->send($request->content)
        ->through($pipes)
        ->then(function ($content) {
            return Post::create(['content' => 'content']);
        });
    // return any type of response
}
复制代码

每个数据处理的class,都应该有一个handle方法来执行具体的逻辑,因此这个时候让它们都扩展或实现某个特定的interface比较好:

<?php
namespace App;

use Closure;

interface Pipe
{
    public function handle($content, Closure $next);
}
复制代码

而后呢假设咱们过滤敏感词的class就能够这样写:

<?php
namespace App;

use Closure;

class RemoveBadWords implements Pipe
{
    public function handle($content, Closure $next)
    {
        //具体的替换逻辑,更新掉$content
        return  $next($content);
    }
}
复制代码

这里handle方法接收两个参数,第一个是你要在管道中传递的对象(passable object),第二个呢是一个Closure,也便是匿名函数,它指代你管道中的下一步,当前这一步的逻辑执行完了,就能够把结果传给下一步。

你也能够不用handle这个方法名,但这个时候你须要经过via方法来指定自定义方法的名字:

app(Pipeline::class)
 ->send($content)
 ->through($pipes)
 ->via(‘customMethodName’) // <---- 在这儿指定
 ->then(function ($content) {
     return Post::create(['content' => $content]);
 });
复制代码

原文出处://medium.com/@jeffochoa/understanding-laravel-pipelines-a7191f75c351

相关文章
相关标签/搜索