环境
Laravel 5.4
前言
下面我们以“音乐播放器”为例子,介绍如何在Laravel中创建一个Service Provider,并且为这个Provider创建一个门面(Facade)。
创建自定义Service Provider
1)既然是音乐播放器,那肯定会有播放功能,因此先定义一个音乐播放器的接口,接口有一个play方法,文件路径app/Helpers/Contracts/MusicPlayerContract.php:
namespace App\Helpers\Contracts;
interface MusicPlayerContract
{
public function play();
}
2)然后创建一个QQ音乐播放器类,并实现上述接口,文件路径app/Helpers/QQPlayer.php:
namespace App\Helpers;
use App\Helpers\Contracts\MusicPlayerContract;
class QQPlayer implements MusicPlayerContract
{
public function play()
{
echo '开始播放QQ音乐';
}
}
再创建一个酷狗音乐播放器类:
namespace App\Helpers;
use App\Helpers\Contracts\MusicPlayerContract;
class KugouPlayer implements MusicPlayerContract
{
public function play()
{
echo '开始播放酷狗音乐';
}
}
3)然后我们创建一个Service Provider,将这个音乐播放服务以单例的方式绑定到Laravel的容器中,绑定的service_id为player,文件路径app/Providers/MusicPlayerServiceProvider.php:
namespace App\Providers;
use App\Helpers\Contracts\MusicPlayerContract;
use App\Helpers\QQPlayer;
use Illuminate\Support\ServiceProvider;
class MusicPlayerServiceProvider extends ServiceProvider
{
protected $defer = true; // 延迟加载
/**
* Register the application services.
*
* @return void
*/
public function register()
{
$this->app->singleton('player', function() {
return new QQPlayer();
});
// 因为有两个播放器,将接口和播放器绑定起来,这样依赖注入接口时,容器就会知道应该实例化哪个播放器
$this->app->bind(MusicPlayerContract::class, QQPlayer::class);
}
/**
* 延迟加载时必须定义此方法
* @return string[]
*/
public function provides()
{
return ['player'];
}
}
4)修改config/app.php配置文件,将上面的Provider添加到providers数组里:
'providers' => [
/*
* 省略的其它Service Provider...
*/
App\Providers\MusicPlayerServiceProvider::class,
],
5)至此,Service Provider已经创建完毕。在Controller中我们可以通过容器的make
方法、或resolve
辅助函数、或者依赖注入来调用音乐播放服务:
namespace App\Http\Controllers;
use App\Helpers\Contracts\MusicPlayerContract;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Facades\App;
class Controller extends BaseController
{
// 普通模式
public function test()
{
$service = App::make('player'); // 方式一
//$service = resolve('player'); // 方式二
$service->play();
}
// 依赖注入模式
public function test2(MusicPlayerContract $player)
{
$player->play();
}
}
创建Facade
上面我们创建的Service Provider,每次调用都需要通过容器的make
方法,或者resolve
辅助函数来获取服务对象,不是很方便,我们可以通过创建一个门面(Facade)类来解决这个问题。
1)创建一个Player门面类,文件路径app/Facades/Player.php:
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class Player extends Facade
{
protected static function getFacadeAccessor() {
return 'player';
}
}
在门面类中,需要重写父类的getFacadeAccessor
方法,在方法中需返回Service Provider与Laravel容器之间绑定的service_id,在此例子中是player。
2)然后我们就可以通过Facade的静态调用接口直接使用音乐播放服务了:
namespace App\Http\Controllers;
use Illuminate\Routing\Controller as BaseController;
use App\Facades\Player; // 导入Facade类
class Controller extends BaseController
{
public function test()
{
Player::play(); // 直接静态调用,无需实例化对象
}
}
3)如上面代码所示,在使用Facade类的时候,需要先通过use
关键字把Facade类导入进来。如果我们把Facade类添加到config/app.php配置文件中的aliases数组中,就可以把导入的步骤也省了:
'aliases' => [
/* 省略的其它别名... */
'Player' => App\Facades\Player::class,
],
4)配置好alias别名后的调用示例,无需再导入Facade类:
namespace App\Http\Controllers;
use Illuminate\Routing\Controller as BaseController;
class Controller extends BaseController
{
public function test()
{
\Player::play(); // 注意在Player前有一个 \ 反斜杠
}
}