跳转到主要内容

什么是 Laravel Pennant

Laravel Pennant 是一个轻量、简洁的功能开关(Feature Flag)扩展包。功能开关可以让你分阶段发布新功能、进行 A/B 测试,或者补充主干开发流程。

什么是功能开关

借助功能开关,可以将代码部署与功能发布分离。代码可以先部署到生产环境,通过配置来打开或关闭功能。

安装

1

安装扩展包

通过 Composer 安装 Pennant。
2

发布配置文件与迁移

通过 vendor:publish Artisan 命令发布文件。
这会在 config/pennant.phpdatabase/migrations 中生成对应文件。
3

执行迁移

创建 Pennant 用来保存功能开关值的 features 表。

配置

config/pennant.php 中可以配置要使用的存储驱动,Pennant 支持两种。

定义功能

基于闭包的定义

功能通过 Feature Facade 的 define 方法定义,通常写在服务提供者的 boot 方法中。闭包会接收一个“作用域(scope)”参数(一般是已认证用户)。
上面这个功能的逻辑是:
  • 团队内部成员始终开启
  • 高流量客户始终关闭
  • 其余用户按 1% 的概率开启
当功能首次被检查时,闭包返回的结果会写入存储驱动,后续判断都直接使用已保存的值。
如果定义体只是返回 Lottery,可以省略闭包。

基于类的定义

Pennant 也支持基于类的功能定义。基于类时无需在服务提供者中注册。
生成的类位于 app/Features 目录,只需实现 resolve 方法。

自定义保存名

默认使用完全限定类名保存。可以通过 Name Attribute 自定义名字。

拦截判断(before 方法)

基于类的功能可以定义 before 方法。它会在读取存储值之前在内存中执行,若返回非 null 值就直接使用该值。
before 方法适合在出现 bug 时紧急关闭功能,或在指定时间点做灰度发布。

判断功能状态

Feature::active() / Feature::inactive()

active 方法可以判断功能是否启用。默认使用当前已认证用户作为作用域。
基于类的功能则传入类名。
其他常用方法:

条件执行(when / unless

when 方法只在功能启用时执行闭包。
unlesswhen 相反,在功能未启用时执行第一个闭包。

HasFeatures trait

User 模型上添加 HasFeatures trait 后,就可以直接从模型上检查功能。

Blade 指令

Blade 模板中可以使用 @feature 指令。

中间件

EnsureFeaturesAreActive 中间件可以为路由声明必须启用的功能。若未启用会返回 400 Bad Request
要自定义响应,使用 whenInactive 方法。

内存缓存

Pennant 会在同一请求内把功能结果缓存到内存中。即使多次判断同一个功能,也不会产生额外的数据库查询。 要手动清空缓存,使用 flushCache

作用域(Scope)

指定作用域

默认情况下作用域是已认证用户,可以通过 for 方法指定任意作用域。
按团队管理功能开关的示例:

自定义默认作用域

可以通过 Feature::resolveScopeUsing 修改默认作用域。
设置后不加 for 时会使用默认作用域。

Nullable 作用域

当作用域为 null(未认证路由、Artisan 命令等)时,如果功能定义不支持 null,会自动返回 false。若需要支持 null,请在定义中使用可空类型。

富功能值(Rich Feature Values)

功能不只可以返回布尔值。例如 A/B 测试中控制按钮颜色:
取值时使用 value 方法。
Blade 中可以基于值进行分支:
使用富值时,除 false 之外的所有值都视为启用。
将富值传入 when 时,第一个闭包会收到该值。

一次性获取多个功能

values 方法可以一次性获取多个功能的值。
all 方法返回已定义的所有功能的值。
若希望 all 的结果包含基于类的功能,在服务提供者中调用 discover
这样 app/Features 目录下的所有功能类都会被注册。

Eager Loading

在循环里检查功能可能带来性能问题。可以通过 load 提前一次性取值。
只加载未取过的值时使用 loadMissing

更新值

手动更新

activate / deactivate 用于打开或关闭功能。
若要让保存的值“被遗忘”,使用 forget。下次判断时会重新从定义计算。

批量更新

activateForEveryone / deactivateForEveryone 会一次性作用于存储中的所有作用域。

清除功能(purge)

当你把某功能从代码中移除或修改了定义时,可以从存储中清除对应值(purge)。
也可以通过 Artisan 命令 purge,非常适合部署流水线。

测试

重新定义功能

测试中可以通过 Feature::define 重新定义,控制返回值。
tab=Pest
tab=PHPUnit
基于类的功能同样如此。
tab=Pest
tab=PHPUnit

测试用存储配置

可以在 phpunit.xml 中通过环境变量指定测试用存储。

自定义驱动

如果已有驱动不能满足需求,可以自定义驱动。实现 Laravel\Pennant\Contracts\Driver 接口即可。
在服务提供者的 boot 方法中通过 extend 注册。
注册后即可在 config/pennant.php 中使用。

小结

下一步

调试与错误处理

了解应用异常处理与上报机制。

Laravel Pulse

引入应用性能监控仪表盘。
最后修改于 2026年7月18日