摘要:其中設置請求是唯一區別于內核的一個引導程序。和命令行腳本的規范一樣,如果執行命令任務程序成功會返回拋出異常退出則返回。嚴格遵循了面向對象程序設計的原則。
Console內核
上一篇文章我們介紹了Laravel的HTTP內核,詳細概述了網絡請求從進入應用到應用處理完請求返回HTTP響應整個生命周期中HTTP內核是如何調動Laravel各個核心組件來完成任務的。除了處理HTTP請求一個健壯的應用經常還會需要執行計劃任務、異步隊列這些。Laravel為了能讓應用滿足這些場景設計了artisan工具,通過artisan工具定義各種命令來滿足非HTTP請求的各種場景,artisan命令通過Laravel的Console內核來完成對應用核心組件的調度來完成任務。 今天我們就來學習一下Laravel Console內核的核心代碼。
內核綁定跟HTTP內核一樣,在應用初始化階有一個內核綁定的過程,將Console內核注冊到應用的服務容器里去,還是引用上一篇文章引用過的bootstrap/app.php里的代碼
singleton( IlluminateContractsHttpKernel::class, AppHttpKernel::class ); // console內核綁定 $app->singleton( IlluminateContractsConsoleKernel::class, AppConsoleKernel::class ); $app->singleton( IlluminateContractsDebugExceptionHandler::class, AppExceptionsHandler::class ); return $app;
Console內核 AppConsoleKernel繼承自IlluminateFoundationConsole, 在Console內核中我們可以注冊artisan命令和定義應用里要執行的計劃任務。
/** * Define the application"s command schedule. * * @param IlluminateConsoleSchedulingSchedule $schedule * @return void */ protected function schedule(Schedule $schedule) { // $schedule->command("inspire") // ->hourly(); } /** * Register the commands for the application. * * @return void */ protected function commands() { $this->load(__DIR__."/Commands"); require base_path("routes/console.php"); }
在實例化Console內核的時候,內核會定義應用的命令計劃任務(shedule方法中定義的計劃任務)
public function __construct(Application $app, Dispatcher $events) { if (! defined("ARTISAN_BINARY")) { define("ARTISAN_BINARY", "artisan"); } $this->app = $app; $this->events = $events; $this->app->booted(function () { $this->defineConsoleSchedule(); }); }應用解析Console內核
查看aritisan文件的源碼我們可以看到, 完成Console內核綁定的綁定后,接下來就會通過服務容器解析出console內核對象
$kernel = $app->make(IlluminateContractsConsoleKernel::class); $status = $kernel->handle( $input = new SymfonyComponentConsoleInputArgvInput, new SymfonyComponentConsoleOutputConsoleOutput );執行命令任務
解析出Console內核對象后,接下來就要處理來自命令行的命令請求了, 我們都知道PHP是通過全局變量$_SERVER["argv"]來接收所有的命令行輸入的, 和命令行里執行shell腳本一樣(在shell腳本里可以通過$0獲取腳本文件名,$1 $2這些依次獲取后面傳遞給shell腳本的參數選項)索引0對應的是腳本文件名,接下來依次是命令行里傳遞給腳本的所有參數選項,所以在命令行里通過artisan腳本執行的命令,在artisan腳本中$_SERVER["argv"]數組里索引0對應的永遠是artisan這個字符串,命令行里后面的參數會依次對應到$_SERVER["argv"]數組后續的元素里。
因為artisan命令的語法中可以指定命令參數選項、有的選項還可以指定實參,為了減少命令行輸入參數解析的復雜度,Laravel使用了SymfonyComponentConsoleInput對象來解析命令行里這些參數選項(shell腳本里其實也是一樣,會通過shell函數getopts來解析各種格式的命令行參數輸入),同樣地Laravel使用了SymfonyComponentConsoleOutput對象來抽象化命令行的標準輸出。
引導應用在Console內核的handle方法里我們可以看到和HTTP內核處理請求前使用bootstrapper程序引用應用一樣在開始處理命令任務之前也會有引導應用這一步操作
其父類 「IlluminateFoundationConsoleKernel」 內部定義了屬性名為 「bootstrappers」 的 引導程序 數組:
protected $bootstrappers = [ IlluminateFoundationBootstrapLoadEnvironmentVariables::class, IlluminateFoundationBootstrapLoadConfiguration::class, IlluminateFoundationBootstrapHandleExceptions::class, IlluminateFoundationBootstrapRegisterFacades::class, IlluminateFoundationBootstrapSetRequestForConsole::class, IlluminateFoundationBootstrapRegisterProviders::class, IlluminateFoundationBootstrapBootProviders::class, ];
數組中包括的引導程序基本上和HTTP內核中定義的引導程序一樣, 都是應用在初始化階段要進行的環境變量、配置文件加載、注冊異常處理器、設置Console請求、注冊應用中的服務容器、Facade和啟動服務。其中設置Console請求是唯一區別于HTTP內核的一個引導程序。
執行命令執行命令是通過Console Application來執行的,它繼承自Symfony框架的SymfonyComponentConsoleApplication類, 通過對應的run方法來執行命令。
name IlluminateFoundationConsole; class Kernel implements KernelContract { public function handle($input, $output = null) { try { $this->bootstrap(); return $this->getArtisan()->run($input, $output); } catch (Exception $e) { $this->reportException($e); $this->renderException($output, $e); return 1; } catch (Throwable $e) { $e = new FatalThrowableError($e); $this->reportException($e); $this->renderException($output, $e); return 1; } } } namespace SymfonyComponentConsole; class Application { //執行命令 public function run(InputInterface $input = null, OutputInterface $output = null) { ...... try { $exitCode = $this->doRun($input, $output); } catch { ...... } ...... return $exitCode; } public function doRun(InputInterface $input, OutputInterface $output) { //解析出命令名稱 $name = $this->getCommandName($input); //解析出入參 if (!$name) { $name = $this->defaultCommand; $definition = $this->getDefinition(); $definition->setArguments(array_merge( $definition->getArguments(), array( "command" => new InputArgument("command", InputArgument::OPTIONAL, $definition->getArgument("command")->getDescription(), $name), ) )); } ...... try { //通過命令名稱查找出命令類(命名空間、類名等) $command = $this->find($name); } ...... //運行命令類 $exitCode = $this->doRunCommand($command, $input, $output); return $exitCode; } protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output) { ...... //執行命令類的run方法來處理任務 $exitCode = $command->run($input, $output); ...... return $exitcode; } }
執行命令時主要有三步操作:
通過命令行輸入解析出命令名稱和參數選項。
通過命令名稱查找命令類的命名空間和類名。
執行命令類的run方法來完成任務處理并返回狀態碼。
和命令行腳本的規范一樣,如果執行命令任務程序成功會返回0, 拋出異常退出則返回1。
還有就是打開命令類后我們可以看到并沒有run方法,我們把處理邏輯都寫在了handle方法中,仔細查看代碼會發現run方法定義在父類中,在run方法會中會調用子類中定義的handle方法來完成任務處理。 嚴格遵循了面向對象程序設計的SOLID 原則。
結束應用執行完命令程序返回狀態碼后, 在artisan中會直接通過exit($status)函數輸出狀態碼并結束PHP進程,接下來shell進程會根據返回的狀態碼是否為0來判斷腳本命令是否執行成功。
到這里通過命令行開啟的程序進程到這里就結束了,跟HTTP內核一樣Console內核在整個生命周期中也是負責調度,只不過Http內核最終將請求落地到了Controller程序中而Console內核則是將命令行請求落地到了Laravel中定義的各種命令類程序中,然后在命令類里面我們就可以寫其他程序一樣自由地使用Laravel中的各個組件和注冊到服務容器里的服務了。
本文已經收錄在系列文章Laravel源碼學習里。
也歡迎關注我的公眾號 網管叨bi叨 ,最近正在籌備準備分享一些日常工作里學到和總結的技術知識,也會分享一些見聞和學習英語的方法。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/29725.html
摘要:終止程序終止中間件內核的方法會調用中間件的方法,調用完成后從請求進來到返回響應整個應用程序的生命周期就結束了。 Http Kernel Http Kernel是Laravel中用來串聯框架的各個核心組件來網絡請求的,簡單的說只要是通過public/index.php來啟動框架的都會用到Http Kernel,而另外的類似通過artisan命令、計劃任務、隊列啟動框架進行處理的都會用到C...
摘要:過去一年時間寫了多篇文章來探討了我認為的框架最核心部分的設計思路代碼實現。為了大家閱讀方便,我把這些源碼學習的文章匯總到這里。數據庫算法和數據結構這些都是編程的內功,只有內功深厚了才能解決遇到的復雜問題。 過去一年時間寫了20多篇文章來探討了我認為的Larave框架最核心部分的設計思路、代碼實現。通過更新文章自己在軟件設計、文字表達方面都有所提高,在剛開始決定寫Laravel源碼分析地...
摘要:的契約是一組定義框架提供的核心服務的接口,例如我們在介紹用戶認證的章節中到的用戶看守器契約和用戶提供器契約以及框架自帶的模型所實現的契約。接口與團隊開發當你的團隊在開發大型應用時,不同的部分有著不同的開發速度。 Contracts Laravel 的契約是一組定義框架提供的核心服務的接口, 例如我們在介紹用戶認證的章節中到的用戶看守器契約IllumninateContractsAuth...
摘要:簡述的生命周期采用了單一入口模式,應用的所有請求入口都是文件。分發請求一旦應用完成引導和所有服務提供者都注冊完成,將會移交給路由進行分發。此外,由于對動態方法的獨特用法,也使測試起來非常容易。 本書的 GitHub 地址:https://github.com/todayqq/PH... Laravel 作為現在最流行的 PHP 框架,其中的知識較多,所以單獨拿出來寫一篇。 簡述 La...
摘要:系統的核心是由的認證組件的看守器和提供器組成。使用的認證系統,幾乎所有東西都已經為你配置好了。其配置文件位于,其中包含了用于調整認證服務行為的注釋清晰的選項配置。 用戶認證系統(基礎介紹) 使用過Laravel的開發者都知道,Laravel自帶了一個認證系統來提供基本的用戶注冊、登錄、認證、找回密碼,如果Auth系統里提供的基礎功能不滿足需求還可以很方便的在這些基礎功能上進行擴展。這篇...
閱讀 1318·2021-11-15 11:37
閱讀 2575·2021-09-22 10:56
閱讀 3399·2021-09-06 15:11
閱讀 811·2021-08-31 09:45
閱讀 2910·2021-07-28 11:16
閱讀 1815·2019-08-30 15:44
閱讀 484·2019-08-30 13:22
閱讀 3352·2019-08-30 13:18