🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
我们先来看一段代码 ~~~ class Foo{} Route::get('/foo',function(Foo $foo){ dd($foo); }); ~~~ 上面代码会执行$foo=new Foo();这是laravel帮我们实现的!上面也是形参的依赖注入 我们再来看这一段代码 ~~~ class Bar{} class Foo{} App::bind('Foo',function(){ dd('called here'); }); Route::get('bind',function(Foo $foo){ dd($foo); }); ~~~ 浏览这个路由会出现called here原因是在于,laravel会先寻找你有没有绑定这个类,没有的话会帮你new这个类,类里面的依赖也会帮你new # 绑定 绑定操作一般在ServiceProviders中的register方法中,最基本的绑定是容器的bind方法,它接受一个类的别名或者全名和一个闭包来获取实例: ~~~ $this->app->bind('XblogConfig', function ($app) { return new MapRepository(); }); ~~~ 还有一个singleton方法,和bind写法没什么区别。你也可以绑定一个已经存在的对象到容器中,上文中提到的request实例就是通过这种方法绑定到容器的:$this->app->instance('request', $request);。绑定之后,我们可以通过一下几种方式来获取绑定实例: ~~~ 1. app('XblogConfig'); 2. app()->make('XblogConfig'); 3. app()['XblogConfig']; 4. resolve('XblogConfig'); ~~~ 以上四种方法均会返回获得MapRepository的实例,唯一的区别是,在一次请求的生命周期中,bind方法的闭包会在每一次调用以上四种方法时执行,singleton方法的闭包只会执行一次。在使用中,如果每一个类要获的不同的实例,或者需要“个性化”的实例时,这时我们需要用bind方法以免这次的使用对下次的使用造成影响;如果实例化一个类比较耗时或者类的方法不依赖该生成的上下文,那么我们可以使用singleton方法绑定。singleton方法绑定的好处就是,如果在一次请求中我们多次使用某个类,那么只生成该类的一个实例将节省时间和空间。 你也可以绑定接口与实现,例如: ~~~ $app->singleton( Illuminate\Contracts\Http\Kernel::class, App\Http\Kernel::class ); ~~~ 上文讲述的Laravel的生命周期的第二步,Laravel默认(在bootstrap\app.php文件中)绑定了Illuminate\Contracts\Http\Kernel,Illuminate\Contracts\Console\Kernel,Illuminate\Contracts\Debug\ExceptionHandler接口的实现类,这些是实现类框架的默认自带的。但是你仍然可以自己去实现。 还有一种上下文绑定,就是相同的接口,在不同的类中可以自动获取不同的实现,例如: ~~~ $this->app->when(PhotoController::class) ->needs(Filesystem::class) ->give(function () { return Storage::disk('local'); }); $this->app->when([VideoController::class, UploadController::class]) ->needs(Filesystem::class) ->give(function () { return Storage::disk('s3'); }); ~~~ 上述表明,同样的接口Filesystem,使用依赖注入时,在PhotoController中获取的是local存储而在VideoController中获取的是s3存储。 <br> 平常使用 ~~~ app()->make(自己定义的完全命名空间+类); ~~~ 他就能解析出来,即使你定义的类依赖其他你定义的类,没关系,会递归反射解决依赖的,但是如果存在循环依赖的话,会直接爆栈内存,laravel没有做循环依赖的检查