make() 是 laravel 6 服务容器获取实例的核心方法,先查缓存、再查绑定、最后反射解析依赖并创建对象;bind() 每次新建,singleton() 复用单例,闭包绑定可自定义逻辑。

在 Laravel 6 中,make() 是服务容器获取类实例的最常用入口。它不是简单地 new 一个对象,而是自动处理依赖、缓存、绑定规则和上下文逻辑的一整套机制。理解它怎么工作,才能写出可测试、易维护、符合 Laravel 设计哲学的代码。
make 的基本行为:先查缓存,再解析依赖
调用 app()->make(MyService::class) 时,容器会按顺序做这几件事:
- 检查
$instances数组里是否已有该抽象(如MyService::class)的单例实例,有则直接返回 - 查绑定表(
$bindings),看有没有显式bind()或singleton()规则;有则按规则执行(比如执行闭包、返回绑定的具体类) - 若无绑定,且抽象名对应一个真实类,则用反射(
ReflectionClass)读取其构造函数参数 - 对每个带类型提示的参数(如
LoggerInterface $logger),递归调用make()解析其实例 - 最后用
new $concrete($resolvedDeps)创建对象,并根据是否为单例决定是否写入$instances
三种常见绑定方式对 make 的影响
绑定方式直接决定 make() 每次调用返回的是新实例还是旧引用:
-
bind():每次调用都新建 —— 即使你绑定了一个类,
app()->make(Service::class)每次都会 new 一次 -
singleton():首次创建后永久复用 —— 第二次起直接从
$instances返回,适合数据库连接、缓存管理器等 -
闭包绑定:按需执行逻辑 —— 如
$app->bind(Client::class, fn($app) => new Client($app['config']->get('http.timeout'))),闭包内可调用$app->make()获取其他服务
实操中容易出错的几个点
很多“Target [X] is not instantiable”错误,其实就卡在 make 的解析链上:
- 接口没绑定实现类:比如构造函数写了
PaymentGateway $gateway,但没在AppServiceProvider::register()里bind(PaymentGateway::class, StripeGateway::class) - 类未自动加载:确保命名空间正确、文件路径符合 PSR-4,否则反射失败直接报错
- 构造函数含标量参数(如
string $prefix):容器无法自动猜出值,必须用闭包绑定或make($abstract, ['prefix' => 'v1'])显式传参 - 用了字符串形式绑定(如
bind('logger', Logger::class)):Laravel 6 不支持字符串抽象的自动解析,必须用::class常量
调试技巧:快速验证 make 是否正常
别只靠运行时报错排查,开发期可用这些方法确认流程:
- 进 Tinker:
php artisan tinker→app()->make(App\Services\SomeService::class),看能否成功返回实例 - 临时加日志:在
Illuminate\Container\Container::resolve()方法开头打点(不建议改 vendor,可用 Xdebug 断点跟踪) - 检查绑定状态:
app()->isBound(MyService::class)和app()->getBindings()可查看当前注册了哪些规则











