自定义Laravel包中如何使用构造函数依赖注入?
在创建自定义Laravel包时,能否通过构造函数依赖注入访问其他类?
背景
我正在开发一个Laravel包,已创建本地代码仓库,并在Laravel项目的composer.json中进行链接配置:
"repositories": { "local": { "type": "path", "url": "../packages/blog" } }
包中的composer.json配置如下:
{ "name": "namespace/blog", "description": "Quick blog", "type": "library", "autoload": { "psr-4": { "Namespace\\Blog\\": "src/" } }, "authors": [ { "name": "Bob Blog", "email": "bob@blog.com" } ], "extra": { "laravel": { "providers": [ "Namespace\\Blog\\BlogServiceProvider" ] } }, "require": {} }
我创建了两个简单类:Reader.php:
<?php namespace Namespace\Blog; class Reader { public function loadFiles() { dd('show me'); } }
Blog类中尝试注入Reader类:
namespace Namespace\Blog; class Blog { private $reader; /** * 请在此处注入Reader实例! */ public function __construct(Reader $reader) { $this->reader = $reader; } public function list() { $this->reader->loadFiles(); } }
在Laravel应用中调用包时:
$blog = new \Namespace\Blog();
出现错误:
Too few arguments to function Namespace\Blog\Blog::__construct(), 0 passed
疑问:是否需要将待注入的类注册到服务容器?我原以为Laravel会自动处理具体类的注入。
当然可以通过构造函数依赖注入访问其他类,但你当前的问题出在没有通过Laravel服务容器来解析Blog类。
你直接用new \Namespace\Blog()实例化类时,PHP会直接调用构造函数,不会经过Laravel的服务容器,自然不会帮你自动注入依赖。Laravel的自动注入机制只在容器解析类时生效,比如:
- 通过
app()->make(\Namespace\Blog\Blog::class)获取实例 - 从控制器方法的参数中自动注入
- 在服务容器中绑定类后,通过依赖注入获取
针对你的包,有两种常见解决方案:
方案1:通过服务容器解析实例
在Laravel应用中调用时,不要直接new,而是让容器帮你创建实例:
$blog = app(\Namespace\Blog\Blog::class); $blog->list();
这种方式下,Laravel会自动解析Blog的构造函数依赖Reader——因为Reader是具体类,不需要额外注册到容器,Laravel能自动实例化它。
方案2:在包的服务提供者中绑定类
如果你希望更灵活(比如后续可能把Reader替换为接口实现),可以在包的BlogServiceProvider中绑定类:
<?php namespace Namespace\Blog; use Illuminate\Support\ServiceProvider; class BlogServiceProvider extends ServiceProvider { public function register() { // 绑定Blog类,容器会自动处理其依赖 $this->app->bind(Blog::class, function ($app) { return new Blog($app->make(Reader::class)); }); // 如果是简单的具体类,也可以直接用singleton或者不需要手动绑定,容器会自动解析 // $this->app->singleton(Reader::class); } }
之后无论是通过app()->make(Blog::class)还是在其他容器管理的类中注入Blog,都会自动处理依赖。
另外要注意:确保你的包的服务提供者已经被Laravel加载——你已经在composer.json的extra.laravel.providers中配置了,只要包被正确安装,Laravel会自动注册这个服务提供者。
总结:
- Laravel的自动依赖注入只在服务容器解析类时生效,直接
new类不会触发 - 具体类不需要手动注册到容器,容器能自动解析其依赖
- 如果需要更复杂的实例逻辑,或者后续要做接口解耦,就在服务提供者中绑定
内容的提问来源于stack exchange,提问作者karatecode

