gmnon.cn-疯狂蹂躏欧美一区二区精品,欧美精品久久久久a,高清在线视频日韩欧美,日韩免费av一区二区

站長資訊網(wǎng)
最全最豐富的資訊網(wǎng)站

Laravel實例詳解之容器、控制反轉(zhuǎn)和依賴注入

本篇文章給大家?guī)砹岁P(guān)于Laravel的相關(guān)知識,其中主要介紹了關(guān)于容器、控制反轉(zhuǎn)以及依賴注入的相關(guān)問題,下面就一起來看一下什么相關(guān)的內(nèi)容,希望對大家有幫助。

Laravel實例詳解之容器、控制反轉(zhuǎn)和依賴注入

推薦學(xué)習(xí):Laravel入門

隨著現(xiàn)在應(yīng)用的規(guī)模越來越龐大,對象之間的依賴關(guān)系也越來越復(fù)雜,耦合程度越來越高,經(jīng)常會出現(xiàn)對象之間多重依賴的情況。對于如此龐大復(fù)雜的應(yīng)用,任何修改都可能會牽一發(fā)而動全身,這就為應(yīng)用的后期維護(hù)造成了很多困擾。

??為了解決對象之間耦合度高的問題,控制反轉(zhuǎn)(IoC)的思想也隨之誕生。所謂控制反轉(zhuǎn),是面向?qū)ο缶幊讨械囊环N設(shè)計原則,其目的是為了降低代碼之間的耦合程度。在 Laravel 中,控制反轉(zhuǎn)是通過依賴注入(DI)的方式實現(xiàn)的。

??控制反轉(zhuǎn)的基本思想是借助 IoC 容器實現(xiàn)對象之間的依賴關(guān)系的解耦。引入 IoC 容器之后,所有對象的控制權(quán)都上交給 IoC 容器,IoC 容器成了整個系統(tǒng)的核心,把所有對象粘合在一起發(fā)揮作用。Laravel 中的容器即起到了這個作用。

⒈ 容器

??所謂容器,在 Laravel 中指的是 IlluminateFoundationApplication 對象,Laravel 框架在啟動時即創(chuàng)建了該對象。

# public/index.php $app = require_once __DIR__.'/../bootstrap/app.php'; # bootstrap/app.php $app = new IlluminateFoundationApplication(     $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__) );

??在創(chuàng)建容器的過程中,Laravel 還會對容器進(jìn)行一些基礎(chǔ)的綁定和服務(wù)注冊。Laravel 首先會將容器實例與 app 和 IlluminateContainerContainer 進(jìn)行綁定;之后,Laravel 會將基礎(chǔ)的服務(wù)提供者注冊到容器實例中,包括事件、日志、路由服務(wù)提供者;最后,Laravel 會將框架核心 class 與其相對應(yīng)的別名一起注冊到容器實例當(dāng)中。

// namespace IlluminateFoundationApplication public function __construct($basePath = null) {     if ($basePath) {         $this->setBasePath($basePath);     }     $this->registerBaseBindings();     $this->registerBaseServiceProviders();     $this->registerCoreContainerAliases(); }      protected function registerBaseBindings() {     static::setInstance($this);     $this->instance('app', $this);     $this->instance(Container::class, $this);     /* ... ... */ } protected function registerBaseServiceProviders() {     $this->register(new EventServiceProvider($this));     $this->register(new LogServiceProvider($this));     $this->register(new RoutingServiceProvider($this)); } public function registerCoreContainerAliases() {     foreach ([         'app' => [self::class, IlluminateContractsContainerContainer::class, IlluminateContractsFoundationApplication::class, PsrContainerContainerInterface::class],         /* ... ...*/         'db' => [IlluminateDatabaseDatabaseManager::class, IlluminateDatabaseConnectionResolverInterface::class],         'db.connection' => [IlluminateDatabaseConnection::class, IlluminateDatabaseConnectionInterface::class],         /* ... ... */         'request' => [IlluminateHttpRequest::class, SymfonyComponentHttpFoundationRequest::class],         'router' => [IlluminateRoutingRouter::class, IlluminateContractsRoutingRegistrar::class, IlluminateContractsRoutingBindingRegistrar::class],         /* ... ... */     ] as $key => $aliases) {         foreach ($aliases as $alias) {             $this->alias($key, $alias);         }     } } // namespace IlluminateContainerContainer public function alias($abstract, $alias) {     if ($alias === $abstract) {         throw new LogicException("[{$abstract}] is aliased to itself.");     }     $this->aliases[$alias] = $abstract;     $this->abstractAliases[$abstract][] = $alias; }

??在完成這三步基本的注冊之后,我們可以很方便的訪問已經(jīng)注冊到容器中的對象實例。例如,可以直接通過 $app['app'] 或 $app['IlluminateContainerContainer'] 訪問容器本身,還可以通過 $app['db'] 直接訪問數(shù)據(jù)庫連接。

⒉ 服務(wù)提供者的注冊以及服務(wù)的訪問

注冊服務(wù)提供者

??在容器創(chuàng)建的過程中會注冊基礎(chǔ)服務(wù)提供者,其注冊過程通過調(diào)用 register() 方法完成。

// namespace IlluminateFoundationApplication public function register($provider, $force = false) {     if (($registered = $this->getProvider($provider)) && ! $force) {         return $registered;     }     if (is_string($provider)) {         $provider = $this->resolveProvider($provider);     }     $provider->register();     if (property_exists($provider, 'bindings')) {         foreach ($provider->bindings as $key => $value) {             $this->bind($key, $value);         }     }     if (property_exists($provider, 'singletons')) {         foreach ($provider->singletons as $key => $value) {             $this->singleton($key, $value);         }     }     $this->markAsRegistered($provider);     if ($this->isBooted()) {         $this->bootProvider($provider);     }     return $provider; }

??Laravel 首先會判斷指定的服務(wù)提供者是否已經(jīng)在容器中注冊(通過調(diào)用 getProvider() 方法實現(xiàn)),如果指定的服務(wù)提供者已經(jīng)在容器中注冊,并且本次注冊操作并非強制執(zhí)行,那么直接返回已經(jīng)注冊好的服務(wù)提供者。

??如果不滿足上述條件,那么 Laravel 就會開始注冊服務(wù)提供者。此時,如果傳參為字符串,那么 Laravel 會默認(rèn)參數(shù)為服務(wù)提供者的 class 名稱并進(jìn)行實例化(通過 resolveProvider() 方法實現(xiàn))。之后,就會調(diào)用服務(wù)提供者定義的 register() 方法進(jìn)行注冊。以日志服務(wù)提供者為例,其 register() 方法的方法體如下

// namespace IlluminateLogLogServiceProvider public function register() {     $this->app->singleton('log', function ($app) {         return new LogManager($app);     }); }

??register() 方法的作用就是將 IlluminateLogLogManager 對象以單例的模式注冊到容器當(dāng)中,注冊完成之后,容器的 $bindings 屬性中會增加一項

$app->bindings['log'] = [     'concrete' => 'IlluminateLogLogManager {#162}',     'shared' => true, ];

??如果服務(wù)提供者自身還定義了 $bindings 屬性以及 $singletons 屬性,那么 Laravel 還會調(diào)用相應(yīng)的 bind() 方法和 singleton() 方法完成這些服務(wù)提供者自定義的綁定的注冊。

??這之后 Laravel 會將服務(wù)提供者標(biāo)記為已經(jīng)注冊的狀態(tài),隨后會調(diào)用服務(wù)提供者定義的 boot() 方法啟動服務(wù)提供者(前提是應(yīng)用已經(jīng)啟動)。

??在向容器中注冊綁定時,有 bind() 和 singleton() 兩種方法,其區(qū)別僅在于注冊的綁定是否為單例模式,即 shared 屬性是否為 true 。

// namespace IlluminateContainerContainer public function singleton($abstract, $concrete = null) {     $this->bind($abstract, $concrete, true); } public function bind($abstract, $concrete = null, $shared = false) {     // 刪除舊的綁定     $this->dropStaleInstances($abstract);     if (is_null($concrete)) {         $concrete = $abstract;     }     if (! $concrete instanceof Closure) {         if (! is_string($concrete)) {             throw new TypeError(self::class.'::bind(): Argument #2 ($concrete) must be of type Closure|string|null');         }         $concrete = $this->getClosure($abstract, $concrete);     }     $this->bindings[$abstract] = compact('concrete', 'shared');     if ($this->resolved($abstract)) {         $this->rebound($abstract);     } } protected function getClosure($abstract, $concrete) {     return function ($container, $parameters = []) use ($abstract, $concrete) {         if ($abstract == $concrete) {             return $container->build($concrete);         }         return $container->resolve(             $concrete, $parameters, $raiseEvents = false         );     }; }

??仍然以日志服務(wù)提供者為例,日志服務(wù)提供者在注冊時以單例模式進(jìn)行注冊,并且 $concrete 參數(shù)為閉包。在綁定開始之前,Laravel 首先會刪除舊的綁定。由于此時 $concrete 為閉包,所以 Laravel 并不會進(jìn)行什么操作,只是將綁定信息存入 $bindings 屬性當(dāng)中。

訪問服務(wù)

??在服務(wù)提供者注冊完成之后,我們可以用上文提到的類似訪問數(shù)據(jù)庫連接的方式那樣訪問服務(wù)。仍然以日志服務(wù)為例,我們可以通過 $app['log'] 的方式訪問日志服務(wù)。另外,在 Laravel 中,我們還可以使用 facade 的方式訪問服務(wù),例如,我們可以調(diào)用 IlluminateSupportFacadesLog::info() 來記錄日志。

// namespace IlluminateSupportFacadesLog class Log extends Facade {     protected static function getFacadeAccessor()     {         return 'log';     } } // namespace IlluminateSupportFacadesFacade public static function __callStatic($method, $args) {     $instance = static::getFacadeRoot();     /* ... ... */     return $instance->$method(...$args); } public static function getFacadeRoot() {     return static::resolveFacadeInstance(static::getFacadeAccessor()); } protected static function resolveFacadeInstance($name) {     if (is_object($name)) {         return $name;     }     if (isset(static::$resolvedInstance[$name])) {         return static::$resolvedInstance[$name];     }     if (static::$app) {         return static::$resolvedInstance[$name] = static::$app[$name];     } }

??在通過靜態(tài)調(diào)用的方式進(jìn)行日志記錄時,首先會訪問 Facade 中的魔術(shù)方法 __callStatic() ,該方法的首先進(jìn)行的就是解析出 facade 對應(yīng)的服務(wù)實例,然后調(diào)用該服務(wù)實例下的方法來執(zhí)行相應(yīng)的功能。每個 facade 中都會定義一個 getFacadeAccessor() 方法,這個方法會返回一個 tag,在日志服務(wù)中,這個 tag 就是日志服務(wù)提供者的閉包在容器的 $bindings 屬性中的 key。也就是說,通過 facade 方式最終得到的是 $app['log']。

??那么為什么可以通過關(guān)聯(lián)數(shù)組的方式訪問容器中注冊的對象/服務(wù)?IlluminateContainerContainer 實現(xiàn)了 ArrayAccess 并且定義了 OffsetGet() 方法,而 IlluminateFoundationApplication 繼承了 Container ,$app 為 Application 實例化的對象,所以通過關(guān)聯(lián)數(shù)組的方式訪問容器中注冊的對象時會訪問 Container 的 OffsetGet() 方法。在 OffsetGet() 方法中會調(diào)用 Container 的 make() 方法,而 make() 方法中又會調(diào)用 resolve() 方法。resolve() 方法最終會解析并返回相應(yīng)的對象。

// namespace IlluminateContainer public function offsetGet($key) {     return $this->make($key); } public function make($abstract, array $parameters = []) {     return $this->resolve($abstract, $parameters); } protected function resolve($abstract, $parameters = [], $raiseEvents = true) {     /* ... ... */     $this->with[] = $parameters;     if (is_null($concrete)) {         $concrete = $this->getConcrete($abstract);     }     if ($this->isBuildable($concrete, $abstract)) {         $object = $this->build($concrete);     } else {         $object = $this->make($concrete);     }     /* ... ... */     $this->resolved[$abstract] = true;     array_pop($this->with);     return $object; } protected function getConcrete($abstract) {     if (isset($this->bindings[$abstract])) {         return $this->bindings[$abstract]['concrete'];     }     return $abstract; } protected function isBuildable($concrete, $abstract) {     return $concrete === $abstract || $concrete instanceof Closure; } public function build($concrete) {     if ($concrete instanceof Closure) {         return $concrete($this, $this->getLastParameterOverride());     }     /* ... ... */ } protected function getLastParameterOverride() {     return count($this->with) ? end($this->with) : []; }

??這里需要說明,在通過 $app['log'] 的方式解析日志服務(wù)實例時,resolve() 方法中的 $concrete 解析得到的是一個閉包,導(dǎo)致 isBuildable() 方法返回結(jié)果為 true,所以 Laravel 會直接調(diào)用 build() 方法。而由于此時 $concrete 是一個閉包,所以在 build() 方法中會直接執(zhí)行這個閉包函數(shù),最終返回 LogManager 實例。

⒊ 請求處理

??在基礎(chǔ)的綁定和服務(wù)注冊完成之后,容器創(chuàng)建成功并返回 $app 。之后 Laravel 會將內(nèi)核(包括 Http 內(nèi)核和 Console 內(nèi)核)和異常處理注冊到容器當(dāng)中。然后 Laravel 開始處理請求。

// namespace bootstrap/app.php $app->singleton(     IlluminateContractsHttpKernel::class,     AppHttpKernel::class ); $app->singleton(     IlluminateContractsConsoleKernel::class,     AppConsoleKernel::class ); $app->singleton(     IlluminateContractsDebugExceptionHandler::class,     AppExceptionsHandler::class ); // public/index.php $kernel = $app->make(IlluminateContractsHttpKernel::class); $response = $kernel->handle(     $request = Request::capture() )->send(); $kernel->terminate($request, $response);

??在開始處理請求之前,Laravel 首先會解析出 Http 內(nèi)核對象 $kernel,即 AppHttpKernel 實例化的對象。而 AppHttpKernel 繼承了 IlluminateFoundationKernel,所以 $kernel 實際調(diào)用的是 IlluminateFoundationKernel 中的 handle() 方法。

namespace IlluminateFoundationHttp use IlluminateContractsDebugExceptionHandler public function handle($request) {     try {         $request->enableHttpMethodParameterOverride();         $response = $this->sendRequestThroughRouter($request);     } catch (Throwable $e) {         $this->reportException($e);         $response = $this->renderException($request, $e);     }     $this->app['events']->dispatch(         new RequestHandled($request, $response)     );     return $response; } // 上報錯誤 protected function reportException(Throwable $e) {     $this->app[ExceptionHandler::class]->report($e); } // 渲染錯誤信息     protected function renderException($request, Throwable $e) {     return $this->app[ExceptionHandler::class]->render($request, $e); }

??handle() 方法在處理請求的過程中如果出現(xiàn)任何異常或錯誤,Laravel 都會調(diào)用容器中已經(jīng)注冊好的異常處理對象來上報異常并且渲染返回信息。

??在容器創(chuàng)建成功以后,Laravel 會將 IlluminateContractsDebugExceptionHandler 和 AppExceptionsHandler 之間的綁定注冊到容器當(dāng)中,所以 Laravel 處理異常實際調(diào)用的都是 AppExceptionsHandler 中的方法。在實際開發(fā)過程中,開發(fā)者可以根據(jù)自身需要在 AppExceptionsHandler 中自定義 report() 和 render() 方法。

在 PHP 7 中,`Exception` 和 `Error` 是兩種不同的類型,但它們同時都繼承了 `Throwable` ,所以 `handler()` 方法中捕獲的是 `Throwable` 對象。

??在正式開始處理請求之前,Laravel 會進(jìn)行一些引導(dǎo)啟動,包括加載環(huán)境變量、配置信息等,這些引導(dǎo)啟動在 Laravel 運行過程中起到了非常重要的作用。

// namespace IlluminateFoundationHttpKernel protected $bootstrappers = [     IlluminateFoundationBootstrapLoadEnvironmentVariables::class,     IlluminateFoundationBootstrapLoadConfiguration::class,     IlluminateFoundationBootstrapHandleExceptions::class,     IlluminateFoundationBootstrapRegisterFacades::class,     IlluminateFoundationBootstrapRegisterProviders::class,     IlluminateFoundationBootstrapBootProviders::class, ]; protected function sendRequestThroughRouter($request) {     /* ... ... */     $this->bootstrap();     /* ... ... */ } public function bootstrap() {     if (! $this->app->hasBeenBootstrapped()) {         $this->app->bootstrapWith($this->bootstrappers());     } } // namespace IlluminateFoundationApplication public function bootstrapWith(array $bootstrappers) {     $this->hasBeenBootstrapped = true;     foreach ($bootstrappers as $bootstrapper) {         $this['events']->dispatch('bootstrapping: '.$bootstrapper, [$this]);         $this->make($bootstrapper)->bootstrap($this);         $this['events']->dispatch('bootstrapped: '.$bootstrapper, [$this]);     } }

??從代碼中可以看出,引導(dǎo)啟動的過程實際就是調(diào)用各個 class 中的 bootstrap() 方法。其中:

LoadEnvironmentVariables 用來加載環(huán)境變量

LoadConfiguration 用來加載 config 目錄下的配置文件

HandleExceptions 用來設(shè)置 PHP 的錯誤報告級別以及相應(yīng)的異常和錯誤處理函數(shù),另外還會設(shè)置 PHP 的程序終止執(zhí)行函數(shù)

// namespace IlluminateFoundationBootstrapHandleExceptions public function bootstrap(Application $app) {     /* ... ... */     $this->app = $app;     error_reporting(-1);     set_error_handler([$this, 'handleError']);     set_exception_handler([$this, 'handleException']);     register_shutdown_function([$this, 'handleShutdown']);     /* ... ... */ } public function handleError($level, $message, $file = '', $line = 0, $context = []) {     if (error_reporting() & $level) {         /* ... ... */         throw new ErrorException($message, 0, $level, $file, $line);     } } public function handleException(Throwable $e) {     /* ... ... */         $this->getExceptionHandler()->report($e);     /* ... ... */ } public function handleShutdown() {     if (! is_null($error = error_get_last()) && $this->isFatal($error['type'])) {         $this->handleException($this->fatalErrorFromPhpError($error, 0));     } } protected function getExceptionHandler() {     return $this->app->make(IlluminateContractsDebugExceptionHandler::class); }

??從以上代碼中可以看出,雖然 HandleExceptions 中定義了異常、錯誤、程序終止的處理函數(shù),但無論是哪種情況,最終還是調(diào)用 AppExceptionsHandler 中的方法來處理異常或錯誤。

RegisterFacades 的作用一個是注冊配置文件以及第三方包中自定義的 alias 類,還有一個非常重要的作用就是為 IlluminateSupportFacadesFacade 類設(shè)置 $app 屬性。

// namespace IlluminateFoundationBootstrapRegisterFAcades public function bootstrap(Application $app) {     Facade::clearResolvedInstances();     Facade::setFacadeApplication($app);     AliasLoader::getInstance(array_merge(         $app->make('config')->get('app.aliases', []),         $app->make(PackageManifest::class)->aliases()     ))->register(); }

&emsp?我們在通過 facade 方式反問容器中注冊的服務(wù)時,F(xiàn)acade 在解析容器中的服務(wù)實例時用到的 static::$app 即是在這個時候設(shè)置的。

RegisterProviders 的作用是注冊配置文件以及第三方包中定義的服務(wù)提供者

// namespace IlluminateFoundationBootstrapRegisterProviders public function bootstrap(Application $app) {     $app->registerConfiguredProviders(); } public function registerConfiguredProviders() {     $providers = Collection::make($this->make('config')->get('app.providers'))                     ->partition(function ($provider) {                         return strpos($provider, 'Illuminate\') === 0;                     });     $providers->splice(1, 0, [$this->make(PackageManifest::class)->providers()]);     (new ProviderRepository($this, new Filesystem, $this->getCachedServicesPath()))                 ->load($providers->collapse()->toArray()); }

??在實際注冊的過程中,Laravel 會按照 Laravel 框架的服務(wù)提供者 > 第三方包的服務(wù)提供者 > 開發(fā)者自定義的服務(wù)提供者 的順序進(jìn)行注冊

BootProviders 則是按順序調(diào)用已經(jīng)注冊到容器中的服務(wù)提供者的 boot() 方法(前提是服務(wù)提供者定義的 boot() 方法)

??在引導(dǎo)啟動完成之后,Laravel 開始處理請求,首先要做的就是將全局的中間件應(yīng)用于 request 。這之后 Laravel 會將請求分發(fā)到相應(yīng)的路由進(jìn)行處理,處理之前需要先根據(jù) request 找到相應(yīng)的路由對象 IlluminateRoutingRoute。在 Laravel 中,除了全局中間件,還有一些中間件只作用于特定的路由或路由分組,此時這些中間件就會被作用于 request 。這些工作都完成之后,路由對象開始執(zhí)行代碼,完成請求。

// namespace IlluminateFoundationHttpKernel protected function sendRequestThroughRouter($request) {     /* ... ... */     return (new Pipeline($this->app))                 ->send($request)                 ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)                 ->then($this->dispatchToRouter()); } protected function dispatchToRouter() {     return function ($request) {         $this->app->instance('request', $request);                  return $this->router->dispatch($request);     }; } // namespace IlluminateRoutingRouter public function dispatch(Request $request) {     $this->currentRequest = $request;     return $this->dispatchToRoute($request); } public function dispatchToRoute(Request $request) {     return $this->runRoute($request, $this->findRoute($request)); } protected function runRoute(Request $request, Route $route) {     /* ... ... */     return $this->prepareResponse($request,         $this->runRouteWithinStack($route, $request)     ); } protected function runRouteWithinStack(Route $route, Request $request) {     /* ... ... */        return (new Pipeline($this->container))                     ->send($request)                     ->through($middleware)                     ->then(function ($request) use ($route) {                         return $this->prepareResponse(                             $request, $route->run()                         );                     }); }

⒋ 依賴注入

??Laravel 中的路由在注冊時,action 可以是控制器方法,也可以是閉包。但無論是那種形式,都需要傳參,而傳參就會遇到需要依賴注入的情況。

??Route 對象在執(zhí)行 run() 方法時會根據(jù) action 的類型分別進(jìn)行控制器方法調(diào)用或閉包函數(shù)的調(diào)用。但兩種方法最終都需要解析參數(shù),而如果參數(shù)中用到了 class ,就需要進(jìn)行依賴注入。

// namespace IlluminateRoutingRouter public function run() {     $this->container = $this->container ?: new Container;     try {         if ($this->isControllerAction()) {             return $this->runController();         }         return $this->runCallable();     } catch (HttpResponseException $e) {         return $e->getResponse();     } } protected function runController() {     return $this->controllerDispatcher()->dispatch(         $this, $this->getController(), $this->getControllerMethod()     ); } protected function runCallable() {     /* ... ... */     return $callable(...array_values($this->resolveMethodDependencies(         $this->parametersWithoutNulls(), new ReflectionFunction($callable)     ))); } // namespace IlluminateRoutingControllerDispatcher public function dispatch(Route $route, $controller, $method) {     $parameters = $this->resolveClassMethodDependencies(         $route->parametersWithoutNulls(), $controller, $method     );     /* ... ... */ } // namespace IlluminateRoutingRouteDependencyResolverTrait protected function resolveClassMethodDependencies(array $parameters, $instance, $method) {     /* ... ... */     return $this->resolveMethodDependencies(         $parameters, new ReflectionMethod($instance, $method)     ); } public function resolveMethodDependencies(array $parameters, ReflectionFunctionAbstract $reflector) {     /* ... ... */     foreach ($reflector->getParameters() as $key => $parameter) {         $instance = $this->transformDependency($parameter, $parameters, $skippableValue);         /* ... ... */     }     return $parameters; } protected function transformDependency(ReflectionParameter $parameter, $parameters, $skippableValue) {     $className = Reflector::getParameterClassName($parameter);     if ($className && ! $this->alreadyInParameters($className, $parameters)) {         return $parameter->isDefaultValueAvailable() ? null : $this->container->make($className);     }     return $skippableValue; }

??在執(zhí)行過程中,Laravel 首先通過反射取得參數(shù)列表(對于控制器方法,使用 ReflectionMethod ,對于閉包函數(shù),則使用 ReflectionFunction )。在得到參數(shù)列表后,Laravel 仍然是利用反射,逐個判斷參數(shù)類型。如果參數(shù)類型為 PHP 的內(nèi)置類型,那么不需要什么特殊處理;但如果參數(shù)不是 PHP 內(nèi)置類型,則需要利用反射解析出參數(shù)的具體類型。在解析出參數(shù)的具體類型之后,緊接著會判斷該類型的對象是不是已經(jīng)存在于參數(shù)列表中,如果不存在并且該類型也沒有設(shè)置默認(rèn)值,那么就需要通過容器創(chuàng)建出該類型的實例。

??要通過容器創(chuàng)建指定 class 的實例,仍然需要用到 resolve() 方法。前文已經(jīng)敘述過使用 resolve() 方法解析閉包函數(shù)的情況,所以這里值敘述實例化 class 的情況。

// namespace IlluminateContainerContainer public function build($concrete) {     /* ... ... */     try {         $reflector = new ReflectionClass($concrete);     } catch (ReflectionException $e) {         throw new BindingResolutionException("Target class [$concrete] does not exist.", 0, $e);     }     if (! $reflector->isInstantiable()) {         return $this->notInstantiable($concrete);     }     $this->buildStack[] = $concrete;     $constructor = $reflector->getConstructor();     if (is_null($constructor)) {         array_pop($this->buildStack);         return new $concrete;     }     $dependencies = $constructor->getParameters();     try {         $instances = $this->resolveDependencies($dependencies);     } catch (BindingResolutionException $e) {         array_pop($this->buildStack);         throw $e;     }     array_pop($this->buildStack);     return $reflector->newInstanceArgs($instances); } protected function resolveDependencies(array $dependencies) {     $results = [];     foreach ($dependencies as $dependency) {         if ($this->hasParameterOverride($dependency)) {             $results[] = $this->getParameterOverride($dependency);             continue;         }         $result = is_null(Util::getParameterClassName($dependency))                         ? $this->resolvePrimitive($dependency)                         : $this->resolveClass($dependency);         if ($dependency->isVariadic()) {             $results = array_merge($results, $result);         } else {             $results[] = $result;         }     }     return $results; }

??容器在實例化 class 的時候,仍然是通過反射獲取 class 基本信息。對于一些無法進(jìn)行實例化的 class (例如 interface 、abstract class ),Laravel 會拋出異常;否則 Laravel 會繼續(xù)獲取 class 的構(gòu)造函數(shù)的信息。對于不存在構(gòu)造函數(shù)的 class ,意味著這些 class 在實例化的時候不需要額外的依賴,可以直接通過 new 來實例化;否則仍然是通過反射解析出構(gòu)造函數(shù)的參數(shù)列表信息,然后逐個實例化這些參數(shù)列表中用到的 class 。在這些參數(shù)列表中的 class 都實例化完成之后,通過容器創(chuàng)建 class 的準(zhǔn)備工作也已經(jīng)完成,此時容器可以順利創(chuàng)建出指定 class 的實例,然后注入到控制器方法或閉包中。

推薦學(xué)習(xí):Laravel入門

贊(0)
分享到: 更多 (0)
?
網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號
gmnon.cn-疯狂蹂躏欧美一区二区精品,欧美精品久久久久a,高清在线视频日韩欧美,日韩免费av一区二区
久久综合九色综合88i| 欧美一级片中文字幕| av片中文字幕| 91免费视频黄| 丝袜制服一区二区三区| 99热一区二区三区| 男人的天堂最新网址| 秋霞无码一区二区| 91午夜在线观看| 麻豆一区二区三区在线观看| youjizzxxxx18| 男人日女人逼逼| 午夜激情影院在线观看| 亚洲国产精品三区| 男女曰b免费视频| 男女高潮又爽又黄又无遮挡| 全黄性性激高免费视频| 免费日韩在线观看| 99视频精品全部免费看| 亚洲综合激情五月| 日本xxx免费| 日韩不卡一二区| 无码人妻aⅴ一区二区三区日本| 99视频在线免费| 欧美三级理论片| 蜜臀一区二区三区精品免费视频| 99视频在线免费| 黄色av免费在线播放| 91黄色小网站| 国产精品自拍视频在线| 成年人三级黄色片| 黄色网zhan| 日韩精品 欧美| 人妻熟女一二三区夜夜爱| 国产中文字幕免费观看| 免费无遮挡无码永久视频| 国产91对白刺激露脸在线观看| 50路60路老熟妇啪啪| 精品亚洲视频在线| 佐佐木明希av| 两根大肉大捧一进一出好爽视频| 黄色国产精品视频| 91小视频在线播放| 免费的一级黄色片| 国产1区2区在线| 久久久久久综合网| 久久久久免费看黄a片app| 国产福利一区视频| 亚洲综合激情五月| 免费高清在线观看免费| 在线a免费观看| 熟女少妇在线视频播放| 久久黄色片网站| 国产一线二线三线女| 亚洲一二三区av| 青青青青在线视频| 一道本在线免费视频| 国产不卡一区二区视频| 91精品999| 国内性生活视频| caoporm在线视频| 一本大道熟女人妻中文字幕在线| 午夜免费福利网站| 国产免费视频传媒| 日韩一级片免费视频| 三区视频在线观看| 欧美极品欧美精品欧美| 三级黄色片播放| 北条麻妃av高潮尖叫在线观看| dy888午夜| 精品亚洲视频在线| 爆乳熟妇一区二区三区霸乳| 国产高清不卡无码视频| 91香蕉视频免费看| 日本男人操女人| 欧美在线观看成人| 久久亚洲精品无码va白人极品| www.成人黄色| 亚洲欧洲日本精品| 日本爱爱免费视频| 久久精品免费一区二区| 日韩精品一区二区三区四 | 欧美牲交a欧美牲交| 天堂av在线中文| 黄瓜视频免费观看在线观看www| 91网址在线播放| 欧美成人黑人猛交| 任你操这里只有精品| 日韩精品一区在线视频| 欧美国产视频一区| av日韩在线看| 国产一级不卡视频| 欧美视频在线第一页| 国产女教师bbwbbwbbw| 400部精品国偷自产在线观看| 91精品国产三级| 美女黄色片网站| 欧美a级黄色大片| 三上悠亚免费在线观看| 成人性做爰片免费视频| 强伦女教师2:伦理在线观看| 三年中国中文在线观看免费播放| 亚洲综合av在线播放| 欧美一级免费在线| 免费观看国产视频在线| 白白操在线视频| 50度灰在线观看| 亚欧无线一线二线三线区别| 国产极品粉嫩福利姬萌白酱| 大香煮伊手机一区| 日本黄色福利视频| 中文字幕日韩精品无码内射| 性欧美大战久久久久久久| 国产精品秘入口18禁麻豆免会员| 国产91美女视频| 日日干日日操日日射| 国产香蕉一区二区三区| 女人扒开屁股爽桶30分钟| 亚洲国产精品三区| 成人手机在线播放| 超碰97人人射妻| 超碰91在线播放| 欧美综合在线播放| 亚洲一区二区福利视频| 日韩激情视频一区二区| 少妇激情一区二区三区| 色中文字幕在线观看| 波多野结衣之无限发射| 青青草原国产在线视频| xxxx18hd亚洲hd捆绑| 日本黄色福利视频| 亚洲熟妇无码另类久久久| 亚洲欧美日韩三级| 亚洲人成无码网站久久99热国产| 亚洲免费一级视频| 五月天激情图片| 国产aⅴ爽av久久久久| 啊啊啊一区二区| 日本一二三区在线| 欧美性猛交久久久乱大交小说 | 91精品999| 337p粉嫩大胆噜噜噜鲁| 日本高清xxxx| 亚洲国产日韩欧美在线观看| 国产精品又粗又长| 国产精品一二三在线观看| 91高清国产视频| 免费看a级黄色片| av高清在线免费观看| 精品日韩在线播放| 一级黄色特级片| 国产主播中文字幕| 无码人妻h动漫| 国内性生活视频| 给我免费播放片在线观看| 中文字幕一区二区三区四区五区人| 国产精品亚洲a| 激情六月丁香婷婷| 欧美黑人经典片免费观看| 波多野结衣av一区二区全免费观看| 9999在线观看| 欧美性视频在线播放| 国产毛片久久久久久| 国产永久免费网站| 亚洲综合伊人久久| 黄色a级在线观看| 中国黄色录像片| 成人区一区二区| 日本人体一区二区| 国产资源在线视频| 99精品视频在线看| 香蕉视频禁止18| 国产三级生活片| 四虎成人在线播放| 黄色特一级视频| 欧美深夜福利视频| 人人干人人视频| 日韩va在线观看| 99亚洲国产精品| www.日本在线播放| 好男人www社区| 天天综合中文字幕| www.好吊操| 农村妇女精品一二区| 亚洲色图 在线视频| 成人亚洲免费视频| 免费看欧美黑人毛片| 免费在线观看日韩视频| 国产精品v日韩精品v在线观看| 亚洲综合激情视频| 国产夫妻自拍一区| 99视频精品免费| 性久久久久久久久久久久久久| 99久久久无码国产精品性色戒| 日本香蕉视频在线观看| 免费看污污网站| 免费网站在线观看视频| 免费国产成人av| 屁屁影院ccyy国产第一页| 亚洲中文字幕无码不卡电影|