laravel 5.5 的宏功能并非新增,而是显式暴露自5.0已存在的macroable机制;其生效前提是类使用macroable trait,执行依赖__call()拦截与静态宏表,注册必须在boot()中完成,否则失效无提示。

Macroable trait 是宏生效的唯一前提
一个类能被加宏,不取决于 Laravel 版本号,而只看它是否用了 Illuminate\Support\Traits\Macroable。Laravel 5.5 中的 Collection、Builder、Request、Response 等类都明确 use 了这个 trait,所以才能调用 macro()。
如果你试图给没实现该 trait 的类(比如自定义的普通 Model 类)直接调用 macro(),会报 Fatal error: Call to undefined method ::macro()。
__call() 拦截 + 静态宏表驱动整个流程
宏的执行完全依赖 PHP 的魔术方法:
• 当你调用 $collection->countBy('status'),而该方法不存在时,__call() 被触发
• 它查 static::$macros 数组,找到 'countBy' 对应的闭包
• 用 $macro->bindTo($this, static::class) 绑定当前实例,确保闭包里 $this 指向正确的对象
• 最后把参数传进去执行
这个链路在 Laravel 5.5 中没有改动,只是文档和示例变得更丰富,让开发者意识到“原来这些类都能这样扩”。
注册时机错 = 宏失效,且无提示
Laravel 5.5 的宏表在类**首次实例化后就冻结**,这是最容易踩坑的地方:
• collect([]) 第一次执行 → Collection 类加载 → 宏表锁定
• 此后再调 Collection::macro('xxx', ...) 不报错,但闭包根本没挂上
• 后续调用 ->xxx() 直接抛 BadMethodCallException
• 常见错误位置:写在 AppServiceProvider::register()、控制器方法里、或配置文件中
必须且只能写在 AppServiceProvider::boot(),因为此时框架已启动、服务已注册、但核心类尚未被业务代码提前触发实例化。
闭包里的 $this 不是全局上下文,而是当前实例
写宏时误用 $request 或 app() 是典型错误:
• Collection::macro('isAdmin', function () { return $this->input('role') === 'admin'; }) → 错!$this 是 Collection,没有 input() 方法
• Request::macro('isAdmin', function () { return $this->input('role') === 'admin'; }) → 对,$this 是 Request 实例,可直接调 input()、route()、ip()
• Response::macro('success', function ($data) { return response()->json($data); }) → $this 是 ResponseFactory,不能访问请求数据,要用 request() 显式取











