概念
嚮應用程式註冊服務提供者
服務容器中的變化
$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
);
$app->register(new Illuminate\Events\EventServiceProvider($app));
//$app->register('Illuminate\Events\EventServiceProvider');
dd($app);
列印後
影響的屬性有:
所有已註冊的服務提供商protected $serviceProviders = [];
載入的服務提供者的名稱protected $loadedProviders = [];
可能會影響的屬性有:
容器的繫結protected $bindings = [];
等
原始碼
下方每個程式碼塊,只解釋一行程式碼。
第一行
/**
* 嚮應用程式註冊服務提供者。返回provider例項。
*/
public function register($provider, $options = [], $force = false)
{
/*
* 如果已經註冊了並且非強制註冊,則返回例項
*
* -->假設我們已經註冊過了
*/
if (($registered = $this->getProvider($provider)) && ! $force) {
return $registered;
}
...
}
/*
* 獲取註冊的服務提供者例項(如果它存在的話)
*
* 此時 $provider = new Illuminate\Events\EventServiceProvider($app);
* 或 'Illuminate\Events\EventServiceProvider'
*
* return EventServiceProvider {#4 ▶}
*/
public function getProvider($provider)
{
//array_values():只提取陣列中的鍵值,忽略鍵名。
return array_values($this->getProviders($provider))[0] ?? null;
}
/*
* 從serviceProviders屬性中查詢是該例項是否存在
*
* return array
*/
public function getProviders($provider)
{
// get_class():php內建函式獲得類名
// 此時 $name = 'Illuminate\Events\EventServiceProvider'
$name = is_string($provider) ? $provider : get_class($provider);
return Arr::where($this->serviceProviders, function ($value) use ($name) {
return $value instanceof $name;
});
}
/*
* 使用給定的回撥篩選陣列
*
* 此時$array = array( EventServiceProvider {#4 ▶} )
*
* return array( 0 => EventServiceProvider {#4 ▶} )
*/
class Arr{
public static function where($array, callable $callback)
{
//該函式把輸入陣列中的每個鍵值傳給回撥函式。如果回撥函式返回 true,則把輸入陣列中的當前鍵值返回給結果陣列。陣列鍵名保持不變。
return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH);
}
}
第二行
public function register($provider, $options = [], $force = false)
{
// 如果已經註冊過,並且非強制註冊,則返回該例項
if (($registered = $this->getProvider($provider)) && ! $force) {
return $registered;
}
//如果給定的“provider”是一個字串,我們將解析它
if (is_string($provider)) {
$provider = $this->resolveProvider($provider);
}
}
/*
* 從類名解析服務提供者例項
*
* 此時$provider = 'Illuminate\Events\EventServiceProvider'
*
* return new Illuminate\Events\EventServiceProvider($this);
*/
public function resolveProvider($provider)
{
return new $provider($this);
}
第三行
public function register($provider, $options = [], $force = false)
{
// 如果已經註冊過,並且非強制註冊,則返回該例項
if (($registered = $this->getProvider($provider)) && ! $force) {
return $registered;
}
//如果給定的“provider”是一個字串,我們將解析它
if (is_string($provider)) {
$provider = $this->resolveProvider($provider);
}
// 如果該 serviceProvider 中有 register 方法,則執行
if (method_exists($provider, 'register')) {
$provider->register();
}
}
/*
* EventServiceProvider類
*/
namespace Illuminate\Events;
use Illuminate\Support\ServiceProvider;
class EventServiceProvider extends ServiceProvider{
public function register()
{
/***注意***列印圖中bindings屬性中的'events'是這時候新增進去的*/
$this->app->singleton('events', function ($app) {
...
});
}
}
第四行
public function register($provider, $options = [], $force = false)
{
// 如果已經註冊過,並且非強制註冊,則返回該例項
if (($registered = $this->getProvider($provider)) && ! $force) {
return $registered;
}
//如果給定的“provider”是一個字串,我們將解析它
if (is_string($provider)) {
$provider = $this->resolveProvider($provider);
}
//呼叫ServiceProvider中的register()方法註冊服務
if (method_exists($provider, 'register')) {
$provider->register();
}
//--> 將該provider做上已註冊的標記
$this->markAsRegistered($provider);
}
/*
* param $provider = EventServiceProvider {#4 ▶}
*/
protected function markAsRegistered($provider)
{
//加入所有已註冊的服務提供商
$this->serviceProviders[] = $provider;
//已載入的服務提供者的名稱
$this->loadedProviders[get_class($provider)] = true;
}
第五行及最後一行
public function register($provider, $options = [], $force = false)
{
// 如果已經註冊過,並且非強制註冊,則返回該例項
if (($registered = $this->getProvider($provider)) && ! $force) {
return $registered;
}
//如果給定的“provider”是一個字串,我們將解析它
if (is_string($provider)) {
$provider = $this->resolveProvider($provider);
}
//呼叫EventServiceProvider中的register()方法註冊服務
if (method_exists($provider, 'register')) {
$provider->register();
}
//將該provider做上已註冊的標記
$this->markAsRegistered($provider);
//-->如果應用程式已經啟動,我們將在provider類上呼叫這個啟動方法,這樣它就有機會執行它的啟動邏輯,併為這個開發人員的應用程式邏輯的任何使用做好準備。
if ($this->booted) {
$this->bootProvider($provider);
}
return $provider;
}
// 如果該 serviceProvider 中有 boot 方法,則呼叫
protected function bootProvider(ServiceProvider $provider)
{
if (method_exists($provider, 'boot')) {
return $this->call([$provider, 'boot']);
}
}
/*
* 何時啟動?
*
* 在index.php中的 執行handle()時 $this->booted = true
*/
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
總結
- 如果
serviceProviders
屬性陣列中已經存在這個例項,則直接返回。這裡判斷是否存在的方式是遍歷該物件陣列,用instanceof
判斷一個物件是不是某個型別的例項。 - 因為我們要儲存例項,所以如果
serviceProvider
傳入的是字串,將解析它。 - 如果該
serviceProvider
包含register
方法,則呼叫。 - 將該
serviceProvider
做上已註冊的標記,即將例項儲存在serviceProviders
屬性中 ,loadedProviders
屬性中標記已載入。 - 如果應用已經啟動,則啟動該
serviceProvider
。應用何時啟動?執行$response = $kernel->handle($request)
時。
本作品採用《CC 協議》,轉載必須註明作者和本文連結