Laravel 服务容器和提供器
看到laravel手册的服务容器和提供器模块,概念有些模糊,网上搜索+动手实践了一番,记录理解。
laravel框架默认加载了很多的服务,一个服务就是一个类,比如Auth,Cache,Route等等。如果想自定义一个服务怎么办,很简单,自己创建一个类然后再绑定就行。服务容器和服务提供器是没有直接关系的,一般都是按照什么提供器就提供什么服务的规则来命名两者,但是你创建一个 火车serviceprovider, 然后再这个火车serviceprovider里绑定汽车类,那么火车serviceprovider提供的就是汽车对象,虽然用起来很尴尬,但你自己定义的你自己肯定会用的,别人估计是哭着用完的。
自定义的功能类所具有的功能如果需要规范点,那就先写个接口,比如Cache类,需要拥有get,set方法等,写个接口加以规范,以后用的时候也只需要调用实现了这个接口的类就行,不写接口也无所谓。
1、创建接口类,接口类的名字随便起,但是最好还是规范点,自己看着也舒服
创建 app\Contract\SktContract.php 接口类
namespace App\Contract;
interface SktContract
{
//展示队伍队员名单
public function list_team($team_name);
}
2、接下来按照这个接口来实现你的功能类
创建 app\Service\SktService.php
namespace App\Service;
use App\Contract\SktContract;
class SktService implements SktContract
{
public $name = null;
//展示队伍队员名单
public function list_team($team_name)
{
echo $team_name."的队员名单是Faker-bengi";
}
}
3、既然功能类写好了,那就要把他装在服务提供器中,到时候别人拿着你的服务提供器,就能获得实例化后的功能类对象了。
创建app\Providers\SktServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Service\SktService;
class SktServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* @return void
*/
public function register()
{
//使用singleton绑定单例
$this->app->singleton('skt',function(){
return new SktService();
});
//使用bind绑定接口
$this->app->bind('App\Contracts\SktContract',function(){
return new SktService();
});
}
}
这了绑定了两次,一次用singleton绑定的,一次用bind方法绑定的,区别是singleton绑定的是单例,继续往下看就知道区别了。
4、既然服务提供器也准备好了,那就把提供器加到框架的加载列表中,之后就可以在控制器中使用啦。
config/app.php在providers键名对应的数组中的最后,加入这行
App\Providers\SktServiceProvider::class,
5、接下来我们在控制器中使用我们刚刚自定义的服务
public function index()
{
$fooService1 = app()->make('App\Contracts\SktContract'); //这里产生的不是单例,这里用bind方法绑定的
$fooService2 = app()->make('App\Contracts\SktContract');
$fooService3 = app()->make('skt'); //这里产生的是单例,666,因为这里skt是用singleton绑定的
$fooService4 = app()->make('skt'); //这里产生的是单例,666
$fooService1->name='111';
$fooService2->name='222';
$fooService3->name='333';
$fooService4->name='444';
$fooService1->list_team('LOL-ssb'); //LOL-ssb的队员名单是Faker-bengi
var_dump($fooService1); //111
var_dump($fooService2); //222
var_dump($fooService3); //444
var_dump($fooService4); //444
}
通过app()->make('提供器中绑定时的键名');来获取功能类对象,用bing方法绑定的,获取出来的都是新对象,用singleton绑定的,获取的是单例。
6、那么问题来了,觉得这样调用还是很麻烦,能不能再简化调用?可以~ laravel有个facade功能。接下来我们创建一个文件:/vendor/laravel/framework/src/Illuminate/Support/Facades/Skt.php
namespace Illuminate\Support\Facades;
use Illuminate\Contracts\Console\Kernel as ConsoleKernelContract;
/**
* @method static bool list_team() //加上这行注释是为了让php_storm编辑器能够追踪函数
* Class Skt
* @package Illuminate\Support\Facades
*/
class Skt extends Facade //类名随便起,但是为了规范还是和功能类为主也叫Skt吧(功能类是叫SktService)
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor
{
return 'skt'; //这里一定要return一个绑定的键名,代表你接下来会获得那个键名绑定的对象
}
}
上面这个类主要是getFacadeAccessor方法返回的字符串要和你绑定时候的键名对应上,这里返回的是skt,之前在服务提供器中,不是有一句
$this->app->singleton('skt',function(){ //注意,这里的键名是skt
return new SktService();
});
吗,那么返回的就是这个return new SktService();对象。
7、好了,Facades文件也写完了,接下来我们回到控制器中,把调用功能类的代码直接改为以下代码
use Illuminate\Support\Facades\Skt; //这里要引入facades
class Test extends Controller
{
public function test()
{
Skt::list_team('LOL-ssb');
}
}
这里引入了 Illuminate\Support\Facades\Skt;获得了一个叫做Skt的类,但是不好意思,这个类和你的功能类SktService只是名字有点像,但是完全没有关系,起作用的是这个Skt类的getFacadeAccessor方法return了一个'skt'字符串,然后框架内部获取到这个'skt‘字符串之后,又根据这个'skt'字符串为键名,找到了之前通过singleton方法绑定的对象,那个对象才是真正的功能类。Skt::list_team()调用的实际上是SktService类的list_team()方法
总结:
接口类SktContract、功能类SktService、服务提供器SktServiceProvider(将功能类在里面绑定好)、将服务提供器加入到框架加载列表config/app.php、创建facades文件Skt(关键是renturn一个绑定时的键名)
实际上想要偷懒的话大可不必这么麻烦,创建一个SktService.php功能类,然后再框架原有的AppServiceProvider里面的register方法进行绑定也行,而且AppServiceProvider默认就在框架的加载列表中了,直接用就行,不过facades文件还是要自己创建。这样做的好处是省事,但是一旦各种各样的功能都在AppServiceProvider类中进行绑定的话,就会很乱,不符合单一功能原则,最好还是一个功能类就创建一个服务提供器。不过要想引入功能类大可不必这么麻烦呢,直接用trait,哪里想用就use进来就行了,省事。
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: