摘要:實(shí)例化各服務(wù)提供者,根據(jù)其屬性將服務(wù)進(jìn)行分類延遲服務(wù)即時(shí)服務(wù),從而得到一個(gè)數(shù)組格式如,延遲處理注冊(cè)延遲的服務(wù),以后再進(jìn)行調(diào)用注冊(cè)延遲的事件即時(shí)處理直接進(jìn)行注冊(cè)調(diào)用等,并重新寫入到,然后根據(jù)此文件進(jìn)行相應(yīng)的處理。
Laravel Kernel引導(dǎo)流程分析 代碼展示
protected function sendRequestThroughRouter($request) { # $this->app->instance("request", $request); # Facade::clearResolvedInstance("request"); // 主要是這句代碼 $this->bootstrap(); # return (new Pipeline($this->app)) # ->send($request) # ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) # ->then($this->dispatchToRouter()); } public function bootstrap() { if (! $this->app->hasBeenBootstrapped()) { $this->app->bootstrapWith($this->bootstrappers()); } } protected function bootstrappers() { ##################################################################### #$bootstrappers = [ # IlluminateFoundationBootstrapLoadEnvironmentVariables::class, # IlluminateFoundationBootstrapLoadConfiguration::class, # IlluminateFoundationBootstrapHandleExceptions::class, # IlluminateFoundationBootstrapRegisterFacades::class, # IlluminateFoundationBootstrapRegisterProviders::class, # IlluminateFoundationBootstrapBootProviders::class, #]; ##################################################################### return $this->bootstrappers; } public function bootstrapWith(array $bootstrappers) { $this->hasBeenBootstrapped = true; foreach ($bootstrappers as $bootstrapper) { $this["events"]->fire("bootstrapping: ".$bootstrapper, [$this]); $this->make($bootstrapper)->bootstrap($this); $this["events"]->fire("bootstrapped: ".$bootstrapper, [$this]); } }
$this->make($bootstrapper)->bootstrap($this):會(huì)先創(chuàng)建$bootstrapper對(duì)象,在執(zhí)行對(duì)象的引導(dǎo)方法,參數(shù)為應(yīng)用對(duì)象
處理流程
加載并設(shè)置應(yīng)用的系統(tǒng)環(huán)境變量(IlluminateFoundationBootstrapLoadEnvironmentVariables)
public function bootstrap(Application $app) { // /var/www/laravel/bootstrap/cache/config.php 存在則直接返回 if ($app->configurationIsCached()) { return; } $this->checkForSpecificEnvironmentFile($app); try { // 委托Dotenv來臨時(shí)設(shè)置此次請(qǐng)求的系統(tǒng)環(huán)境變量,默認(rèn)傳參依次為"/var/www/laravel"和".env" (new Dotenv($app->environmentPath(), $app->environmentFile()))->load(); } catch (InvalidPathException $e) { // } } protected function checkForSpecificEnvironmentFile($app) { // cli模式下,并且存在--env參數(shù)(類似命令為: cammond --env=example) if (php_sapi_name() == "cli" && with($input = new ArgvInput)->hasParameterOption("--env")) { // 將系統(tǒng)環(huán)境文件(類似:/var/www/laravel/.env.example)設(shè)置為$app應(yīng)用的environmentFile屬性,供后面使用 $this->setEnvironmentFilePath( $app, $app->environmentFile().".".$input->getParameterOption("--env") ); } if (! env("APP_ENV")) { return; } $this->setEnvironmentFilePath( $app, $app->environmentFile().".".env("APP_ENV") ); }
(new Dotenv($app->environmentPath(), $app->environmentFile()))->load()
public function __construct($path, $file = ".env") { // 類似/var/www/laravel/.env $this->filePath = $this->getFilePath($path, $file); // 創(chuàng)建加載器,委托Loader處理 $this->loader = new Loader($this->filePath, true); } protected function getFilePath($path, $file) { if (!is_string($file)) { $file = ".env"; } $filePath = rtrim($path, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.$file; return $filePath; } public function load() { return $this->loadData(); } protected function loadData($overload = false) { $this->loader = new Loader($this->filePath, !$overload); return $this->loader->load(); }
new Loader($this->filePath, !$overload)
public function __construct($filePath, $immutable = false) { $this->filePath = $filePath; $this->immutable = $immutable; } public function load() { $this->ensureFileIsReadable(); $filePath = $this->filePath; $lines = $this->readLinesFromFile($filePath); foreach ($lines as $line) { // 如果行不是注釋行且含有=號(hào),則進(jìn)行 if (!$this->isComment($line) && $this->looksLikeSetter($line)) { $this->setEnvironmentVariable($line); } } return $lines; } // 將文件按行的形式讀入到數(shù)組并返回 protected function readLinesFromFile($filePath) { $autodetect = ini_get("auto_detect_line_endings"); ini_set("auto_detect_line_endings", "1"); $lines = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); ini_set("auto_detect_line_endings", $autodetect); return $lines; } public function setEnvironmentVariable($name, $value = null) { // 檢測(cè)過濾校驗(yàn)環(huán)境變量 list($name, $value) = $this->normaliseEnvironmentVariable($name, $value); // 當(dāng)immutable為真時(shí),不覆蓋對(duì)應(yīng)的環(huán)境變量 if ($this->immutable && $this->getEnvironmentVariable($name) !== null) { return; } // apache運(yùn)行環(huán)境下,嘗試臨時(shí)覆蓋系統(tǒng)環(huán)境變量 if (function_exists("apache_getenv") && function_exists("apache_setenv") && apache_getenv($name)) { apache_setenv($name, $value); } // 嘗試臨時(shí)設(shè)置當(dāng)前請(qǐng)求的系統(tǒng)環(huán)境變量 if (function_exists("putenv")) { putenv("$name=$value"); } // 賦值全局變量 $_ENV[$name] = $value; $_SERVER[$name] = $value; }
將應(yīng)用配置文件目錄(/var/www/laravel/config)下所有php文件返回的數(shù)組載入到$config對(duì)象(IlluminateFoundationBootstrapLoadConfiguration)
public function bootstrap(Application $app) { $items = []; // /var/www/laravel/bootstrap/cache/config.php文件[配置文件的緩存合集,加快加載速度]存在則載入,并標(biāo)記已加載 if (file_exists($cached = $app->getCachedConfigPath())) { $items = require $cached; $loadedFromCache = true; } // 構(gòu)建config對(duì)象,并注入到服務(wù)容器 $app->instance("config", $config = new Repository($items)); if (! isset($loadedFromCache)) { // 將系統(tǒng)的配置文件載入到$config對(duì)象 $this->loadConfigurationFiles($app, $config); } // 設(shè)置$this["env"]為系統(tǒng)環(huán)境變量app.env,沒有則默認(rèn)為production $app->detectEnvironment(function () use ($config) { return $config->get("app.env", "production"); }); date_default_timezone_set($config->get("app.timezone", "UTC")); mb_internal_encoding("UTF-8"); } $config = new IlluminateConfigRepository($items) public function __construct(array $items = []) { $this->items = $items; } protected function loadConfigurationFiles(Application $app, RepositoryContract $repository) { foreach ($this->getConfigurationFiles($app) as $key => $path) { // 此操作將在$repository對(duì)象里面構(gòu)造一個(gè)多維數(shù)組屬性$this->items,值為相應(yīng)的系統(tǒng)配置文件返回的數(shù)組,后續(xù)可以直接通過get獲取 $repository->set($key, require $path); } } /** $files數(shù)組形式如下 [ "app" => "/var/www/laravel/config/app.php", "auth" => "/var/www/laravel/config/auth.php", "xx.file" => "/var/www/laravel/config/xx/file.php", "xx.yy.file" => "/var/www/laravel/config/xx/yy/file.php", ] */ protected function getConfigurationFiles(Application $app) { $files = []; // 系統(tǒng)配置文件的路徑(/var/www/laravel/config) $configPath = realpath($app->configPath()); // 文件相關(guān)的操作委托給Finder類(很強(qiáng)大)來處理,F(xiàn)inder實(shí)現(xiàn)了IteratorAggregate的getIterator方法 foreach (Finder::create()->files()->name("*.php")->in($configPath) as $file) { // 迭代/var/www/laravel/config下面嵌套的層層子目錄構(gòu)造成.形式的目錄 $directory = $this->getNestedDirectory($file, $configPath); $files[$directory.basename($file->getRealPath(), ".php")] = $file->getRealPath(); } return $files; } $repository->set($key, require $path) // 構(gòu)造將.形式轉(zhuǎn)變?yōu)橄鄳?yīng)層級(jí)的數(shù)組$this->items。比如:$key="xx.yy.file",$value="/var/www/laravel/config/xx/yy/file.php",將會(huì)構(gòu)建為:$this->items["xx"]["yy"]["file"] = $value返回的數(shù)組。 public function set($key, $value = null) { $keys = is_array($key) ? $key : [$key => $value]; foreach ($keys as $key => $value) { Arr::set($this->items, $key, $value); } }
根據(jù)默認(rèn)的系統(tǒng)配置文件目錄,以上操作的結(jié)果如下:
$config對(duì)象(new Repository)里面的$this->items數(shù)組屬性,后期可以通過$config->get()來獲取
$this->items["app"] = /var/www/laravel/config/app.php返回的數(shù)組; $this->items["auth"] = /var/www/laravel/config/auth.php返回的數(shù)組; $this->items["broadcasting"] = /var/www/laravel/config/broadcasting.php返回的數(shù)組; $this->items["cache"] = /var/www/laravel/config/cache.php返回的數(shù)組; $this->items["database"] = /var/www/laravel/config/database.php返回的數(shù)組; $this->items["filesystems"] = /var/www/laravel/config/filesystems.php返回的數(shù)組; $this->items["mail"] = /var/www/laravel/config/mail.php返回的數(shù)組; $this->items["queue"] = /var/www/laravel/config/queue.php返回的數(shù)組; $this->items["services"] = /var/www/laravel/config/services.php返回的數(shù)組; $this->items["session"] = /var/www/laravel/config/session.php返回的數(shù)組; $this->items["view"] = /var/www/laravel/config/view.php返回的數(shù)組; 假如有這樣的文件(/var/www/laravel/config/xx/yy/zz/file.php),返回["a"=>"hello,world!"]數(shù)組 將得到:$this->items["xx"]["yy"]["zz"]["file"] = ["a"=>"hello,world!"]; 獲取方式: $config->get("xx.yy.zz.file.a", $default),直接返回"hello,world!";
設(shè)置應(yīng)用的錯(cuò)誤異常等處理事件(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"]); if (! $app->environment("testing")) { ini_set("display_errors", "Off"); } } public function handleError($level, $message, $file = "", $line = 0, $context = []) { if (error_reporting() & $level) { throw new ErrorException($message, 0, $level, $file, $line); } } public function handleException($e) { if (! $e instanceof Exception) { $e = new FatalThrowableError($e); } $this->getExceptionHandler()->report($e); if ($this->app->runningInConsole()) { $this->renderForConsole($e); } else { $this->renderHttpResponse($e); } } // 核心代碼,獲取的AppExceptionsHandle對(duì)象 protected function getExceptionHandler() { // make時(shí)將會(huì)直接調(diào)用$this->bindings["IlluminateContractsDebugExceptionHandler"]["concrete"](此代碼位于/var/www/laravel/bootstrap/app.php,應(yīng)用對(duì)象化后,直接注入到服務(wù)容器的幾個(gè)單例),返回AppExceptionsHandle對(duì)象,并將此對(duì)象注入到服務(wù)容器[參考] return $this->app->make(ExceptionHandler::class); } protected function renderHttpResponse(Exception $e) { $this->getExceptionHandler()->render($this->app["request"], $e)->send(); } // AppExceptionsHandle public function render($request, Exception $e) { $e = $this->prepareException($e); if ($e instanceof HttpResponseException) { return $e->getResponse(); } elseif ($e instanceof AuthenticationException) { return $this->unauthenticated($request, $e); } elseif ($e instanceof ValidationException) { return $this->convertValidationExceptionToResponse($e, $request); } return $this->prepareResponse($request, $e); } protected function renderHttpException(HttpException $e) { $status = $e->getStatusCode(); view()->replaceNamespace("errors", [ resource_path("views/errors"), __DIR__."/views", ]); if (view()->exists("errors::{$status}")) { return response()->view("errors::{$status}", ["exception" => $e], $status, $e->getHeaders()); } else { return $this->convertExceptionToResponse($e); } } public function handleShutdown() { if (! is_null($error = error_get_last()) && $this->isFatal($error["type"])) { $this->handleException($this->fatalExceptionFromError($error, 0)); } }
根據(jù)配置項(xiàng)設(shè)置應(yīng)用的 Facades(IlluminateFoundationBootstrapRegisterFacades)
public function bootstrap(Application $app) { Facade::clearResolvedInstances(); Facade::setFacadeApplication($app); // 將配置文件/var/www/laravel/config/app.php返回?cái)?shù)組的鍵為aliases的值賦給IlluminateFoundationAliasLoader的aliases屬性,并進(jìn)行注冊(cè) AliasLoader::getInstance($app->make("config")->get("app.aliases", []))->register(); } public static function clearResolvedInstances() { static::$resolvedInstance = []; } public static function setFacadeApplication($app) { static::$app = $app; } IlluminateFoundationAliasLoader public static function getInstance(array $aliases = []) { if (is_null(static::$instance)) { return static::$instance = new static($aliases); } $aliases = array_merge(static::$instance->getAliases(), $aliases); static::$instance->setAliases($aliases); return static::$instance; } private function __construct($aliases) { $this->aliases = $aliases; } public function getAliases() { return $this->aliases; } public function setAliases(array $aliases) { $this->aliases = $aliases; } public function register() { if (! $this->registered) { $this->prependToLoaderStack(); $this->registered = true; } } protected function prependToLoaderStack() { // 將$this->load注冊(cè)到自動(dòng)加載器的最前面,失敗時(shí)拋異常 spl_autoload_register([$this, "load"], true, true); } public function load($alias) { // $facadeNamespace = "Facades",估計(jì)是框架內(nèi)部使用的,以后再看吧 if (static::$facadeNamespace && strpos($alias, static::$facadeNamespace) === 0) { $this->loadFacade($alias); return true; } if (isset($this->aliases[$alias])) { return class_alias($this->aliases[$alias], $alias); } }
Facade的本質(zhì)
實(shí)際上是通過$app->make("config")->get("app.aliases", [])取出config/app.php文件里面的aliases數(shù)組并實(shí)例化AliasLoader,再將AliasLoader->load方法放到spl自動(dòng)加載器最前面,最后通過class_alias($this->aliases[$alias], $alias)。當(dāng)調(diào)用Cache::Method時(shí),會(huì)觸發(fā)Facdes的__callStatic魔術(shù)方法,此方法會(huì)調(diào)用相應(yīng)對(duì)象里面的方法。
注入配置項(xiàng)的服務(wù)提供者(IlluminateFoundationBootstrapRegisterProviders)
public function bootstrap(Application $app) { $app->registerConfiguredProviders(); } public function registerConfiguredProviders() { (new ProviderRepository($this, new Filesystem, $this->getCachedServicesPath())) ->load($this->config["app.providers"]); } public function getCachedServicesPath() { return $this->bootstrapPath()."/cache/services.php"; } // 先取services緩存文件,再對(duì)IlluminateFoundationProviderRepository進(jìn)行實(shí)例化,隨后加載系統(tǒng)配置文件(./config/app.php)里面的providers數(shù)組 (new ProviderRepository($this, new Filesystem, $this->getCachedServicesPath())) ->load($this->config["app.providers"]) public function __construct(ApplicationContract $app, Filesystem $files, $manifestPath) { $this->app = $app; $this->files = $files; $this->manifestPath = $manifestPath; } public function load(array $providers) { $manifest = $this->loadManifest(); if ($this->shouldRecompile($manifest, $providers)) { $manifest = $this->compileManifest($providers); } foreach ($manifest["when"] as $provider => $events) { $this->registerLoadEvents($provider, $events); } foreach ($manifest["eager"] as $provider) { // 直接注冊(cè)服務(wù)(將直接調(diào)用服務(wù)的register方法) $this->app->register($provider); } $this->app->addDeferredServices($manifest["deferred"]); } public function loadManifest() { if ($this->files->exists($this->manifestPath)) { $manifest = $this->files->getRequire($this->manifestPath); if ($manifest) { return array_merge(["when" => []], $manifest); } } } public function shouldRecompile($manifest, $providers) { return is_null($manifest) || $manifest["providers"] != $providers; } protected function compileManifest($providers) { $manifest = $this->freshManifest($providers); foreach ($providers as $provider) { $instance = $this->createProvider($provider); // 延遲加載的服務(wù) if ($instance->isDeferred()) { foreach ($instance->provides() as $service) { $manifest["deferred"][$service] = $provider; } // 注冊(cè)延遲的事件 $manifest["when"][$provider] = $instance->when(); } // 即時(shí)加載的服務(wù) else { $manifest["eager"][] = $provider; } } return $this->writeManifest($manifest); } protected function freshManifest(array $providers) { return ["providers" => $providers, "eager" => [], "deferred" => []]; } public function createProvider($provider) { return new $provider($this->app); } public function isDeferred() { return $this->defer; } public function writeManifest($manifest) { if (! is_writable(dirname($this->manifestPath))) { throw new Exception("The bootstrap/cache directory must be present and writable."); } $this->files->put( $this->manifestPath, " []], $manifest); } protected function registerLoadEvents($provider, array $events) { if (count($events) < 1) { return; } $this->app->make("events")->listen($events, function () use ($provider) { $this->app->register($provider); }); } public function addDeferredServices(array $services) { $this->deferredServices = array_merge($this->deferredServices, $services); }
大致流程
通過/var/www/laravel/bootstrap/cache/services.php等實(shí)例化IlluminateFoundationProviderRepository,并加載$this->config["app.providers"]數(shù)組。實(shí)例化app.providers各服務(wù)提供者,根據(jù)其defer屬性將服務(wù)進(jìn)行分類(延遲服務(wù)|即時(shí)服務(wù)),從而得到一個(gè)$manifest數(shù)組(格式如services.php,延遲處理:deferred=>注冊(cè)延遲的服務(wù),以后再進(jìn)行調(diào)用;when=>注冊(cè)延遲的事件;即時(shí)處理:eager=>直接進(jìn)行注冊(cè)調(diào)用等),并重新寫入到services.php,然后根據(jù)此文件進(jìn)行相應(yīng)的處理。
啟動(dòng)服務(wù)提供者的boot方法等操作(IlluminateFoundationBootstrapBootProviders)
public function bootstrap(Application $app) { $app->boot(); } public function boot() { if ($this->booted) { return; } // 可以通過應(yīng)用的booting方法來注冊(cè)服務(wù)啟動(dòng)前的事件監(jiān)聽者 $this->fireAppCallbacks($this->bootingCallbacks); // 嘗試調(diào)用所有的服務(wù)提供者的boot方法 array_walk($this->serviceProviders, function ($p) { $this->bootProvider($p); }); $this->booted = true; // 可以通過應(yīng)用的booted方法來注冊(cè)服務(wù)啟動(dòng)后的事件監(jiān)聽者,若已經(jīng)啟用了,則直接出發(fā)事件 $this->fireAppCallbacks($this->bootedCallbacks); } protected function fireAppCallbacks(array $callbacks) { foreach ($callbacks as $callback) { call_user_func($callback, $this); } } protected function bootProvider(ServiceProvider $provider) { if (method_exists($provider, "boot")) { return $this->call([$provider, "boot"]); } }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/22606.html
摘要:請(qǐng)求周期加載自動(dòng)加載器獲取應(yīng)用對(duì)象實(shí)例化應(yīng)用解析此對(duì)象貫穿全文主要過程設(shè)置基礎(chǔ)路徑基礎(chǔ)綁定注冊(cè)全局基礎(chǔ)服務(wù)核心容器別名設(shè)置注冊(cè)三個(gè)單例獲取對(duì)象實(shí)例化此對(duì)象為應(yīng)用的樞紐,將會(huì)協(xié)調(diào)各部分之間的工作,完成請(qǐng)求主要過程注入應(yīng)用對(duì)象注入事件對(duì)象注入 Laravel 請(qǐng)求周期 加載 composer 自動(dòng)加載器 require __DIR__./../bootstrap/autoload.php;...
摘要:應(yīng)用實(shí)例所依賴的服務(wù)提供者可以在配置文件中的節(jié)點(diǎn)找到。完成所有服務(wù)提供者注冊(cè)到應(yīng)用實(shí)例后,應(yīng)用實(shí)例執(zhí)行啟動(dòng)方法引導(dǎo)項(xiàng)目啟動(dòng)?;騼?nèi)核接收到請(qǐng)求,加載服務(wù)提供者,同時(shí),將請(qǐng)求分發(fā)給路由器執(zhí)行。 這是一篇翻譯文章,原文 Request Life Cycle of Laravel,譯文 Laravel 請(qǐng)求生命周期 首發(fā)于個(gè)人博客,轉(zhuǎn)載請(qǐng)注明出處。 當(dāng)需要使用一個(gè)框架、工具或者服務(wù)時(shí),在使用前...
摘要:直到所有中間件都執(zhí)行完畢,最后在執(zhí)行最后的即上述的方法如果上述有地方難懂的,可以參考這邊文章內(nèi)置函數(shù)在中的使用以上是在通過全局中間件時(shí)的大致流程,通過中間件和路由中間件也是一樣的,都是采用管道流操作,詳情可翻閱源碼 簡介 Laravel 中間件提供了一種方便的機(jī)制來過濾進(jìn)入應(yīng)用的 HTTP 請(qǐng)求, 如ValidatePostSize用來驗(yàn)證POST請(qǐng)求體大小、ThrottleReque...
摘要:所以就是對(duì)象其他的都是類似的。和一樣,既可以數(shù)組形式訪問,也可以按對(duì)象方式訪問。大體流程是創(chuàng)建獲取請(qǐng)求對(duì)象包括請(qǐng)求頭和請(qǐng)求體注入請(qǐng)求對(duì)象到服務(wù)容器配置系統(tǒng)運(yùn)行環(huán)境發(fā)送請(qǐng)求 Laravel Kernel實(shí)例化后的處理 $response = $kernel->handle( $request = IlluminateHttpRequest::capture() ); 創(chuàng)建并獲取...
摘要:調(diào)用了的可以看出,所有服務(wù)提供器都在配置文件文件的數(shù)組中。啟動(dòng)的啟動(dòng)由類負(fù)責(zé)引導(dǎo)應(yīng)用的屬性中記錄的所有服務(wù)提供器,就是依次調(diào)用這些服務(wù)提供器的方法,引導(dǎo)完成后就代表應(yīng)用正式啟動(dòng)了,可以開始處理請(qǐng)求了。 服務(wù)提供器是所有 Laravel 應(yīng)用程序引導(dǎo)中心。你的應(yīng)用程序自定義的服務(wù)、第三方資源包提供的服務(wù)以及 Laravel 的所有核心服務(wù)都是通過服務(wù)提供器進(jìn)行注冊(cè)(register)和引...
閱讀 1276·2021-11-24 09:39
閱讀 1533·2021-09-07 09:59
閱讀 3490·2019-08-30 15:54
閱讀 2486·2019-08-30 11:00
閱讀 2678·2019-08-29 15:06
閱讀 2169·2019-08-26 13:52
閱讀 438·2019-08-26 13:24
閱讀 2504·2019-08-26 12:20