摘要:說明本文主要學(xué)習(xí)容器的實(shí)例化過程,主要包括等四個(gè)過程。看下的源碼如果是數(shù)組,抽取別名并且注冊到中,上文已經(jīng)討論實(shí)際上就是的。
說明:本文主要學(xué)習(xí)Laravel容器的實(shí)例化過程,主要包括Register Base Bindings, Register Base Service Providers , Register Core Container Aliases and Set the Base Path等四個(gè)過程。同時(shí)并把自己的一點(diǎn)研究心得分享出來,希望對別人有所幫助。
開發(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自動加載原理可看這篇文章:Laravel學(xué)習(xí)筆記之Composer自動加載
然后開始實(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過程中做了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對象進(jìn)容器,綁定的是同一對象,但給了兩個(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); } }
分解代碼,看別名的注冊:
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", ];
然后在注冊到屬性$instances[ ]中,則上面的綁定代碼類似于;
// 這里加個(gè)別名 $this->instances["app" => "IlluminateFoundationApplication"] = (new IlluminateFoundationApplication($path = __DIR__)); $this->instances["IlluminateContainerContainer"] = (new IlluminateFoundationApplication($path = __DIR__));
可以PHPUnit測試下別名這個(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的對象,但不是同一對象。singleton()和make()稍后討論下。
同時(shí)檢查下之前是否已經(jīng)綁定了,如果已經(jīng)綁定了,則執(zhí)行之前rebinding()的回調(diào)函數(shù),主要是執(zhí)行Container的$reboundCallbacks[ ]屬性值。Container提供了rebinding()函數(shù)供再一次補(bǔ)充綁定(如再給"app"綁定一些之前綁定沒有的的行為),PHPUnit測試下:
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??聪率侨绾巫詢蓚€(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)注冊了,如果注冊了就直接返回,主要是檢查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)生成對象,所以上面兩個(gè)注冊可以這么寫:
$this->register(IlluminateEventsEventServiceProvider::class); $this->register(IlluminateRoutingRoutingServiceProvider::class);
然后執(zhí)行service provider中的register()方法,稍后看下兩個(gè)base service provider注冊了哪些service。
然后把注冊過的service provider標(biāo)記為provided,就是寫入到$serviceProviders[ ]中,而開始是先檢查$serviceProviders[ ]中,有沒有已經(jīng)注冊過的將要注冊的service。看下markAsRegistered()源碼:
protected function markAsRegistered($provider) { $this["events"]->fire($class = get_class($provider), [$provider]); $this->serviceProviders[] = $provider; $this->loadedProviders[$class] = true; }
這里還用了剛注冊的"events" service來觸發(fā)該service provider已經(jīng)注冊的事件,并把該service provider寫入到已經(jīng)加載的屬性中l(wèi)oadedProviders[ ].
然后檢查程序是否已經(jīng)啟動,如果已經(jīng)啟動完成了,再執(zhí)行每一個(gè)service provider中的boot()方法,這里會發(fā)現(xiàn)為啥每一個(gè)service provider里經(jīng)常出現(xiàn)register()和boot()方法,并且register()是注冊服務(wù)的,等所有服務(wù)注冊完,再去boot()一些東西。當(dāng)然,這里程序剛剛注冊第一個(gè)EventServiceProvider,程序離完全啟動還早著呢。不過,可以先看下這里的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),那就通過Container::callClass()來解析出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); }
也就是說,如果call(EventServiceProvider@register)這種方式的話先轉(zhuǎn)化成call([$class, $method], $parameters)來調(diào)用,當(dāng)然要是直接這種方式就不用在轉(zhuǎn)換了。這里是通過[(new EventServiceProvider($app)), "boot"]類似這種方式來調(diào)用的。在調(diào)用boot()時(shí)有依賴怎么辦?使用[$class, $method]通過getMethodDependencies($parameters)來獲取$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(); } }
這里是通過PHP的Reflector Method來獲取依賴,依賴如果是對象的話再繼續(xù)make()自動解析出service,是個(gè)外部傳進(jìn)來的值則代入,有默認(rèn)值傳默認(rèn)值。反射(Reflector)是PHP的一個(gè)重要的高級特性,值得研究。
總的來說,在boot()方法中如果有dependency,container會自動解析,不管該dependency是不是某個(gè)service。這就是Method Injection,我們知道Dependency Injection有兩種:Constructor Injection and Method Injection,這里可看到Method Injection是如何實(shí)現(xiàn)的。
OK,然后看下兩個(gè)service provider注冊了些什么?
首先注冊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注冊到容器中了,并且是單例注冊的??聪聅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ù)組,抽取別名并且注冊到$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)注冊過的名為$abstract的service,當(dāng)然別名數(shù)組也別忘了舍棄。
如果$concrete沒有提供,則使用$abstract自動補(bǔ)全$concrete,并且使用getClosure()封裝下做個(gè)Closure:
protected function getClosure($abstract, $concrete) { // $c 就是$container,即Container Object,會在回調(diào)時(shí)傳遞給這個(gè)變量 return function ($c, $parameters = []) use ($abstract, $concrete) { $method = ($abstract == $concrete) ? "build" : "make"; return $c->$method($concrete, $parameters); }; }
$concrete沒有提供綁定的情況,如:$this->singleton(IlluminateContainerContainer::class); 只提供了$abstract.
這里,就是向$bindings[ ]中注冊下,現(xiàn)在它的值類似這樣:
$bindings = [ "events" => [ "concrete" => function ($app) { return (new Dispatcher($app))->setQueueResolver(function () use ($app) {return $app->make("IlluminateContractsQueueFactory");}); }, "shared" => true, ], ];
已經(jīng)說了singleton()和binding()注冊的區(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中注冊了些什么service?
上文說過,Application中register()會調(diào)用service provider中的register()方法,看下IlluminateRoutingRoutingServiceProvider源碼就發(fā)現(xiàn)其注冊了幾個(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); });
為什么說是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代碼類似于:
$this->app["router"] = new Router($app["events"], $app);
$this->app是Container對象,而Container implement ArrayAccess這個(gè)Interface,實(shí)現(xiàn)對類的屬性做數(shù)組式訪問,所以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);
這里是對$this->app賦值,所以看下offsetSet()源碼:
public function offsetSet($key, $value) { if (! $value instanceof Closure) { $value = function () use ($value) { return $value; }; } $this->bind($key, $value); }
這里是用bind()來綁定到container中,所以上文中說是bind(),而不是其他。所上文的代碼類似于這樣:
$this->app["router"] = new Router($app["events"], $app); is like: $object = new Router($app["events"], $app); $this->bind("router", function () use ($object) {return $object});
總的來說,就是通過注冊EventServiceProvider and RoutingServiceProvider來綁定了一些service, e.g. "events", "router" and so on.
3. Register Core Container Aliases由于PHP使用namespace來命名class,有時(shí)類名很長,所以需要做個(gè)別名alias圖方便。看下registerCoreContainerAliases()的源碼:
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注冊個(gè)別名,并且在相同數(shù)組里有著共同的別名,e.g. "IlluminateFoundationApplication", "IlluminateContractsContainerContainer" and "IlluminateContractsFoundationApplication" share the same alias name "app".
4. Set the Base PathApplication Constructor里需要傳入一個(gè)path這個(gè)原料來構(gòu)造類,這里path是這個(gè)project的當(dāng)前絕對路徑。同時(shí)綁定一些常用的文件夾路徑供將來使用,看下構(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)討論過,所以這里的$instances[ ]類似于這樣:
$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í)例化對象后,再單例綁定Two Kernel and One Exception:
$app->singleton( IlluminateContractsHttpKernel::class, RightCapitalAdminHttpKernel::class ); $app->singleton( IlluminateContractsConsoleKernel::class, RightCapitalAdminConsoleKernel::class ); $app->singleton( IlluminateContractsDebugExceptionHandler::class, RightCapitalAdminExceptionsHandler::class );
最后,就得到一個(gè)塞滿好幾個(gè)service的容器了,而未被實(shí)例化前是個(gè)空Container.整個(gè)的Application的實(shí)例化過程分析就OK了。
總結(jié):本文主要學(xué)習(xí)了Application的實(shí)例化過程,主要學(xué)習(xí)了實(shí)例化過程中向這個(gè)IoC(Inversion of Control) Container綁定了哪些service,并討論了綁定的三個(gè)方法:bind(),singleton(),instance(),解析方法make()留到多帶帶研究Container時(shí)再討論吧。下次分享下Container學(xué)習(xí)心得,并寫上PHPUnit測試,到時(shí)見。
歡迎關(guān)注Laravel-China。
RightCapital招聘Laravel DevOps
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/30448.html
摘要:實(shí)際上的綁定主要有三種方式且只是一種的,這些已經(jīng)在學(xué)習(xí)筆記之實(shí)例化源碼解析聊過,其實(shí)現(xiàn)方法并不復(fù)雜。從以上源碼發(fā)現(xiàn)的反射是個(gè)很好用的技術(shù),這里給出個(gè),看下能干些啥打印結(jié)果太長了,就不粘貼了。 說明:本文主要學(xué)習(xí)Laravel中Container的源碼,主要學(xué)習(xí)Container的綁定和解析過程,和解析過程中的依賴解決。分享自己的研究心得,希望對別人有所幫助。實(shí)際上Container的綁...
摘要:學(xué)習(xí)筆記之已經(jīng)聊過使用了來設(shè)計(jì),看源碼發(fā)現(xiàn)其巧妙用了和的一些數(shù)組函數(shù)來設(shè)計(jì)。開發(fā)環(huán)境內(nèi)置函數(shù)和看源碼之前,先看下這幾個(gè)內(nèi)置函數(shù)的使用。學(xué)習(xí)筆記之實(shí)例化源碼解析已經(jīng)聊過的實(shí)例化,得到中的變量,即的實(shí)例化對象。后面再學(xué)習(xí)下的源碼,到時(shí)見。 說明:本文主要學(xué)習(xí)Laravel的Middleware的源碼設(shè)計(jì)思想,并將學(xué)習(xí)心得分享出來,希望對別人有所幫助。Laravel學(xué)習(xí)筆記之Decorato...
摘要:總結(jié)本文主要學(xué)習(xí)了啟動時(shí)做的七步準(zhǔn)備工作環(huán)境檢測配置加載日志配置異常處理注冊注冊啟動。 說明:Laravel在把Request通過管道Pipeline送入中間件Middleware和路由Router之前,還做了程序的啟動Bootstrap工作,本文主要學(xué)習(xí)相關(guān)源碼,看看Laravel啟動程序做了哪些具體工作,并將個(gè)人的研究心得分享出來,希望對別人有所幫助。Laravel在入口index...
摘要:服務(wù)容器在說容器之前,我們需要了解什么是容器。服務(wù)容器是一個(gè)用于管理類依賴和執(zhí)行依賴注入的強(qiáng)大工具。幾乎所有的服務(wù)容器綁定都是在服務(wù)提供者中完成,也就是在服務(wù)提供者中綁定。 服務(wù)容器 在說 Ioc 容器之前,我們需要了解什么是 Ioc 容器。 Laravel 服務(wù)容器是一個(gè)用于管理類依賴和執(zhí)行依賴注入的強(qiáng)大工具。 在理解這句話之前,我們需要先了解一下服務(wù)容器的來龍去脈: larave...
摘要:哲學(xué)的一個(gè)重要組成部分就是容器,也可以稱為服務(wù)容器。那我們要怎么做呢請看下面的例子數(shù)據(jù)庫連接通過上面的代碼,如果我們想把改成,根本不需要去修改類構(gòu)造函數(shù)里的依賴。現(xiàn)在我要講下容器里到底發(fā)生了什么。 showImg(https://segmentfault.com/img/remote/1460000018868909); IOC 容器是一個(gè)實(shí)現(xiàn)依賴注入的便利機(jī)制 - Taylor?Ot...
閱讀 1987·2021-09-26 10:19
閱讀 3262·2021-09-24 10:25
閱讀 1649·2019-12-27 11:39
閱讀 1933·2019-08-30 15:43
閱讀 675·2019-08-29 16:08
閱讀 3512·2019-08-29 16:07
閱讀 912·2019-08-26 11:30
閱讀 1277·2019-08-26 10:41