先說幾句廢話,調和氣氛。事情的起由來自客戶需求頻繁變更,偉大的師傅決定橫刀立馬的改革使用新的框架(created by 師傅)。在他老人家為時半小時對其新框架代碼目錄簡要的講解后,我依然一臉懵逼(準確來講,他可能最需要只是鄙人快速上手,照貓畫虎,知道HOW就行了,迅速完成代碼改造TODO。)
而我一臉懵逼的原因是:對于照貓畫虎,迅速完成TODO我還是自信可以的,但我真正感冒的并不是這個,依我的性格,要么已經知道why了,沒必要再去考究,為了工期迅速完成工作(如果能有所改革,那最好不過了。);要么不知道why,慢慢的探索研究,發現樂趣并同時完成工作;但要我如盲人摸象一樣,茫茫然的重復勞動,我一定是會拒絕的。。。工期嘛,科科。。。就是這么草率。。。(據說該新框架是聚百家之所長的雜糅產物,既有Laravel的優雅知性,又兼具CI的簡潔明了,但木有文檔。。。。。無論如何,出于好奇心,我還是一腔雞血的開始了膜拜師傅偉大的框架的進程~~
新框架的知曉過程:首先,粗糙的瀏覽了下其文件目錄結構,同laravel類似,其所有應用請求的入口是backend/index.php,它做了這些事:1.Composer的自動加載;2. 設置路由規則,可能由于未看過其vendor中源代碼,看起來略有不適;3. loadAllControllersInDirectoryAsCI 呃,加載控制器目錄?估計是為了命名空間?(待嘗試以驗證)4. handleRequestThroughAdah處理應用請求; 其次,暫且不探究這讓我略奇怪的路由規則(maybe 我太渣)和黑盒子中如何處理響應請求的,在悠悠的看了剩余的目錄結構外,只能說:照貓畫虎的用還是能用的,但這不順手的不適感若不去除,我很難過。。。。所以我想是不是因為我幾乎沒怎么接觸過laravel框架的緣故?
Laravel框架的工作原理
快速的根據文檔https://docs.golaravel.com/docs/5.4/lifecycle/#focus-on-service-providers, 簡明扼要的全面了解下Laravel的工作原理。
請求入口
一個 Laravel 應用的所有請求的入口都是public/index.php文件。index.php做了這幾件事:1.載入 Composer 生成的自動加載器定義, /vendor/autoload.php(至于composer自動加載的奧妙此處暫不詳解);2. bootstrap/app.php文件獲取到 Laravel 應用實例。3. 創建一個自身應用實例 /服務容器,然后handle request 、send response and terminate.
tip:關于類自動加載的具體細節可參見博客文章:http://www.cnblogs.com/lpfuture/p/5578274.html,我們直接關注laravel的核心:服務容器。
服務容器
服務容器,也叫IOC容器,其實包含了依賴注入(DI)和控制反轉(IOC)兩部分,是laravel的真正核心。而larvavel的其他各種功能模塊比如 Route(路由)、Eloquent ORM(數據庫 ORM 組件)、Request and Response(請求和響應)等等,實際上都是與核心無關的類模塊提供的,這些類從注冊到實例化,最終被你所使用,其實都是 laravel 的服務容器負責的。服務容器的概念我們一步步來解釋:
IOC容器誕生的故事——石器時代(原始模式)
舉個荔枝,我們有一個“超人”類,超人肯定擁有不止一個超能力,這些超能力可以抽象化定義為一個個描述它的類,比如一個超能力肯定有多種屬性、(操作)方法等。。。目前,我們先大致定義個超能力的“力量”類,然后讓“超人”類在構造函數中被賦予“力量”的超能力,形勢如下:
我們看到了一點,“超人”和“力量類”之間不可避免的產生了一個依賴。這種依賴在面向對象編程項目中是隨處可見的,少量的依賴并不會有太過直觀的影響,我們隨著這個例子逐漸鋪開,大家會慢慢意識到當依賴達到一個量級時,是怎樣一番噩夢般的體驗。
現在我們將超能力繼續多元化,假設超人還可以具有以下多種超能力,那么超人現在的形式如下:
飛行,屬性有:飛行速度、持續飛行時間
力量,屬性是力量值
能量彈,屬性有:傷害值、射擊距離、同時射擊個數
我們要手動在構造函數(或其他方法)內實例化一系列需要的類,這樣:增加或者變更超能力時,必須重新改造超人。這時,有人靈機一動想到:既然超人的能力可以被隨時更換,為何不做成添加或者更新一個芯片呢?
IOC容器誕生的故事——青銅時代(工廠模式)
此時,我們不再在“超人”類中固化 “超能力” 初始化的行為,而轉由外部負責,由外部創造超能力模組、裝置或者芯片等(我們后面統一稱為 “模組”),植入超人體內的某一個接口,這個接口是一個既定的,只要這個 “模組” 滿足這個接口的裝置都可以被超人所利用,可以提升、增加超人的某一種能力。這種由外部負責其依賴需求的行為,我們可以稱其為 “控制反轉(IOC)”。
工廠模式,顧名思義,就是一個類所以依賴的外部事物的實例,都可以被一個或多個 “工廠” 創建的這樣一種開發模式,就是 “工廠模式”。我們為了給超人制造超能力模組,我們創建了一個工廠,它可以制造各種各樣的模組,且僅需要通過一個方法:
諾,現在,“超人” 的創建不再依賴任何一個 “超能力” 的類,我們如若修改了或者增加了新的超能力,只需要針對修改 SuperModuleFactory 即可。擴充超能力的同時不再需要重新編輯超人的類文件,但是,這才剛剛開始。
IOC容器誕生的故事——鐵器時代(依賴注入)
正如我們所看到的,由“超人”對“超能力”的依賴變成超人“超能力模組工廠”的依賴后,對付小怪獸更加得心應手,但依賴并未解除,假如工廠出了點麻煩,問題就變得很棘手。
多數情況下,工廠模式已經足夠了,但工廠模式的缺點是:接口未知(沒有契約模型)、產生對象單一。由于工廠模式下,所有的模組都已經在工廠中安排好了(統一的接口),如果有新的、高級模組加入時,我們必須修改工廠類(類似增加新的生產線)。噩夢即將到來,引入我們的主要配角:DI(依賴注入)。
由于對超能力模組的需求不斷增大,擴展生產線倒是其次的,重要的是高智商的大神們創造出的超能力模組沒有統一的接口,自然而然無法被正常使用。這時我們需要提出一種契約,這樣無論是誰創造出的模組,都符合這樣的接口,自然就可被正常使用,然后有了如下形式。
這樣我們可以創造多個超人,分別注入需要的超能力模組即可(雖然一個超人只有一個超能力。。。。。)
現在你可能會疑問,說好的重要配角“依賴注入”呢?其實,本文從開頭到現在提到的一系列依賴,只要不是由內部生產(比如初始化、構造函數 __construct 中通過工廠方法、自行手動 new 的),而是由外部以參數或其他形式注入的,都屬于 依賴注入(DI) 。事實上,就是這么簡單。下面就是一個典型的依賴注入:
理解了依賴注入,我們就可以繼續深入問題。慢慢走近今天的主角……
IOC容器誕生的故事——科技時代(IOC容器)
回頭看看上面“鐵器時代”手動創建超人并注入剛剛創建的超能力模組,手動。。。,顯然,我們其實還是更多的自動化。這種更為高級的工廠,就是工廠模式的升華 —— IOC容器,形式如下:
這就是一個粗糙的容器,有點摸不著頭腦,來,我們先看下how,如何使用。
$container= new Container();//創建一個容器(后面簡稱為超級工廠)
$container->bind('superman',function($container,$moduleName) {return new Superman($container->make($moduleName));
});// 向該 超級工廠 添加 超人 的生產腳本
$container->bind('xpower',function($container) {return new XPower;});// 向該 超級工廠 添加 超能力模組 的生產腳本
$container->bind('ultrabomb',function($container) {returnnew UltraBomb;});// 同上******************? 華麗麗的分割線? **********************
$superman_1=$container->make('superman','xpower');//啟動生產Superman
$superman_2 =$container->make('superman','ultrabomb');
So,通過最初的 綁定(bind) 操作,我們向 超級工廠 注冊了一些生產腳本,這些生產腳本在生產指令下達之時便會執行。我們徹底的解除了 超人 與 超能力模組 的依賴關系,更重要的是,容器類也絲毫沒有和他們產生任何依賴!我們通過注冊、綁定的方式向容器中添加一段可以被執行的回調(可以是匿名函數、非匿名函數、類的方法)作為生產一個類的實例的 腳本 ,只有在真正的 生產(make) 操作被調用執行時,才會觸發。
實際上,真正的 IOC容器更為高級。我們現在的例子中,還是需要手動提供超人所需要的模組參數,但真正的 IOC容器會根據類的依賴需求,自動在注冊、綁定的一堆實例中搜尋符合的依賴需求,并自動注入到構造函數中。
laravel初始化一個服務容器的大概過程
這就要拉出源碼溜溜了(好在我們能站在巨人的肩膀上~~)。。。初始化服務容器的相關調度文件就是:/bootstrap/app.php...
然后在跟隨大神的??,讀了三個
代碼清單/bootstrap/app.php
singleton('Illuminate\Contracts\Http\Kernel','App\Http\Kernel');//單例一個App\Console\Kernel對象,可以使用App::make('Illuminate\Contracts\Console\Kernel')調用$app->singleton('Illuminate\Contracts\Console\Kernel','App\Console\Kernel');//打字好累,同上,不解釋$app->singleton('Illuminate\Contracts\Debug\ExceptionHandler','App\Exceptions\Handler');//返回一個初始化完成的服務容器return$app;
代碼清單Illuminate\Foundation\Application
//代碼太多,只能解釋幾個主要的方法(真實情況是,我了解也不多,也就看了這幾個方法*^_^*)publicfunction__construct($basePath = null)? ? {//初始化最簡單的容器$this->registerBaseBindings();//在容器中注冊最基本的服務提供者(即ServiceProvider)$this->registerBaseServiceProviders();//在容器中注冊一些核心類的別名(這個說法貌似有點不妥,可以參見以下的代碼注釋自己再理解一下)$this->registerCoreContainerAliases();//在容器中注冊一些常用的文檔絕對路徑if ($basePath)$this->setBasePath($basePath);? ? }protectedfunctionregisterBaseBindings()? ? {//初始化一個空的容器static::setInstance($this);//在容器中,實例化一個key為app的實例,相對的值就是當前容器,你可以使用App::make('app')來取得一個容器對象$this->instance('app',$this);//同上$this->instance('Illuminate\Container\Container',$this);? ? }protectedfunctionregisterBaseServiceProviders()? ? {//EventServiceProvider這個服務提供者,其實是向容器注冊了一個key為events的對象,可以在你的IDE里面追蹤一下代碼$this->register(new EventServiceProvider($this));//注冊4個key分別為router、url、redirect、Illuminate\Contracts\Routing\ResponseFactory的對象$this->register(new RoutingServiceProvider($this));? ? }/*這個方法的作用,就以一個例子來解釋吧(語文不太好~\(≧▽≦)/~)? ? ? ? 在調用此方法之前,我們想取得一個容器實例的做法是 App::make('app');? ? ? ? 現在我們可以使用App::make('Illuminate\Foundation\Application')? ? ? ? App::make('Illuminate\Contracts\Container\Container')? ? ? ? App::make('Illuminate\Contracts\Foundation\Application')? ? ? ? 三種方法來取得一個容器實例,即Illuminate\Foundation\Application、Illuminate\Contracts\Container\Container、Illuminate\Contracts\Foundation\Application三者都是app的別名;? ? */publicfunctionregisterCoreContainerAliases()? ? {$aliases =array('app'? ? ? ? ? ? ? ? ? => ['Illuminate\Foundation\Application','Illuminate\Contracts\Container\Container','Illuminate\Contracts\Foundation\Application'],'artisan'? ? ? ? ? ? ? => ['Illuminate\Console\Application','Illuminate\Contracts\Console\Application'],'auth'? ? ? ? ? ? ? ? =>'Illuminate\Auth\AuthManager','auth.driver'? ? ? ? ? => ['Illuminate\Auth\Guard','Illuminate\Contracts\Auth\Guard'],'auth.password.tokens' =>'Illuminate\Auth\Passwords\TokenRepositoryInterface','blade.compiler'? ? ? =>'Illuminate\View\Compilers\BladeCompiler','cache'? ? ? ? ? ? ? ? => ['Illuminate\Cache\CacheManager','Illuminate\Contracts\Cache\Factory'],'cache.store'? ? ? ? ? => ['Illuminate\Cache\Repository','Illuminate\Contracts\Cache\Repository'],'config'? ? ? ? ? ? ? => ['Illuminate\Config\Repository','Illuminate\Contracts\Config\Repository'],'cookie'? ? ? ? ? ? ? => ['Illuminate\Cookie\CookieJar','Illuminate\Contracts\Cookie\Factory','Illuminate\Contracts\Cookie\QueueingFactory'],'encrypter'? ? ? ? ? ? => ['Illuminate\Encryption\Encrypter','Illuminate\Contracts\Encryption\Encrypter'],'db'? ? ? ? ? ? ? ? ? =>'Illuminate\Database\DatabaseManager','events'? ? ? ? ? ? ? => ['Illuminate\Events\Dispatcher','Illuminate\Contracts\Events\Dispatcher'],'files'? ? ? ? ? ? ? ? =>'Illuminate\Filesystem\Filesystem','filesystem'? ? ? ? ? =>'Illuminate\Contracts\Filesystem\Factory','filesystem.disk'? ? ? =>'Illuminate\Contracts\Filesystem\Filesystem','filesystem.cloud'? ? =>'Illuminate\Contracts\Filesystem\Cloud','hash'? ? ? ? ? ? ? ? =>'Illuminate\Contracts\Hashing\Hasher','translator'? ? ? ? ? => ['Illuminate\Translation\Translator','Symfony\Component\Translation\TranslatorInterface'],'log'? ? ? ? ? ? ? ? ? => ['Illuminate\Log\Writer','Illuminate\Contracts\Logging\Log','Psr\Log\LoggerInterface'],'mailer'? ? ? ? ? ? ? => ['Illuminate\Mail\Mailer','Illuminate\Contracts\Mail\Mailer','Illuminate\Contracts\Mail\MailQueue'],'paginator'? ? ? ? ? ? =>'Illuminate\Pagination\Factory','auth.password'? ? ? ? => ['Illuminate\Auth\Passwords\PasswordBroker','Illuminate\Contracts\Auth\PasswordBroker'],'queue'? ? ? ? ? ? ? ? => ['Illuminate\Queue\QueueManager','Illuminate\Contracts\Queue\Factory','Illuminate\Contracts\Queue\Monitor'],'queue.connection'? ? =>'Illuminate\Contracts\Queue\Queue','redirect'? ? ? ? ? ? =>'Illuminate\Routing\Redirector','redis'? ? ? ? ? ? ? ? => ['Illuminate\Redis\Database','Illuminate\Contracts\Redis\Database'],'request'? ? ? ? ? ? ? =>'Illuminate\Http\Request','router'? ? ? ? ? ? ? => ['Illuminate\Routing\Router','Illuminate\Contracts\Routing\Registrar'],'session'? ? ? ? ? ? ? =>'Illuminate\Session\SessionManager','session.store'? ? ? ? => ['Illuminate\Session\Store','Symfony\Component\HttpFoundation\Session\SessionInterface'],'url'? ? ? ? ? ? ? ? ? => ['Illuminate\Routing\UrlGenerator','Illuminate\Contracts\Routing\UrlGenerator'],'validator'? ? ? ? ? ? => ['Illuminate\Validation\Factory','Illuminate\Contracts\Validation\Factory'],'view'? ? ? ? ? ? ? ? => ['Illuminate\View\Factory','Illuminate\Contracts\View\Factory'],? ? ? ? );foreach ($aliasesas$key =>$aliases)? ? ? ? {foreach ((array)$aliasesas$alias)? ? ? ? ? ? {$this->alias($key,$alias);
}
}
}
由此得到的一個容器實例
Application {#2 ▼#basePath: "/Applications/XAMPP/xamppfiles/htdocs/laravel"#hasBeenBootstrapped: false#booted: false#bootingCallbacks: []#bootedCallbacks: []#terminatingCallbacks: []#serviceProviders: array:2 [?]#loadedProviders: array:2 [?]#deferredServices: []#storagePath: null#environmentFile: ".env"#resolved: array:1 [?]#bindings: array:8 [▼"events" =>array:2 [?]"router" =>array:2 [?]"url" =>array:2 [?]"redirect" =>array:2 [?]"Illuminate\Contracts\Routing\ResponseFactory" =>array:2 [?]"Illuminate\Contracts\Http\Kernel" =>array:2 [?]"Illuminate\Contracts\Console\Kernel" =>array:2 [?]"Illuminate\Contracts\Debug\ExceptionHandler" =>array:2 [?]? ]#instances: array:10 [▼"app" => Application {#2}"Illuminate\Container\Container" => Application {#2}"events" => Dispatcher {#5 ?}"path" =>"/Applications/XAMPP/xamppfiles/htdocs/laravel/app""path.base" =>"/Applications/XAMPP/xamppfiles/htdocs/laravel""path.config" =>"/Applications/XAMPP/xamppfiles/htdocs/laravel/config""path.database" =>"/Applications/XAMPP/xamppfiles/htdocs/laravel/database""path.lang" =>"/Applications/XAMPP/xamppfiles/htdocs/laravel/resources/lang""path.public" =>"/Applications/XAMPP/xamppfiles/htdocs/laravel/public""path.storage" =>"/Applications/XAMPP/xamppfiles/htdocs/laravel/storage"? ]#aliases: array:59 [▼"Illuminate\Foundation\Application" =>"app""Illuminate\Contracts\Container\Container" =>"app""Illuminate\Contracts\Foundation\Application" =>"app""Illuminate\Console\Application" =>"artisan""Illuminate\Contracts\Console\Application" =>"artisan""Illuminate\Auth\AuthManager" =>"auth""Illuminate\Auth\Guard" =>"auth.driver""Illuminate\Contracts\Auth\Guard" =>"auth.driver""Illuminate\Auth\Passwords\TokenRepositoryInterface" =>"auth.password.tokens""Illuminate\View\Compilers\BladeCompiler" =>"blade.compiler""Illuminate\Cache\CacheManager" =>"cache""Illuminate\Contracts\Cache\Factory" =>"cache""Illuminate\Cache\Repository" =>"cache.store""Illuminate\Contracts\Cache\Repository" =>"cache.store""Illuminate\Config\Repository" =>"config""Illuminate\Contracts\Config\Repository" =>"config""Illuminate\Cookie\CookieJar" =>"cookie""Illuminate\Contracts\Cookie\Factory" =>"cookie""Illuminate\Contracts\Cookie\QueueingFactory" =>"cookie""Illuminate\Encryption\Encrypter" =>"encrypter""Illuminate\Contracts\Encryption\Encrypter" =>"encrypter""Illuminate\Database\DatabaseManager" =>"db""Illuminate\Events\Dispatcher" =>"events""Illuminate\Contracts\Events\Dispatcher" =>"events""Illuminate\Filesystem\Filesystem" =>"files""Illuminate\Contracts\Filesystem\Factory" =>"filesystem""Illuminate\Contracts\Filesystem\Filesystem" =>"filesystem.disk""Illuminate\Contracts\Filesystem\Cloud" =>"filesystem.cloud""Illuminate\Contracts\Hashing\Hasher" =>"hash""Illuminate\Translation\Translator" =>"translator""Symfony\Component\Translation\TranslatorInterface" =>"translator""Illuminate\Log\Writer" =>"log""Illuminate\Contracts\Logging\Log" =>"log""Psr\Log\LoggerInterface" =>"log""Illuminate\Mail\Mailer" =>"mailer""Illuminate\Contracts\Mail\Mailer" =>"mailer""Illuminate\Contracts\Mail\MailQueue" =>"mailer""Illuminate\Pagination\Factory" =>"paginator""Illuminate\Auth\Passwords\PasswordBroker" =>"auth.password""Illuminate\Contracts\Auth\PasswordBroker" =>"auth.password""Illuminate\Queue\QueueManager" =>"queue""Illuminate\Contracts\Queue\Factory" =>"queue""Illuminate\Contracts\Queue\Monitor" =>"queue""Illuminate\Contracts\Queue\Queue" =>"queue.connection""Illuminate\Routing\Redirector" =>"redirect""Illuminate\Redis\Database" =>"redis""Illuminate\Contracts\Redis\Database" =>"redis""Illuminate\Http\Request" =>"request""Illuminate\Routing\Router" =>"router""Illuminate\Contracts\Routing\Registrar" =>"router""Illuminate\Session\SessionManager" =>"session""Illuminate\Session\Store" =>"session.store""Symfony\Component\HttpFoundation\Session\SessionInterface" =>"session.store""Illuminate\Routing\UrlGenerator" =>"url""Illuminate\Contracts\Routing\UrlGenerator" =>"url""Illuminate\Validation\Factory" =>"validator""Illuminate\Contracts\Validation\Factory" =>"validator""Illuminate\View\Factory" =>"view""Illuminate\Contracts\View\Factory" =>"view"? ]#extenders: []#tags: []#buildStack: []? +contextual: []#reboundCallbacks: []#globalResolvingCallbacks: []#globalAfterResolvingCallbacks: []#resolvingCallbacks: []#afterResolvingCallbacks: []
}
怎么打印一個實例??
到這一步為止,你可以這樣做dd(app())
dd(app())什么意思??
這里包含兩個方法dd()和app(),具體定義請看自動加載的第四種方法
那說好的App::make(‘app’)方法咋不能用呢?
這是因為這個方法需要用到Contracts,而到此為止,還未定義App作為Illuminate\Support\Facades\App的別名,因而不能用;需要等到統一入口文件里面的運行Kernel類的handle方法才能用,所以在Controller里面是可以用的,現在不能用
到此為止,一個容器實例就誕生了,事情就是這么個事情,情況就是這個個情況,再具體的那就需要你自己去看代碼了,我知道的就這些
Kernel實例調用handle方法,意味著laravel的核心和公用代碼已經準備完畢,此項目正式開始運行
代碼清單/app/Http/Kernel.php
'App\Http\Middleware\Authenticate','auth.basic' =>'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth','guest' =>'App\Http\Middleware\RedirectIfAuthenticated','test' =>'App\Http\Middleware\testMiddleWare',
];
}
大家看到了,其實這個文件里面沒有handle方法,只有一些屬性定義,所以真正的handle方法,實在父類里面實現的
代碼清單…/Illuminate/Foundation/Http/Kernel.php
//好多代碼,見幾個我看過的扯扯,其他的期待你們補上//這個很重要,是項目的一些啟動引導項,Kernel的重要步驟中,首先就是啟動這些文件的bootstrap方法protected$bootstrappers = [//檢測環境變量文件是否正常'Illuminate\Foundation\Bootstrap\DetectEnvironment',//取得配置文件,即把/config/下的所有配置文件讀取到容器(app()->make('config')可以查看所有配置信息)'Illuminate\Foundation\Bootstrap\LoadConfiguration',//綁定一個名字為log的實例到容器,怎么訪問??(app()->make('log'))'Illuminate\Foundation\Bootstrap\ConfigureLogging',//設置異常抓取信息,這個還沒仔細看,但大概就是這個意思'Illuminate\Foundation\Bootstrap\HandleExceptions',//把/config/app.php里面的aliases項利用PHP庫函數class_alias創建別名,從此,我們可以使用App::make('app')方式取得實例'Illuminate\Foundation\Bootstrap\RegisterFacades',//把/config/app.php里面的providers項,注冊到容器'Illuminate\Foundation\Bootstrap\RegisterProviders',//運行容器中注冊的所有的ServiceProvider中得boot方法'Illuminate\Foundation\Bootstrap\BootProviders',? ? ];//真正的handle方法publicfunctionhandle($request)? ? {try? ? ? ? {//主要是這行,調度了需要運行的方法return$this->sendRequestThroughRouter($request);? ? ? ? }catch (Exception$e)? ? ? ? {$this->reportException($e);return$this->renderException($request,$e);? ? ? ? }? ? }protectedfunctionsendRequestThroughRouter($request)? ? {$this->app->instance('request',$request);? ? ? ? Facade::clearResolvedInstance('request');//運行上述$bootstrappers里面包含的文件的bootstrap方法,運行的作用,上面已經注釋$this->bootstrap();//這是在對URL進行調度之前,也就是運行Route之前,進行的一些準備工作return (new Pipeline($this->app))//不解釋? ? ? ? ? ? ? ? ? ? ->send($request)//繼續不解釋//需要運行$this->middleware里包含的中間件? ? ? ? ? ? ? ? ? ? ->through($this->middleware)//運行完上述中間件之后,調度dispatchToRouter方法,進行Route的操作? ? ? ? ? ? ? ? ? ? ->then($this->dispatchToRouter());? ? }//前奏執行完畢之后,進行Route操作protectedfunctiondispatchToRouter()? ? {returnfunction($request)? ? ? ? {$this->app->instance('request',$request);//跳轉到Router類的dispatch方法return$this->router->dispatch($request);
};
}
下面就需要根據URL和/app/Http/routes.php文件,進行Route操作
文件清單…/Illuminate/Routing/Router.php
//代碼好多,挑幾個解釋publicfunctiondispatch(Request$request)? ? {$this->currentRequest =$request;//在4.2版本里面,Route有一個篩選屬性;5.0之后的版本,被Middleware代替$response =$this->callFilter('before',$request);if (is_null($response))? ? ? ? {//繼續調度$response =$this->dispatchToRoute($request);? ? ? ? }$response =$this->prepareResponse($request,$response);//在4.2版本里面,Route有一個篩選屬性;5.0之后的版本,被Middleware代替$this->callFilter('after',$request,$response);return$response;? ? }publicfunctiondispatchToRoute(Request$request)? ? {$route =$this->findRoute($request);$request->setRouteResolver(function()use($route)? ? ? ? {return$route;? ? ? ? });$this->events->fire('router.matched', [$route,$request]);$response =$this->callRouteBefore($route,$request);if (is_null($response))? ? ? ? {// 只看這一行,還是調度文件$response =$this->runRouteWithinStack($route,$request? ? ? ? ? ? );? ? ? ? }$response =$this->prepareResponse($request,$response);$this->callRouteAfter($route,$request,$response);return$response;? ? }//干貨來了protectedfunctionrunRouteWithinStack(Route$route, Request$request)? ? {// 取得routes.php里面的Middleware節點$middleware =$this->gatherRouteMiddlewares($route);//這個有點眼熟return (new Pipeline($this->container))? ? ? ? ? ? ? ? ? ? ? ? ->send($request)//執行上述的中間件? ? ? ? ? ? ? ? ? ? ? ? ->through($middleware)? ? ? ? ? ? ? ? ? ? ? ? ->then(function($request)use($route)? ? ? ? ? ? ? ? ? ? ? ? {//不容易啊,終于到Controller類了return$this->prepareResponse($request,//run控制器$route->run($request)? ? ? ? ? ? ? ? ? ? ? ? ? ? );? ? ? ? ? ? ? ? ? ? ? ? });? ? }publicfunctionrun(Request$request)? ? {$this->container =$this->container ?:new Container;try? ? ? ? {if ( ! is_string($this->action['uses']))return$this->runCallable($request);if ($this->customDispatcherIsBound())//實際上是運行了這行return$this->runWithCustomDispatcher($request);//其實我是直接想運行這行return$this->runController($request);? ? ? ? }catch (HttpResponseException$e)? ? ? ? {return$e->getResponse();? ? ? ? }? ? }//繼續調度,最終調度到.../Illuminate/Routing/ControllerDispatcher.php文件的dispatch方法protectedfunctionrunWithCustomDispatcher(Request$request)? ? {list($class,$method) = explode('@',$this->action['uses']);$dispatcher =$this->container->make('illuminate.route.dispatcher');return$dispatcher->dispatch($this,$request,$class,$method);
}
文件清單…/Illuminate/Routing/ControllerDispatcher.php
publicfunctiondispatch(Route$route, Request$request,$controller,$method)? ? {$instance =$this->makeController($controller);$this->assignAfter($instance,$route,$request,$method);$response =$this->before($instance,$route,$request,$method);if (is_null($response))? ? ? ? {//還要調度$response =$this->callWithinStack($instance,$route,$request,$method? ? ? ? ? ? );? ? ? ? }return$response;? ? }protectedfunctioncallWithinStack($instance,$route,$request,$method)? ? {//又是Middleware......有沒有忘記,官方文檔里面Middleware可以加在控制器的構造函數中??!沒錯,這個Middleware就是在控制器里面申明的$middleware =$this->getMiddleware($instance,$method);//又是這個,眼熟吧return (new Pipeline($this->container))? ? ? ? ? ? ? ? ? ? ->send($request)//再次運行Middleware? ? ? ? ? ? ? ? ? ? ->through($middleware)? ? ? ? ? ? ? ? ? ? ->then(function($request)use($instance,$route,$method)? ? ? ? ? ? ? ? ? ? {? ? ? ? ? ? ? ? ? ? ? ? ? ? 運行控制器,返回結果return$this->call($instance,$route,$method);
});
}
分類:PHP
1
0
HTTP / Console 內核
接下來,傳入的請求會被發送給 HTTP 內核或者 console 內核,這根據進入應用的請求的類型而定。這兩個內核服務是所有請求都經過的中樞。讓我們現在只關注位于app/Http/Kernel.php的 HTTP 內核。
HTTP 內核繼承自Illuminate\Foundation\Http\Kernel類,它定義了一個bootstrappers數組,數組中的類在請求真正執行前進行前置執行。 這些引導程序配置了錯誤處理,日志記錄,檢測應用程序環境,以及其他在請求被處理前需要完成的工作。
HTTP 內核同時定義了一個 HTTP中間件列表,所有的請求必須在處理前通過這些中間件,這些中間件處理HTTP session的讀寫,判斷應用是否在維護模式,驗證 CSRF token等等。
HTTP 內核的標志性handle方法是相當簡單的:接收一個Request并返回一個Response。你可以把內核想成一個代表你應用的大黑盒子。給它喂 HTTP 請求然后它就會吐給你 HTTP 響應。
服務提供者
在內核引導啟動的過程中最重要的動作之一就是載入服務提供者到你的應用。所有的服務提供者都配置在config/app.php文件中的providers數組中。 首先,所有提供者的register方法會被調用,接下來,一旦所有提供者注冊完成,boot方法將會被調用。
服務提供者負責引導啟動框架的全部各種組件,例如數據庫、隊列、驗證器以及路由組件。因為這些組件引導和配置了框架的各種功能,所以服務提供者是整個 Laravel 啟動過程中最為重要的部分。
分發請求
一旦應用完成引導和所有服務提供者都注冊完成,Request將會移交給路由進行分發。路由將分發請求給一個路由或控制器,同時運行路由指定的中間件。
服務提供者是 Laravel 應用的真正關鍵部分,應用實例被創建后,服務提供者就會被注冊完成,并將請求傳遞給應用進行處理,真的就是這么簡單!
了解 Laravel 是怎樣通過服務提供者構建和引導一個穩定的應用是非常有價值的,當然,應用的默認服務提供者都存放在app/Providers目錄中。
在新創建的應用中,AppServiceProvider文件中方法實現都是空的。這個提供者是你添加應用專屬的引導和服務的最佳位置,當然的,對于大型應用你可能希望創建幾個服務提供者,每個都具有粒度更精細的引導。
譯者署名
用戶名頭像職能簽名