Laravel 中的服务容器、服务、服务提供者
服务容器我也还不太会,只是知道该怎么使用,所以没有进行讲解,这里的重点就是如何注册自定义的服务提供者以及设置调用时间。
服务容器/服务/服务提供者
服务容器
你了解了这个之后就知道这个玩意有多强大,这里推荐一篇蛮好的文章:Ioc模式介绍,去看的时候提一点小建议:
- Ioc模式是如何解决依赖自动注入的
- Ioc模式比起一般的手工添加有什么优点,他又存在哪些缺点
具体是如何实现的,那么可以直接看那位大哥的代码或者我下面抄来的例子。
基础代码
假设情景:
一个Traveller去西藏旅行(visitTibet),他可以选择朝圣(leg,用脚徒步走过去),或者自驾游(car),或者搭乘火车(train)。
下面开始编写上面情景的代码:
基础类
<?php
interface Visit{
public function go();
}
class Leg implememts Visit{
public function go(){
echo "朝圣";
}
}
class Car implements Visit{
public function go(){
echo "自驾游";
}
}
class Train implements Visit{
public function go(){
echo "乘火车";
}
}
上面定义了几个基础类,下面定义旅行者类:
<?php
class Traveller{
protected $trafficTool;
public function __construct(Visit $traficTool){
$this->trafficTool=$traficTool;
}
public function visitTibet(){
$this->trafficTool->go();
}
}
这里不再赘述如果需要实例化多个Traveller时需要多麻烦之类的了,这里直接介绍Ioc模式
。
Ioc容器类
在开始看下面的代码前,先看一下其作用结果,这样可以减少你的疑惑:
$app=new Container();
$app->bind('Visit','Train');
$app->bind("traveller","Traveller");
$traveller=$app->make('traveller');
$traveller->visitTibet();
其中只要调用bind
就能实现依赖类的自动关联,之后只要使用make
函数就能实现类的自动实例化,并且依赖被自动处理了。
class Container{
protected $bindings=[];
public function bind($abstract,$concrete=null,$shared=false){
if(!$concrete instanceof Closure){
$concrete=$this->getClosure($abstract,$concrete);
}
$this->bindings[$abstract]=compact('concrete','shared');
}
public function getClosure($abstract,$concrete){
return function($c) use ($abstract,$concrete){
$method=($abstract==$concrete) ? "build":"make";
return $c->$method($concrete);
};
}
public function make($abstract){
$concrete=$this->getConcrete($abstract);
if($this->isBuildable($concrete,$abstract)){
$object=$this->build($concrete);
}else{
$object=$this->make($concrete);
}
return $object;
}
public function getConcrete($abstract){
if(!isset($this->bindings[$abstract])){
return $abstract;
}
return $this->bindings[$abstract]['concrete'];
}
public function isBuildable($concrete,$abstract){
return $concrete===$abstract || $concrete instanceof Closure;
}
public function build($concrete){
if($concrete instanceof Closure){
return $concrete($this);
}
$reflector=new ReflectionClass($concrete);
if(!$reflector->isInstantiable()){
echo "<span style='color: red;font-size: large;font-weight: bolder'>你个傻屌,这个类无法被实例化!!!</span>";
}
$constructor=$reflector->getConstructor();
if(is_null($constructor)){
return new $constructor;
}
$dependencies=$constructor->getParameters();
$instances=$this->getDependencies($dependencies);
return $reflector->newInstanceArgs($instances);
}
public function getDependencies($parameters){
$dependencies=[];
foreach ($parameters as $parameter){
$dependency=$parameter->getClass();
if(is_null($dependency)){
$dependencies[]=null;
}else{
$dependencies[]=$this->resolveClass($dependency);
}
}
return (array) $dependencies;
}
public function resolveClass(ReflectionParameter $parameter){
return $this->make($parameter);
}
}
服务
所谓服务其实就是上面绑定到bind
中的类,至于这些类有什么作用,暂时还没有遇到,这里可以暂时举一个简单的例子,就在public/index.php
文件中添加下面的内容:
容器类:App调用方式
这里先列举几种调用app
类的方法:
//方式1
$app = require_once __DIR__.'/../bootstrap/app.php';
//方式2
$app=$this->app;
//方式3
app();
//方式4:
\App::
绑定服务方式
//待绑定的类
class GeneralService {}
class GeneralService2{}
class GeneralService3{}
class GeneralService4{}
interface GeneralService5 { }
class GeneralService6 implements GeneralService5{}
//绑定服务方式1
$app->bind(GeneralService::class,function($app){
return new GeneralService();
});
//绑定服务方式2
$app->singleton(GeneralService2::class,function ($app){
return new GeneralService2();
});
//绑定服务方式3
$instance=new GeneralService3();
$app->instance('GeneralService3',$instance);
//绑定服务方式4
$app->bind(GeneralService4::class,GeneralService4::class);
//绑定服务方式5
$app->bind(GeneralService5::class,GeneralService6::class);
服务提供者
命令行生成服务提供者
创建服务提供者:php artisan make:provider ProviderName
服务提供者基础模板
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ProviderName extends ServiceProvider
{
/**
* Bootstrap any application services.
* 这个函数在register之后运行
* @return void
*/
public function boot()
{
//
}
/**
* Register any application services.
* 该函数会在该服务提供者被注册时执行,该服务提供者何时运行看情况,注意,该函数不能向其中传递任何参数,因为调用时是没有传递参数的,
* 所以即使要传递参数也要设置默认值的形式
* @return void
*/
public function register()
{
//
}
}
关于为什么先调用register
,之后再调用boot
,可以看这篇文章:Laravel服务容器启动过程。
所以在Laravel
启动后已经默认启动了一些服务提供者,我们定义在/config/app.php
中的providers
配置项,也会在之后被加载,所以如果我们要自定义服务提供者,那么只需要将新建的服务提供者添加到该配置文件中。
设置服务提供者启动方式
如果上面的ProviderName
服务提供者代码直接在config/app.php
中直接注册的话,那么随着系统启动,该服务提供者也会自动调用,但是当我们想要这样设置时:当某一具体服务被调用时,该服务提供者被调用,则可以修改服务提供者:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ProviderName extends ServiceProvider
{
//第一步,将 $defer 属性设置为 true
protected $defer=true;
public function boot()
{
//
}
public function register()
{
//第二步 不一定需要,但是当你下面需要额外的依赖时,就可以在这里绑定进服务容器中
//$this->app->bind(NameSpace/ClassName::class)
}
// 第三步 设置何时调用该服务提供者,即注册何种服务时实例化该服务提供者
public function provides(){
return [ClassName1::class,ClassName2::class];
}
}
更多推荐
所有评论(0)