ServiceProvider & ServiceContainer[php]

服務容器:

Vito Chen
Vito Chen
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內容和方法,若傳入屬性即可被綁定至該物件。

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade