前言
上章了解了服務(wù)容器綁定篇拆魏,本章介紹通過(guò)服務(wù)容器解析實(shí)例
正文
在Laravel的服務(wù)容器中提供了兩種用于獲取服務(wù)容器中實(shí)例的方法
make及resolve
make
make在內(nèi)部是直接調(diào)用了resolve慈俯,但因?yàn)槭褂萌萜魇谴蠖嗍鞘褂肁pplication類來(lái)進(jìn)行make的所以會(huì)先執(zhí)行Application類的make,再調(diào)用到Container中的make
Application:
public function make($abstract, array $parameters = [])
{
//獲取別名卖子,如果未配置則原樣返回
$abstract = $this->getAlias($abstract);
//判斷是否有延遲服務(wù)且未經(jīng)過(guò)instance綁定
if ($this->isDeferredService($abstract) && ! isset($this->instances[$abstract])) {
//加載延遲服務(wù)提供程序
$this->loadDeferredProvider($abstract);
}
return parent::make($abstract, $parameters);
}
Container:
public function make($abstract, array $parameters = [])
{
return $this->resolve($abstract, $parameters);
}
resolve
protected function resolve($abstract, $parameters = [], $raiseEvents = true)
{
//getAlias方法會(huì)假定$abstract是綁定的別名刑峡,從$aliases找到映 射的真實(shí)類型名
//如果沒(méi)有映射則$abstract即為真實(shí)類型名,將$abstract原樣返回
$abstract = $this->getAlias($abstract);
//獲取給定抽象的上下文具體綁定诫舅。
$needsContextualBuild = ! empty($parameters) || ! is_null(
$this->getContextualConcrete($abstract)
);
// 如果服務(wù)是通過(guò)instance()方式綁定的宫患,就直接解析返回綁定的service
if (isset($this->instances[$abstract]) && ! $needsContextualBuild) {
return $this->instances[$abstract];
}
$this->with[] = $parameters;
//獲取綁定時(shí)存入的閉包
$concrete = $this->getConcrete($abstract);
//isBuildable方法:$concrete === $abstract || $concrete instanceof Closure
if ($this->isBuildable($concrete, $abstract)) {
//直接構(gòu)建出實(shí)例娃闲,如果是閉包就返回閉包,如果不是就通過(guò)反射類獲取出實(shí)例返回
$object = $this->build($concrete);
} else {
//如果時(shí)接口實(shí)現(xiàn)這種綁定方式皇帮,通過(guò)接口拿到實(shí)現(xiàn)后需要再make一次才能
$object = $this->make($concrete);
}
//獲取擴(kuò)展程序
foreach ($this->getExtenders($abstract) as $extender) {
$object = $extender($object, $this);
}
//如果服務(wù)是以singleton方式注冊(cè)進(jìn)來(lái)的則属拾,把構(gòu)建好的服務(wù)對(duì)象放到 $instances里冷溶,
// 避免下次使用時(shí)重新構(gòu)建
if ($this->isShared($abstract) && ! $needsContextualBuild) {
$this->instances[$abstract] = $object;
}
if ($raiseEvents) {
$this->fireResolvingCallbacks($abstract, $object);
}
$this->resolved[$abstract] = true;
array_pop($this->with);
return $object;
}
build
public function build($concrete)
{
// 如果是閉包直接執(zhí)行閉包并返回(對(duì)應(yīng)閉包綁定)
if ($concrete instanceof Closure) {
return $concrete($this, $this->getLastParameterOverride());
}
// 使用反射ReflectionClass來(lái)對(duì)實(shí)現(xiàn)類進(jìn)行反射實(shí)例操作
try {
$reflector = new ReflectionClass($concrete);
} catch (ReflectionException $e) {
throw new BindingResolutionException("Target class [$concrete] does not exist.", 0, $e);
}
// 如果不能實(shí)例化瓢娜,這應(yīng)該是接口或抽象類,再或者就是構(gòu)造函數(shù)是 private的虏劲,進(jìn)行異常跑出褒颈。反之實(shí)例化操作
if (! $reflector->isInstantiable()) {
return $this->notInstantiable($concrete);
}
$this->buildStack[] = $concrete;
// 獲取構(gòu)造函數(shù)
$constructor = $reflector->getConstructor();
// 如果構(gòu)造函數(shù)是空,說(shuō)明沒(méi)有任何依賴堡掏,直接new返回
if (is_null($constructor)) {
array_pop($this->buildStack);
return new $concrete;
}
// 獲取構(gòu)造函數(shù)的依賴(形參)刨疼,返回一組ReflectionParameter對(duì)象 組成的數(shù)組表示每一個(gè)參數(shù)
$dependencies = $constructor->getParameters();
try {
// 構(gòu)建構(gòu)造函數(shù)需要的依賴
$instances = $this->resolveDependencies($dependencies);
} catch (BindingResolutionException $e) {
array_pop($this->buildStack);
throw $e;
}
array_pop($this->buildStack);
//從給出的參數(shù)創(chuàng)建一個(gè)新的類實(shí)例
return $reflector->newInstanceArgs($instances);
}