ServiceProvider & ServiceContainer[php]
服務容器:
Jul 27, 2017 · 7 min read
一般容器可以放置變數、數值,而服務容器可放置高級功能提供取用
IoC容器:
Laravel 核心就是一個IoC容器,整個容器可供一系列服務。
接下來解釋何謂IoC(控制反轉) 和 DI(依賴注入)。
For example:
欲產生一個超人的類別,並賦予基本能力:
class Superman {}該類別的屬性描述:
class Power {
protected $ability;
protected $range;
public function __construct($ability, $range)
{
$this->ability = $ability;
$this->range = $range;
}
}創建類別時並賦予能力:
class Superman
{
protected $power;
public function __construct()
{
$this->power = new Power(999, 100);
}
}以上第一個簡易的類別已經創建。
但遇到以下狀況:
原本的超人技能需增加
class Flight
{
protected $speed;
protected $holdtime;
public function __construct($speed, $holdtime) {}
}
class Force
{
protected $force;
public function __construct($force) {}
}
class Shot
{
protected $atk;
protected $range;
protected $limit;
public function __construct($atk, $range, $limit) {}
}若該屬性修改時創建類別的內容也要修改:
class Superman
{
protected $power;
public function __construct()
{
$this->power = new Fight(9, 100);
$this->power = array(
new Force(45),
new Shot(99, 50, 2)
);
}
}以上範例就是所謂的依賴,超人類別依賴能力屬性,導致修改屬性後類別內容也要跟著修改。
工廠模式,依賴轉移:
class SuperModuleFactory
{
public function makeModule($moduleName, $options)
{
switch ($moduleName) {
case 'Fight':return new Fight($options[0], $options[1]);
case 'Force':return new Force($options[0]);
case 'Shot':return new Shot($options[0], $options[1], $options[2]);
}
}
}上個例子要初始化多個屬性,目前只要初始化工廠即可。
class Superman
{
protected $power;
public function __construct(array $modules)
{
$factory = new SuperModuleFactory;
foreach ($modules as $moduleName => $moduleOptions) {
$this->power[] = $factory->makeModule($moduleName, $moduleOptions);
}
}
}
$superman = new Superman([
'Fight' => [9, 100],
'Shot' => [99, 50, 2]
]);但若有多個屬性要新增,還是要修改工廠內容
class SuperModuleFactory
{
public function makeModule($moduleName, $options)
{
switch ($moduleName) {
case 'Fight': return new Fight($options[0], $options[1]);
case 'Force': return new Force($options[0]);
case 'Shot': return new Shot($options[0], $options[1], $options[2]);
// case 'more': .......
// case 'and more': .......
// case 'and more': .......
// case 'oh no! its too many!': .......
}
}
}依賴注入:
工廠模式升級 — IoC容器:
class Container
{
protected $binds;
protected $instances;
public function bind($abstract, $concrete)
{
if ($concrete instanceof Closure) {
$this->binds[$abstract] = $concrete;
} else {
$this->instances[$abstract] = $concrete;
}
}
public function make($abstract, $parameters = [])
{
if (isset($this->instances[$abstract])) {
return $this->instances[$abstract];
}
array_unshift($parameters, $this);
return call_user_func_array($this->binds[$abstract], $parameters);
}
}使用方法:
// 創建一个容器(稱超级工廠)
$container = new Container;
// 向 超级工廠 加 超人 的屬性脚本
$container->bind('superman', function($container, $moduleName) {
return new Superman($container->make($moduleName));
});
// 向 超级工廠 加 超能力模组 的屬性脚本
$container->bind('xpower', function($container) {
return new XPower;
});
// 同上
$container->bind('ultrabomb', function($container) {
return new UltraBomb;
});
// 開始創建
$superman_1 = $container->make('superman', ['xpower']);
$superman_2 = $container->make('superman', ['ultrabomb']);
$superman_3 = $container->make('superman', ['xpower']);
// ...以上若要新增屬性只要加屬性脚本即可,不需重新修改工廠內容。
結論: 但在Laravel中,我們如何實作!?
A:
1.到config\app.php->新增我們自訂的服務提供者。
2.到App\ Providers裡面->新增自訂的服務提供者也必須註冊 和 綁定功能。
3.到App\ Http\Controllers裡面->定義controller內容和方法,若傳入屬性即可被綁定至該物件。
