Laravel过滤器模式怎么实现

wen PHP项目 5

Laravel过滤器模式实现全指南:从原理到实战的高效代码架构

目录导读


什么是过滤器模式?为什么要在Laravel中使用?

过滤器模式(Filter Pattern)是一种结构型设计模式,它允许你通过一系列可组合的过滤条件来筛选数据或请求,而无需修改现有业务逻辑,在Laravel生态中,这种模式常被用于请求参数验证数据查询条件组装中间件链式处理等场景。

Laravel过滤器模式怎么实现

使用过滤器模式的三大理由:

  1. 解耦核心逻辑:将过滤规则从控制器和模型中剥离,降低耦合度。
  2. 可扩展性:新增过滤条件无需修改原有代码,只需添加新过滤器类。
  3. 可测试性:每个过滤器独立可测,易于维护。

Laravel过滤器模式的核心实现原理

Laravel本身没有内置“过滤器设计模式”的抽象,但我们可以通过管道(Pipeline)策略模式自定义Service Provider来实现,最推荐的方式是结合面向接口编程管道模式,因为Laravel的Pipeline类天然支持链式调用。

基础架构三要素:

  1. 过滤器接口:定义统一的方法(如handleapply)。
  2. 具体过滤器:实现接口,包含具体的过滤逻辑。
  3. 过滤器管理者:负责按顺序执行所有过滤器。
// 定义过滤器接口
interface FilterInterface {
    public function handle($data, \Closure $next);
}
// 具体过滤器:IP白名单过滤
class IpFilter implements FilterInterface {
    public function handle($request, \Closure $next) {
        if (in_array($request->ip(), config('whitelist.ips'))) {
            return $next($request);
        }
        abort(403, 'IP not allowed');
    }
}
// 通过管道执行
$pipeline = new Pipeline(app());
$result = $pipeline
    ->send($request)
    ->through([new IpFilter(), new AuthFilter()])
    ->thenReturn();

实战:手写一个用户请求过滤器

假设我们需要对API请求进行多维过滤:只允许特定用户类型、过滤敏感参数、并对数据进行格式化,下面是完整实现步骤。

步骤1:创建过滤器基类

// app/Filters/BaseFilter.php
namespace App\Filters;
use Closure;
use Illuminate\Http\Request;
abstract class BaseFilter {
    abstract public function handle(Request $request, Closure $next);
}

步骤2:实现具体过滤器

// app/Filters/UserTypeFilter.php
class UserTypeFilter extends BaseFilter {
    public function handle(Request $request, Closure $next) {
        if ($request->user() && $request->user()->type !== 'admin') {
            throw new \Exception('仅管理员可访问');
        }
        return $next($request);
    }
}
// app/Filters/TrimStringsFilter.php
class TrimStringsFilter extends BaseFilter {
    public function handle(Request $request, Closure $next) {
        $input = array_map('trim', $request->all());
        $request->replace($input);
        return $next($request);
    }
}

步骤3:创建过滤器执行器

// app/Services/FilterManager.php
namespace App\Services;
use Illuminate\Pipeline\Pipeline;
class FilterManager {
    public function run(string $class, array $filters) {
        return app(Pipeline::class)
            ->send(new $class())
            ->through($filters)
            ->then(fn($content) => $content);
    }
}

步骤4:在控制器中调用

public function store(FilterManager $manager) {
    $filters = [
        new UserTypeFilter(),
        new TrimStringsFilter(),
    ];
    $request = $manager->run(Request::class, $filters);
    // 接下来使用处理后的$request
}

高级应用:多条件组合过滤与管道模式结合

查询条件动态组合(Eloquent模型过滤)

// app/Filters/QueryFilters/ProductFilter.php
namespace App\Filters\QueryFilters;
use App\Filters\BaseFilter;
use Illuminate\Database\Eloquent\Builder;
use Closure;
class PriceRangeFilter extends BaseFilter {
    public function handle(Builder $query, Closure $next) {
        if (request()->has('min_price')) {
            $query->where('price', '>=', request('min_price'));
        }
        if (request()->has('max_price')) {
            $query->where('price', '<=', request('max_price'));
        }
        return $next($query);
    }
}
// 在Repository中使用
class ProductRepository {
    public function getFilteredProducts(array $filters) {
        $query = Product::query();
        return app(Pipeline::class)
            ->send($query)
            ->through($filters)  // 传入过滤器数组
            ->then(fn($q) => $q->get());
    }
}

与Laravel中间件类比

  • 中间件:处理HTTP请求生命周期,全局或路由级。
  • 过滤器模式:更灵活,可用于任意数据流(请求、数据库结果、数组等)。

常见问题与性能优化

过滤器执行顺序如何控制?

通过数组顺序直接控制,或使用优先级值排序。

过滤器如何停止链式执行?

handle方法中直接返回结果(不调用$next)即可中断。

性能优化建议

  • 使用惰性加载:在过滤器内部延迟创建依赖。
  • 缓存过滤器实例:单例模式注册到容器。
  • 将无状态过滤器设为singleton
// 在AppServiceProvider中
$this->app->singleton(IpFilter::class);

问答环节

Q1:过滤器模式和Laravel的中间件有什么区别?
A:中间件专用于HTTP请求前后处理,是框架级别的特性;过滤器模式是设计模式实现,可以用于任意数据流(包括Eloquent查询、数组、表单请求),更通用,你可以将中间件视为一种特殊化的过滤器实现。

Q2:多个过滤器之间如何共享数据?
A:通过$next闭包传递参数,或在过滤器中直接修改共享对象(如Request实例),更优雅的方式是使用Illuminate\Support\Collection作为数据容器。

Q3:能否动态加载过滤器(比如从数据库读取规则)?
A:可以,将过滤器类名存储为配置项或数据库字段,通过app()->make($config['filter_class'])实例化,注意验证类名合法性以避免安全风险。

Q4:过滤器模式与Laravel的「FormRequest」验证冲突吗?
A:不冲突,FormRequest专注于输入验证,而过滤器模式可以处理更广泛的业务逻辑(如权限检查、数据转换、日志记录),建议:验证用FormRequest,复杂业务过滤用模式。


通过以上结构化的实现,你可以在Laravel项目中灵活应用过滤器模式,保持代码清晰、可维护,实际开发中,建议先从简单场景(如请求参数清洗)开始,逐步扩展到多维度数据过滤。好的架构不是设计出来的,而是演进出来的——过滤器模式恰好为演进提供了良好的扩展点。

抱歉,评论功能暂时关闭!