摘要:說(shuō)明本文主要學(xué)習(xí)容器的實(shí)例化過(guò)程,主要包括等四個(gè)過(guò)程??聪碌脑创a如果是數(shù)組,抽取別名并且注冊(cè)到中,上文已經(jīng)討論實(shí)際上就是的。
說(shuō)明:本文主要學(xué)習(xí)Laravel容器的實(shí)例化過(guò)程,主要包括Register Base Bindings, Register Base Service Providers , Register Core Container Aliases and Set the Base Path等四個(gè)過(guò)程。同時(shí)并把自己的一點(diǎn)研究心得分享出來(lái),希望對(duì)別人有所幫助。
開(kāi)發(fā)環(huán)境:Laravel5.3 + PHP7 + OS X10.11
Laravel的入口文件是public/index.php文件,首先第一步加載composer的autoload文件:
// bootstrap/autoload.php require __DIR__."/../vendor/autoload.php";
關(guān)于composer自動(dòng)加載原理可看這篇文章:Laravel學(xué)習(xí)筆記之Composer自動(dòng)加載
然后開(kāi)始實(shí)例化Application容器得到全局變量$app:
$app = new IlluminateFoundationApplication( realpath(__DIR__."/../") );
輸入的是project的根路徑,研究下IlluminateFoundationApplication的構(gòu)造函數(shù)源碼:
public function __construct($basePath = null) { $this->registerBaseBindings(); $this->registerBaseServiceProviders(); $this->registerCoreContainerAliases(); if ($basePath) { $this->setBasePath($basePath); } }
Create Application過(guò)程中做了4件事:
1. register base bindings. 2. register base service providers(IlluminateEventsEventServiceProvider and IlluminateRoutingRoutingServiceProvider). 3. register core service aliases ("app", "auth", "auth.driver", "blade.compiler", "cache", "cache.store", "config", "cookie", "encrypter", "db", "db.connection", "events", "files", "filesystem", "filesystem.disk", "filesystem.cloud", "hash", "translator", "log", "mailer", "auth.password", "auth.password.broker", "queue", "queue.connection", "queue.failer", "redirect", "redis", "request", "router", "session", "session.store", "url", "validator", "view"), and these core service will be registered later. 4. set the base path, including "path" = __DIR__ . "/app", "path.base" = __DIR__ , "path.lang" = __DIR__ . "/resources/lang", "path.config" = __DIR__ . "/config", "path.public" = __DIR__ . "/public", "path.storage" = __DIR__ . "/storage", "path.database" = __DIR__ . "/database", "path.resources" = __DIR__ . "/resources", "path.bootstrap" = __DIR__ . "/bootstrap". U can get theses path everywhere in the way, e.g. public_path("/js/app.js") === __DIR__ . "/public/js/app.js";1. Register Base Bindings
基礎(chǔ)綁定主要是綁定當(dāng)前Application對(duì)象進(jìn)容器,綁定的是同一對(duì)象,但給了兩個(gè)名字:
$this->instance("app", $this); $this->instance("IlluminateContainerContainer", $this);
OK, 那instance()是如何綁定服務(wù)的?
IlluminateFoundationApplication是extends from the IlluminateContainerContainer,看instance()源碼:
/** * Register an existing instance as shared in the container. * * @param string $abstract * @param mixed $instance * @return void */ public function instance($abstract, $instance) { // $abstract如果是string,截取右邊的"", 如IlluminateFoundationApplication => IlluminateFoundationApplication $abstract = $this->normalize($abstract); if (is_array($abstract)) { list($abstract, $alias) = $this->extractAlias($abstract); $this->alias($abstract, $alias); } unset($this->aliases[$abstract]); $bound = $this->bound($abstract); $this->instances[$abstract] = $instance; if ($bound) { $this->rebound($abstract); } }
分解代碼,看別名的注冊(cè):
if (is_array($abstract)) { list($abstract, $alias) = $this->extractAlias($abstract); $this->alias($abstract, $alias); } ... protected function extractAlias(array $definition) { return [key($definition), current($definition)]; } public function alias($abstract, $alias) { $this->aliases[$alias] = $this->normalize($abstract); }
如果$abstract是數(shù)組, e.g. $this->instance(["app" => "IlluminateFoundationApplication"], $this),則app是alias name,存入Container class的$aliases[ ]屬性中,這樣存入值是:
$aliases = [ "app"=> "IlluminateFoundationApplication", ];
然后在注冊(cè)到屬性$instances[ ]中,則上面的綁定代碼類(lèi)似于;
// 這里加個(gè)別名 $this->instances["app" => "IlluminateFoundationApplication"] = (new IlluminateFoundationApplication($path = __DIR__)); $this->instances["IlluminateContainerContainer"] = (new IlluminateFoundationApplication($path = __DIR__));
可以PHPUnit測(cè)試下別名這個(gè)feature:
public function testAlias () { // make()是從Container中解析出service,與instance正好相反 $object1 = App::make("app"); $object2 = App::make("IlluminateFoundationApplication"); $this->assertInstanceOf(IlluminateFoundationApplication::class, $object1); $this->assertInstanceOf(IlluminateFoundationApplication::class, $object2); }
由于不是單例綁定singleton(),這里$object1與$object2都是IlluminateFoundationApplication的對(duì)象,但不是同一對(duì)象。singleton()和make()稍后討論下。
同時(shí)檢查下之前是否已經(jīng)綁定了,如果已經(jīng)綁定了,則執(zhí)行之前rebinding()的回調(diào)函數(shù),主要是執(zhí)行Container的$reboundCallbacks[ ]屬性值。Container提供了rebinding()函數(shù)供再一次補(bǔ)充綁定(如再給"app"綁定一些之前綁定沒(méi)有的的行為),PHPUnit測(cè)試下:
public function testReboundCallbacks() { // Arrange $container = new Container; // Actual $container->instance("app", function(){ return "app1"; }); $a = 0 $container->rebinding("app", function() use (&$a) { $a = 1; }); // 再次綁定時(shí),觸發(fā)上一次rebinding中綁定該"app"的回調(diào) $container->instance("app", function () { return "app2"; }); // Assert $this->assertEqual(1, $a); }
Container的作用是供service的綁定和解析,綁定有三種方法:bind(),singleton(),instance();解析是make(),稍后討論下容器中最重要的這幾個(gè)feature。
2. Register Base Service Providers綁定了名為"app","IlluminateContainerContainer"的兩個(gè)service后(盡管綁定的service相同),看下綁定了兩個(gè)基礎(chǔ)service provider:
$this->register(new IlluminateEventsEventServiceProvider($this)); $this->register(new IlluminateRoutingRoutingServiceProvider($this));
兩個(gè)基礎(chǔ)的service provider is: IlluminateEventsEventServiceProvider和IlluminateRoutingRoutingServiceProvider。看下是如何注冊(cè)兩個(gè)service provider:
public function register($provider, $options = [], $force = false) { if (($registered = $this->getProvider($provider)) && ! $force) { return $registered; } if (is_string($provider)) { $provider = $this->resolveProviderClass($provider); } if (method_exists($provider, "register")) { $provider->register(); } foreach ($options as $key => $value) { $this[$key] = $value; } $this->markAsRegistered($provider); // If the application has already booted, we will call this boot method on // the provider class so it has an opportunity to do its boot logic and // will be ready for any usage by the developer"s application logics. if ($this->booted) { $this->bootProvider($provider); } return $provider; }
首先檢查是否已經(jīng)注冊(cè)了,如果注冊(cè)了就直接返回,主要是檢查Application class 的$serviceProviders[ ]的值,看下代碼:
if (($registered = $this->getProvider($provider)) && ! $force) { return $registered; } ... public function getProvider($provider) { $name = is_string($provider) ? $provider : get_class($provider); return Arr::first($this->serviceProviders, function ($value) use ($name) { return $value instanceof $name; }); }
如果輸入的是字符串,就直接new $provider($this)生成對(duì)象,所以上面兩個(gè)注冊(cè)可以這么寫(xiě):
$this->register(IlluminateEventsEventServiceProvider::class); $this->register(IlluminateRoutingRoutingServiceProvider::class);
然后執(zhí)行service provider中的register()方法,稍后看下兩個(gè)base service provider注冊(cè)了哪些service。
然后把注冊(cè)過(guò)的service provider標(biāo)記為provided,就是寫(xiě)入到$serviceProviders[ ]中,而開(kāi)始是先檢查$serviceProviders[ ]中,有沒(méi)有已經(jīng)注冊(cè)過(guò)的將要注冊(cè)的service??聪耺arkAsRegistered()源碼:
protected function markAsRegistered($provider) { $this["events"]->fire($class = get_class($provider), [$provider]); $this->serviceProviders[] = $provider; $this->loadedProviders[$class] = true; }
這里還用了剛注冊(cè)的"events" service來(lái)觸發(fā)該service provider已經(jīng)注冊(cè)的事件,并把該service provider寫(xiě)入到已經(jīng)加載的屬性中l(wèi)oadedProviders[ ].
然后檢查程序是否已經(jīng)啟動(dòng),如果已經(jīng)啟動(dòng)完成了,再執(zhí)行每一個(gè)service provider中的boot()方法,這里會(huì)發(fā)現(xiàn)為啥每一個(gè)service provider里經(jīng)常出現(xiàn)register()和boot()方法,并且register()是注冊(cè)服務(wù)的,等所有服務(wù)注冊(cè)完,再去boot()一些東西。當(dāng)然,這里程序剛剛注冊(cè)第一個(gè)EventServiceProvider,程序離完全啟動(dòng)還早著呢。不過(guò),可以先看下這里的bootProvider()方法源碼:
protected function bootProvider(ServiceProvider $provider) { if (method_exists($provider, "boot")) { return $this->call([$provider, "boot"]); } } /** * Call the given Closure / class@method and inject its dependencies. * * @param callable|string $callback * @param array $parameters * @param string|null $defaultMethod * @return mixed */ public function call($callback, array $parameters = [], $defaultMethod = null) { if ($this->isCallableWithAtSign($callback) || $defaultMethod) { return $this->callClass($callback, $parameters, $defaultMethod); } $dependencies = $this->getMethodDependencies($callback, $parameters); return call_user_func_array($callback, $dependencies); }
重點(diǎn)看下call()這個(gè)Container另一個(gè)重要的函數(shù),如果這么調(diào)用call(EventServiceProvider@register),那就通過(guò)Container::callClass()來(lái)解析出class和method,然后在調(diào)用call(),看下callClass()源碼:
protected function callClass($target, array $parameters = [], $defaultMethod = null) { $segments = explode("@", $target); $method = count($segments) == 2 ? $segments[1] : $defaultMethod; if (is_null($method)) { throw new InvalidArgumentException("Method not provided."); } // 然后在這樣調(diào)用call([$class, $method], $parameters) return $this->call([$this->make($segments[0]), $method], $parameters); }
也就是說(shuō),如果call(EventServiceProvider@register)這種方式的話(huà)先轉(zhuǎn)化成call([$class, $method], $parameters)來(lái)調(diào)用,當(dāng)然要是直接這種方式就不用在轉(zhuǎn)換了。這里是通過(guò)[(new EventServiceProvider($app)), "boot"]類(lèi)似這種方式來(lái)調(diào)用的。在調(diào)用boot()時(shí)有依賴(lài)怎么辦?使用[$class, $method]通過(guò)getMethodDependencies($parameters)來(lái)獲取$dependencies,看下getMethodDependencies($parameters)源碼:
protected function getMethodDependencies($callback, array $parameters = []) { $dependencies = []; foreach ($this->getCallReflector($callback)->getParameters() as $parameter) { $this->addDependencyForCallParameter($parameter, $parameters, $dependencies); } return array_merge($dependencies, $parameters); } protected function getCallReflector($callback) { if (is_string($callback) && strpos($callback, "::") !== false) { $callback = explode("::", $callback); } if (is_array($callback)) { return new ReflectionMethod($callback[0], $callback[1]); } return new ReflectionFunction($callback); } protected function addDependencyForCallParameter(ReflectionParameter $parameter, array &$parameters, &$dependencies) { if (array_key_exists($parameter->name, $parameters)) { $dependencies[] = $parameters[$parameter->name]; unset($parameters[$parameter->name]); } elseif ($parameter->getClass()) { $dependencies[] = $this->make($parameter->getClass()->name); } elseif ($parameter->isDefaultValueAvailable()) { $dependencies[] = $parameter->getDefaultValue(); } }
這里是通過(guò)PHP的Reflector Method來(lái)獲取依賴(lài),依賴(lài)如果是對(duì)象的話(huà)再繼續(xù)make()自動(dòng)解析出service,是個(gè)外部傳進(jìn)來(lái)的值則代入,有默認(rèn)值傳默認(rèn)值。反射(Reflector)是PHP的一個(gè)重要的高級(jí)特性,值得研究。
總的來(lái)說(shuō),在boot()方法中如果有dependency,container會(huì)自動(dòng)解析,不管該dependency是不是某個(gè)service。這就是Method Injection,我們知道Dependency Injection有兩種:Constructor Injection and Method Injection,這里可看到Method Injection是如何實(shí)現(xiàn)的。
OK,然后看下兩個(gè)service provider注冊(cè)了些什么?
首先注冊(cè)EventServiceProvider中提供的service,看有哪些:
public function register() { $this->app->singleton("events", function ($app) { return (new Dispatcher($app))->setQueueResolver(function () use ($app) { return $app->make("IlluminateContractsQueueFactory"); }); }); }
OK,只有一個(gè)名為"events"的service注冊(cè)到容器中了,并且是單例注冊(cè)的??聪聅ingleton()的源碼:
public function singleton($abstract, $concrete = null) { $this->bind($abstract, $concrete, true); } public function bind($abstract, $concrete = null, $shared = false) { $abstract = $this->normalize($abstract); $concrete = $this->normalize($concrete); // 如果是數(shù)組,抽取別名并且注冊(cè)到$aliases[]中,上文已經(jīng)討論 if (is_array($abstract)) { list($abstract, $alias) = $this->extractAlias($abstract); $this->alias($abstract, $alias); } $this->dropStaleInstances($abstract); if (is_null($concrete)) { $concrete = $abstract; } // If the factory is not a Closure, it means it is just a class name which is // bound into this container to the abstract type and we will just wrap it // up inside its own Closure to give us more convenience when extending. if (! $concrete instanceof Closure) { $concrete = $this->getClosure($abstract, $concrete); } $this->bindings[$abstract] = compact("concrete", "shared"); // If the abstract type was already resolved in this container we"ll fire the // rebound listener so that any objects which have already gotten resolved // can have their copy of the object updated via the listener callbacks. if ($this->resolved($abstract)) { $this->rebound($abstract); } } protected function dropStaleInstances($abstract) { unset($this->instances[$abstract], $this->aliases[$abstract]); }
singleton()實(shí)際上就是$shared = true 的bind()。同時(shí)舍棄掉$instances[]中已經(jīng)注冊(cè)過(guò)的名為$abstract的service,當(dāng)然別名數(shù)組也別忘了舍棄。
如果$concrete沒(méi)有提供,則使用$abstract自動(dòng)補(bǔ)全$concrete,并且使用getClosure()封裝下做個(gè)Closure:
protected function getClosure($abstract, $concrete) { // $c 就是$container,即Container Object,會(huì)在回調(diào)時(shí)傳遞給這個(gè)變量 return function ($c, $parameters = []) use ($abstract, $concrete) { $method = ($abstract == $concrete) ? "build" : "make"; return $c->$method($concrete, $parameters); }; }
$concrete沒(méi)有提供綁定的情況,如:$this->singleton(IlluminateContainerContainer::class); 只提供了$abstract.
這里,就是向$bindings[ ]中注冊(cè)下,現(xiàn)在它的值類(lèi)似這樣:
$bindings = [ "events" => [ "concrete" => function ($app) { return (new Dispatcher($app))->setQueueResolver(function () use ($app) {return $app->make("IlluminateContractsQueueFactory");}); }, "shared" => true, ], ];
已經(jīng)說(shuō)了singleton()和binding()注冊(cè)的區(qū)別就是"shared"的值不一樣,如果是$this->app->binding("events", Closure),則$bindings[ ]值是:
$bindings = [ "events" => [ "concrete" => function ($app) { return (new Dispatcher($app))->setQueueResolver(function () use ($app) {return $app->make("IlluminateContractsQueueFactory");}); }, "shared" => false, ], ];
OK,看下RoutingServiceProvider中注冊(cè)了些什么service?
上文說(shuō)過(guò),Application中register()會(huì)調(diào)用service provider中的register()方法,看下IlluminateRoutingRoutingServiceProvider源碼就發(fā)現(xiàn)其注冊(cè)了幾個(gè)service:"router", "url", "redirect", PsrHttpMessage|ServerRequestInterface::class, PsrHttpMessageResponseInterface::class, IlluminateContractsRoutingResponseFactory::class。
只有IlluminateContractsRoutingResponseFactory::class是singleton(),其余是bind(),e.g. "router" service source code:
$this->app["router"] = $this->app->share(function ($app) { return new Router($app["events"], $app); });
為什么說(shuō)是bind()?并且$this->app["router"]是啥意思?
OK, 看下share()的源碼:
public function share(Closure $closure) { return function ($container) use ($closure) { static $object; if (is_null($object)) { $object = $closure($container); } return $object; }; }
share()僅僅執(zhí)行$closure()并傳入$container,所以上面的"router" service代碼類(lèi)似于:
$this->app["router"] = new Router($app["events"], $app);
$this->app是Container對(duì)象,而Container implement ArrayAccess這個(gè)Interface,實(shí)現(xiàn)對(duì)類(lèi)的屬性做數(shù)組式訪(fǎng)問(wèn),所以Container必須實(shí)現(xiàn)四個(gè)方法:
@link http://php.net/manual/en/arrayaccess.offsetset.php public function offsetExists($offset); public function offsetGet($offset); public function offsetSet($offset, $value); public function offsetUnset($offset);
這里是對(duì)$this->app賦值,所以看下offsetSet()源碼:
public function offsetSet($key, $value) { if (! $value instanceof Closure) { $value = function () use ($value) { return $value; }; } $this->bind($key, $value); }
這里是用bind()來(lái)綁定到container中,所以上文中說(shuō)是bind(),而不是其他。所上文的代碼類(lèi)似于這樣:
$this->app["router"] = new Router($app["events"], $app); is like: $object = new Router($app["events"], $app); $this->bind("router", function () use ($object) {return $object});
總的來(lái)說(shuō),就是通過(guò)注冊(cè)EventServiceProvider and RoutingServiceProvider來(lái)綁定了一些service, e.g. "events", "router" and so on.
3. Register Core Container Aliases由于PHP使用namespace來(lái)命名class,有時(shí)類(lèi)名很長(zhǎng),所以需要做個(gè)別名alias圖方便??聪聄egisterCoreContainerAliases()的源碼:
public function registerCoreContainerAliases() { $aliases = [ "app" => ["IlluminateFoundationApplication", "IlluminateContractsContainerContainer", "IlluminateContractsFoundationApplication"], "auth" => ["IlluminateAuthAuthManager", "IlluminateContractsAuthFactory"], "auth.driver" => ["IlluminateContractsAuthGuard"], "blade.compiler" => ["IlluminateViewCompilersBladeCompiler"], "cache" => ["IlluminateCacheCacheManager", "IlluminateContractsCacheFactory"], "cache.store" => ["IlluminateCacheRepository", "IlluminateContractsCacheRepository"], "config" => ["IlluminateConfigRepository", "IlluminateContractsConfigRepository"], "cookie" => ["IlluminateCookieCookieJar", "IlluminateContractsCookieFactory", "IlluminateContractsCookieQueueingFactory"], "encrypter" => ["IlluminateEncryptionEncrypter", "IlluminateContractsEncryptionEncrypter"], "db" => ["IlluminateDatabaseDatabaseManager"], "db.connection" => ["IlluminateDatabaseConnection", "IlluminateDatabaseConnectionInterface"], "events" => ["IlluminateEventsDispatcher", "IlluminateContractsEventsDispatcher"], "files" => ["IlluminateFilesystemFilesystem"], "filesystem" => ["IlluminateFilesystemFilesystemManager", "IlluminateContractsFilesystemFactory"], "filesystem.disk" => ["IlluminateContractsFilesystemFilesystem"], "filesystem.cloud" => ["IlluminateContractsFilesystemCloud"], "hash" => ["IlluminateContractsHashingHasher"], "translator" => ["IlluminateTranslationTranslator", "SymfonyComponentTranslationTranslatorInterface"], "log" => ["IlluminateLogWriter", "IlluminateContractsLoggingLog", "PsrLogLoggerInterface"], "mailer" => ["IlluminateMailMailer", "IlluminateContractsMailMailer", "IlluminateContractsMailMailQueue"], "auth.password" => ["IlluminateAuthPasswordsPasswordBrokerManager", "IlluminateContractsAuthPasswordBrokerFactory"], "auth.password.broker" => ["IlluminateAuthPasswordsPasswordBroker", "IlluminateContractsAuthPasswordBroker"], "queue" => ["IlluminateQueueQueueManager", "IlluminateContractsQueueFactory", "IlluminateContractsQueueMonitor"], "queue.connection" => ["IlluminateContractsQueueQueue"], "queue.failer" => ["IlluminateQueueFailedFailedJobProviderInterface"], "redirect" => ["IlluminateRoutingRedirector"], "redis" => ["IlluminateRedisDatabase", "IlluminateContractsRedisDatabase"], "request" => ["IlluminateHttpRequest", "SymfonyComponentHttpFoundationRequest"], "router" => ["IlluminateRoutingRouter", "IlluminateContractsRoutingRegistrar"], "session" => ["IlluminateSessionSessionManager"], "session.store" => ["IlluminateSessionStore", "SymfonyComponentHttpFoundationSessionSessionInterface"], "url" => ["IlluminateRoutingUrlGenerator", "IlluminateContractsRoutingUrlGenerator"], "validator" => ["IlluminateValidationFactory", "IlluminateContractsValidationFactory"], "view" => ["IlluminateViewFactory", "IlluminateContractsViewFactory"], ]; foreach ($aliases as $key => $aliases) { foreach ($aliases as $alias) { $this->alias($key, $alias); } } }
給class name注冊(cè)個(gè)別名,并且在相同數(shù)組里有著共同的別名,e.g. "IlluminateFoundationApplication", "IlluminateContractsContainerContainer" and "IlluminateContractsFoundationApplication" share the same alias name "app".
4. Set the Base PathApplication Constructor里需要傳入一個(gè)path這個(gè)原料來(lái)構(gòu)造類(lèi),這里path是這個(gè)project的當(dāng)前絕對(duì)路徑。同時(shí)綁定一些常用的文件夾路徑供將來(lái)使用,看下構(gòu)造函數(shù)中源碼:
public function __construct($basePath) { ... if ($basePath) { $this->setBasePath($basePath); } } public function setBasePath($basePath) { $this->basePath = rtrim($basePath, "/"); $this->bindPathsInContainer(); return $this; } protected function bindPathsInContainer() { $this->instance("path", $this->path()); $this->instance("path.base", $this->basePath()); $this->instance("path.lang", $this->langPath()); $this->instance("path.config", $this->configPath()); $this->instance("path.public", $this->publicPath()); $this->instance("path.storage", $this->storagePath()); $this->instance("path.database", $this->databasePath()); $this->instance("path.resources", $this->resourcePath()); $this->instance("path.bootstrap", $this->bootstrapPath()); }
instance()上文已經(jīng)討論過(guò),所以這里的$instances[ ]類(lèi)似于這樣:
$instances = [ "path" => __DIR__ . "/app", "path.base" => __DIR__ . "/", "path.lang" => __DIR__ . "/resources/lang", "path.config" => __DIR__ . "/config", "path.public" => __DIR__ . "/public", "path.storage" => __DIR__ . "/storage", "path.database" => __DIR__ . "/database", "path.resources" => __DIR__ . "/resources", "path.bootstrap" => __DIR__ . "/bootstrap", ];
OK,看下bootstrap/app.php文件,在得到$app這個(gè)實(shí)例化對(duì)象后,再單例綁定Two Kernel and One Exception:
$app->singleton( IlluminateContractsHttpKernel::class, RightCapitalAdminHttpKernel::class ); $app->singleton( IlluminateContractsConsoleKernel::class, RightCapitalAdminConsoleKernel::class ); $app->singleton( IlluminateContractsDebugExceptionHandler::class, RightCapitalAdminExceptionsHandler::class );
最后,就得到一個(gè)塞滿(mǎn)好幾個(gè)service的容器了,而未被實(shí)例化前是個(gè)空Container.整個(gè)的Application的實(shí)例化過(guò)程分析就OK了。
總結(jié):本文主要學(xué)習(xí)了Application的實(shí)例化過(guò)程,主要學(xué)習(xí)了實(shí)例化過(guò)程中向這個(gè)IoC(Inversion of Control) Container綁定了哪些service,并討論了綁定的三個(gè)方法:bind(),singleton(),instance(),解析方法make()留到多帶帶研究Container時(shí)再討論吧。下次分享下Container學(xué)習(xí)心得,并寫(xiě)上PHPUnit測(cè)試,到時(shí)見(jiàn)。
歡迎關(guān)注Laravel-China。
RightCapital招聘Laravel DevOps
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/30448.html
摘要:實(shí)際上的綁定主要有三種方式且只是一種的,這些已經(jīng)在學(xué)習(xí)筆記之實(shí)例化源碼解析聊過(guò),其實(shí)現(xiàn)方法并不復(fù)雜。從以上源碼發(fā)現(xiàn)的反射是個(gè)很好用的技術(shù),這里給出個(gè),看下能干些啥打印結(jié)果太長(zhǎng)了,就不粘貼了。 說(shuō)明:本文主要學(xué)習(xí)Laravel中Container的源碼,主要學(xué)習(xí)Container的綁定和解析過(guò)程,和解析過(guò)程中的依賴(lài)解決。分享自己的研究心得,希望對(duì)別人有所幫助。實(shí)際上Container的綁...
摘要:學(xué)習(xí)筆記之已經(jīng)聊過(guò)使用了來(lái)設(shè)計(jì),看源碼發(fā)現(xiàn)其巧妙用了和的一些數(shù)組函數(shù)來(lái)設(shè)計(jì)。開(kāi)發(fā)環(huán)境內(nèi)置函數(shù)和看源碼之前,先看下這幾個(gè)內(nèi)置函數(shù)的使用。學(xué)習(xí)筆記之實(shí)例化源碼解析已經(jīng)聊過(guò)的實(shí)例化,得到中的變量,即的實(shí)例化對(duì)象。后面再學(xué)習(xí)下的源碼,到時(shí)見(jiàn)。 說(shuō)明:本文主要學(xué)習(xí)Laravel的Middleware的源碼設(shè)計(jì)思想,并將學(xué)習(xí)心得分享出來(lái),希望對(duì)別人有所幫助。Laravel學(xué)習(xí)筆記之Decorato...
摘要:總結(jié)本文主要學(xué)習(xí)了啟動(dòng)時(shí)做的七步準(zhǔn)備工作環(huán)境檢測(cè)配置加載日志配置異常處理注冊(cè)注冊(cè)啟動(dòng)。 說(shuō)明:Laravel在把Request通過(guò)管道Pipeline送入中間件Middleware和路由Router之前,還做了程序的啟動(dòng)Bootstrap工作,本文主要學(xué)習(xí)相關(guān)源碼,看看Laravel啟動(dòng)程序做了哪些具體工作,并將個(gè)人的研究心得分享出來(lái),希望對(duì)別人有所幫助。Laravel在入口index...
摘要:服務(wù)容器在說(shuō)容器之前,我們需要了解什么是容器。服務(wù)容器是一個(gè)用于管理類(lèi)依賴(lài)和執(zhí)行依賴(lài)注入的強(qiáng)大工具。幾乎所有的服務(wù)容器綁定都是在服務(wù)提供者中完成,也就是在服務(wù)提供者中綁定。 服務(wù)容器 在說(shuō) Ioc 容器之前,我們需要了解什么是 Ioc 容器。 Laravel 服務(wù)容器是一個(gè)用于管理類(lèi)依賴(lài)和執(zhí)行依賴(lài)注入的強(qiáng)大工具。 在理解這句話(huà)之前,我們需要先了解一下服務(wù)容器的來(lái)龍去脈: larave...
摘要:哲學(xué)的一個(gè)重要組成部分就是容器,也可以稱(chēng)為服務(wù)容器。那我們要怎么做呢請(qǐng)看下面的例子數(shù)據(jù)庫(kù)連接通過(guò)上面的代碼,如果我們想把改成,根本不需要去修改類(lèi)構(gòu)造函數(shù)里的依賴(lài)?,F(xiàn)在我要講下容器里到底發(fā)生了什么。 showImg(https://segmentfault.com/img/remote/1460000018868909); IOC 容器是一個(gè)實(shí)現(xiàn)依賴(lài)注入的便利機(jī)制 - Taylor?Ot...
閱讀 1991·2021-09-26 10:19
閱讀 3266·2021-09-24 10:25
閱讀 1654·2019-12-27 11:39
閱讀 1937·2019-08-30 15:43
閱讀 683·2019-08-29 16:08
閱讀 3515·2019-08-29 16:07
閱讀 915·2019-08-26 11:30
閱讀 1279·2019-08-26 10:41