摘要:會依據(jù)協(xié)議,將請求的數(shù)據(jù)等信息發(fā)送給解析器,接下來解析器會解析文件,初始化執(zhí)行環(huán)境,然后處理請求,再以規(guī)定的格式返回處理后的結(jié)果,退出進程。它的特點是會在動態(tài)分配處理進程給請求,以達到提高效率的目的,大多數(shù)實現(xiàn)都會維護一個進程池。
PHP作為世界上最好的編程語音,被廣泛的運用到Web開發(fā)中。因為其語法和C類似,有著非常平緩的學(xué)習(xí)曲線,越來越多的人使用PHP進行Web產(chǎn)品的快速開發(fā)。PHP世界里也涌現(xiàn)了很多開發(fā)框架,比如Laravel、ThinkPHP等,但不論何總框架,他們在處理Web請求時的模式都是一樣的,本文首先闡述PHP開發(fā)Web應(yīng)用的基本架構(gòu),然后分別分析Laravel和ThinkPHP在處理Web請求時的處理流程。
PHP開發(fā)Web應(yīng)用的基本架構(gòu)PHP開發(fā)Web應(yīng)用時所以的請求需要指向具體的入口文件。WebServer是一個內(nèi)容分發(fā)者,他接受用戶的請求后,如果是請求的是css、js等靜態(tài)文件,WebServer會找到這個文件,然后發(fā)送給瀏覽器;如果請求的是/index.php,根據(jù)配置文件,WebServer知道這個不是靜態(tài)文件,需要去找PHP解析器來處理,那么他會把這個請求簡單處理后交給PHP解析器。
WebServer會依據(jù)CGI協(xié)議,將請求的Url、數(shù)據(jù)、Http Header等信息發(fā)送給PHP解析器,接下來PHP解析器會解析php.ini文件,初始化執(zhí)行環(huán)境,然后處理請求,再以CGI規(guī)定的格式返回處理后的結(jié)果,退出進程。web server再把結(jié)果返回給瀏覽器。整個處理過程如上圖所示。
FastCGI這里的PHP解析器就是實現(xiàn)了CGI協(xié)議的程序,每次請求到來時他會解析php.ini文件,初始化執(zhí)行環(huán)境,這就導(dǎo)致PHP解析器性能低下,于是就出現(xiàn)了CGI的改良升級版FastCGI。FastCGI是一種語言無關(guān)的協(xié)議,用來溝通程序(如PHP, Python, Java)和Web服務(wù)器(Apache2, Nginx), 理論上任何語言編寫的程序都可以通過FastCGI來提供Web服務(wù)。它的特點是會在動態(tài)分配處理進程給請求,以達到提高效率的目的,大多數(shù)FastCGI實現(xiàn)都會維護一個進程池。FastCGI會先啟一個master進程,解析配置文件,初始化執(zhí)行環(huán)境,然后再啟動多個worker進程。當請求過來時,master進程會這個請求傳遞給一個worker進程,然后立即接受下一個請求。而且當worker進程不夠用時,master可以根據(jù)配置預(yù)先啟動幾個worker進程等待;當然空閑worker進程太多時,也會自動關(guān)閉,這樣就提高了性能,節(jié)約了系統(tǒng)資源。整個過程FastCGI扮演著對CGI進程進行管理的角色。
PHP-FPMPHP-FPM是一個專門針對PHP實現(xiàn)了FastCGI協(xié)議的程序,它實際上就是一個PHP FastCGI進程管理器,負責管理一個進程池,調(diào)用PHP解析器來處理來自Web服務(wù)器的請求。PHP-FPM能夠?qū)hp.ini文件的修改進行平滑過度。
新建一個helloworld.php文件,寫入下列代碼
配置好WebServer和PHP-FPM等php運行環(huán)境后,在瀏覽器中訪問該文件就可以直接得到輸出。
基于PHP的Web框架它主要的任務(wù)包括:基于某模式將PHP開發(fā)常用功能封裝實現(xiàn)使開發(fā)者快速開發(fā)的工具
代碼重用:定義包、類、函數(shù)的放置和加載規(guī)則,建議直接整合Composer及其AutoLoad特性。
請求的分發(fā)管理:這個就是路由,Rest風(fēng)的框架喜歡Rewrite,簡單的一點的框架主要通過參數(shù)來定位模塊和方法所在。
配置文件管理:加載和動態(tài)加載配置數(shù)據(jù)
錯誤和異常管理:異常捕捉、錯誤日志記錄以及錯誤碼規(guī)范。
Layout和模板引擎:如何規(guī)劃頁面布局、widget如何重用、ajax頁面如何結(jié)合、過期- session如何重定向;數(shù)據(jù)和模板怎么渲染成HTML,是否壓縮和設(shè)置過期頭。
數(shù)據(jù)庫:如何融入控制器;支持什么樣的driver;考慮主從分離的擴展性;以及是否使用ORM
ThinkPHP3.2框架處理流程分析
TP的設(shè)計邏輯就是簡單粗暴,面對問題解決問題,所以他的處理流程是基于面向過程的思想,而沒有采用面向?qū)ο蟮囊蕾囎⑷?、控制反轉(zhuǎn)等思路。他的自動加載、錯誤處理通過php原生函數(shù)的回調(diào)來實現(xiàn)。TP處理每次請求要經(jīng)過四個步驟如下圖所示:
index.php是TP的入口文件,所有的請求都由該文件接管,它的工作也很簡單主要是引入ThinkPHP入口文件
5.3.0 !"); // 開啟調(diào)試模式 建議開發(fā)階段開啟 部署階段注釋或者設(shè)為false define("APP_DEBUG",False); // 定義應(yīng)用目錄 define("APP_PATH","./Application/"); // 引入ThinkPHP入口文件 require "./ThinkPHP/ThinkPHP.php";載入框架入口文件ThinkPHP.php
在ThinkPHP.php中主要記錄初始運行時間和內(nèi)存開銷,然后完成系統(tǒng)常量判斷及定義,最后載入框架引導(dǎo)類(ThinkThink)并執(zhí)行Think::start方法進行應(yīng)用初始化。
應(yīng)用初始化ThinkThink:start()應(yīng)用初始化首先設(shè)置錯誤處理機制和自動加載機制
static public function start() { // 注冊AUTOLOAD方法 spl_autoload_register("ThinkThink::autoload"); // 設(shè)定錯誤和異常處理 register_shutdown_function("ThinkThink::fatalError"); set_error_handler("ThinkThink::appError"); set_exception_handler("ThinkThink::appException");
然后加載相關(guān)配置文件和運行模式定義文件,最后調(diào)用ThinkApp類的run方法啟動應(yīng)用
運行應(yīng)用App::run()此后TP進入請求處理管道,TP為管道中定義了14個事件,每個事件都可以綁定回調(diào)函數(shù),請求到達管道后依次觸發(fā)這些事件,事件觸發(fā)后就會調(diào)用綁定到事件的回調(diào)函數(shù),整個管道的生命周期由app_init開始,由app_end結(jié)束。具體實現(xiàn)上,TP將這些事件命名為標簽(位),也可以稱之為鉤子,將回調(diào)函數(shù)命名為行為,當應(yīng)用程序運行到標簽的時候,就會被攔截下來,統(tǒng)一執(zhí)行相關(guān)的行為。
Laravel框架處理流程分析統(tǒng)一入口
Laravel框架使用了統(tǒng)一入口,入口文件:/public/index.php
make("IlluminateContractsHttpKernel"); //運行Kernel類的handle方法,主要動作是運行middleware和啟動URL相關(guān)的Contrller $response = $kernel->handle( $request = IlluminateHttpRequest::capture() ); //控制器返回結(jié)果之后的操作,暫時還沒看,以后補上 $response->send(); $kernel->terminate($request, $response);自動加載文件
laravel的自動加載,其實也就是Composer的自動加載
Composer根據(jù)聲明的依賴關(guān)系,從相關(guān)庫的源下載代碼文件,并根據(jù)依賴關(guān)系在 Composer 目錄下生成供類自動加載的 PHP 腳本,使用的時候,項目開始處引入 “/vendor/autoload.php” 文件,就可以直接實例化這些第三方類庫中的類了。
服務(wù)容器,也叫IoC容器,其實包含了依賴注入(DI)和控制反轉(zhuǎn)(IoC)兩部分,是Laravel的真正核心。其他的各種功能模塊比如 Route(路由)、Eloquent ORM(數(shù)據(jù)庫 ORM 組件)、Request and Response(請求和響應(yīng))等等等等,實際上都是與核心無關(guān)的類模塊提供的,這些類從注冊到實例化,最終被使用,其實都是 Laravel 的服務(wù)容器負責的。
啟動Kernel代碼Kernel實例調(diào)用handle方法,意味著Laravel的核心和公用代碼已經(jīng)準備完畢,此項目正式開始運行
代碼清單/app/Http/Kernel.php
"AppHttpMiddlewareAuthenticate", "auth.basic" => "IlluminateAuthMiddlewareAuthenticateWithBasicAuth", "guest" => "AppHttpMiddlewareRedirectIfAuthenticated", "test" => "AppHttpMiddleware estMiddleWare", ]; }
可以看到,其實這個文件里面沒有handle方法,只有一些屬性定義,所以真正的handle方法,實在父類里面實現(xiàn)的
代碼清單…/Illuminate/Foundation/Http/Kernel.php
//這個很重要,是項目的一些啟動引導(dǎo)項,Kernel的重要步驟中,首先就是啟動這些文件的bootstrap方法 protected $bootstrappers = [ //檢測環(huán)境變量文件是否正常 "IlluminateFoundationBootstrapDetectEnvironment", //取得配置文件,即把/config/下的所有配置文件讀取到容器(app()->make("config")可以查看所有配置信息) "IlluminateFoundationBootstrapLoadConfiguration", //綁定一個名字為log的實例到容器,怎么訪問??(app()->make("log")) "IlluminateFoundationBootstrapConfigureLogging", //設(shè)置異常抓取信息,這個還沒仔細看,但大概就是這個意思 "IlluminateFoundationBootstrapHandleExceptions", //把/config/app.php里面的aliases項利用PHP庫函數(shù)class_alias創(chuàng)建別名,從此,我們可以使用App::make("app")方式取得實例 "IlluminateFoundationBootstrapRegisterFacades", //把/config/app.php里面的providers項,注冊到容器 "IlluminateFoundationBootstrapRegisterProviders", //運行容器中注冊的所有的ServiceProvider中得boot方法 "IlluminateFoundationBootstrapBootProviders", ]; //真正的handle方法 public function handle($request) { try { //主要是這行,調(diào)度了需要運行的方法 return $this->sendRequestThroughRouter($request); } catch (Exception $e) { $this->reportException($e); return $this->renderException($request, $e); } } protected function sendRequestThroughRouter($request) { $this->app->instance("request", $request); Facade::clearResolvedInstance("request"); //運行上述$bootstrappers里面包含的文件的bootstrap方法,運行的作用,上面已經(jīng)注釋 $this->bootstrap(); //這是在對URL進行調(diào)度之前,也就是運行Route之前,進行的一些準備工作 return (new Pipeline($this->app)) ->send($request) //需要運行$this->middleware里包含的中間件 ->through($this->middleware) //運行完上述中間件之后,調(diào)度dispatchToRouter方法,進行Route的操作 ->then($this->dispatchToRouter()); } //前奏執(zhí)行完畢之后,進行Route操作 protected function dispatchToRouter() { return function($request) { $this->app->instance("request", $request); //跳轉(zhuǎn)到Router類的dispatch方法 return $this->router->dispatch($request); }; }
下面就需要根據(jù)URL和/app/Http/routes.php文件,進行Route操作
文件清單…/Illuminate/Routing/Router.php
public function dispatch(Request $request) { $this->currentRequest = $request; //在4.2版本里面,Route有一個篩選屬性;5.0之后的版本,被Middleware代替 $response = $this->callFilter("before", $request); if (is_null($response)) { //繼續(xù)調(diào)度 $response = $this->dispatchToRoute($request); } $response = $this->prepareResponse($request, $response); //在4.2版本里面,Route有一個篩選屬性;5.0之后的版本,被Middleware代替 $this->callFilter("after", $request, $response); return $response; } public function dispatchToRoute(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)) { // 只看這一行,還是調(diào)度文件 $response = $this->runRouteWithinStack( $route, $request ); } $response = $this->prepareResponse($request, $response); $this->callRouteAfter($route, $request, $response); return $response; } protected function runRouteWithinStack(Route $route, Request $request) { // 取得routes.php里面的Middleware節(jié)點 $middleware = $this->gatherRouteMiddlewares($route); //這個有點眼熟 return (new Pipeline($this->container)) ->send($request) //執(zhí)行上述的中間件 ->through($middleware) ->then(function($request) use ($route) { //到Controller類了 return $this->prepareResponse( $request, //run控制器 $route->run($request) ); }); } public function run(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(); } } //繼續(xù)調(diào)度,最終調(diào)度到.../Illuminate/Routing/ControllerDispatcher.php文件的dispatch方法 protected function runWithCustomDispatcher(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
public function dispatch(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)) { //還要調(diào)度 $response = $this->callWithinStack( $instance, $route, $request, $method ); } return $response; } protected function callWithinStack($instance, $route, $request, $method) { //又是Middleware......有沒有忘記,官方文檔里面Middleware可以加在控制器的構(gòu)造函數(shù)中??!沒錯,這個Middleware就是在控制器里面申明的 $middleware = $this->getMiddleware($instance, $method); //又是這個,眼熟吧 return (new Pipeline($this->container)) ->send($request) //再次運行Middleware ->through($middleware) ->then(function($request) use ($instance, $route, $method) { 運行控制器,返回結(jié)果 return $this->call($instance, $route, $method); }); }
終于到達控制器
轉(zhuǎn)自:http://www.eurekao.com/PHP-pr...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/22586.html
摘要:的運維追蹤技巧總結(jié)曾幾何時我開始運維公司的網(wǎng)站,經(jīng)過一段時間的摸爬滾打,也算是總結(jié)了不少在服務(wù)器下調(diào)試追蹤各種網(wǎng)站錯誤的方法。 LNMP的運維追蹤技巧總結(jié) 曾幾何時我開始運維公司的LNMP網(wǎng)站,經(jīng)過一段時間的摸爬滾打,也算是總結(jié)了不少在LNMP服務(wù)器下調(diào)試追蹤各種網(wǎng)站錯誤的方法。好記性不如爛筆頭,還是總結(jié)一下吧! 在開始我會梳理一下我所理解的一個web請求從發(fā)起到響應(yīng)的各個階段服務(wù)器和...
摘要:的運維追蹤技巧總結(jié)曾幾何時我開始運維公司的網(wǎng)站,經(jīng)過一段時間的摸爬滾打,也算是總結(jié)了不少在服務(wù)器下調(diào)試追蹤各種網(wǎng)站錯誤的方法。 LNMP的運維追蹤技巧總結(jié) 曾幾何時我開始運維公司的LNMP網(wǎng)站,經(jīng)過一段時間的摸爬滾打,也算是總結(jié)了不少在LNMP服務(wù)器下調(diào)試追蹤各種網(wǎng)站錯誤的方法。好記性不如爛筆頭,還是總結(jié)一下吧! 在開始我會梳理一下我所理解的一個web請求從發(fā)起到響應(yīng)的各個階段服務(wù)器和...
摘要:是與之間數(shù)據(jù)交換的一種協(xié)議。當收到這個請求后,會啟動對應(yīng)的程序,這里就是的解析器。接下來解析器會解析文件,初始化執(zhí)行環(huán)境,然后處理請求,再以規(guī)定規(guī)定的格式返回處理后的結(jié)果,退出進程,再把結(jié)果返回給瀏覽器。 CGI:是 Web Server 與 Web Application 之間數(shù)據(jù)交換的一種協(xié)議。FastCGI:同 CGI,是一種通信協(xié)議,但比 CGI 在效率上做了一些優(yōu)化。PHP-...
摘要:是與之間數(shù)據(jù)交換的一種協(xié)議。當收到這個請求后,會啟動對應(yīng)的程序,這里就是的解析器。接下來解析器會解析文件,初始化執(zhí)行環(huán)境,然后處理請求,再以規(guī)定規(guī)定的格式返回處理后的結(jié)果,退出進程,再把結(jié)果返回給瀏覽器。 CGI:是 Web Server 與 Web Application 之間數(shù)據(jù)交換的一種協(xié)議。FastCGI:同 CGI,是一種通信協(xié)議,但比 CGI 在效率上做了一些優(yōu)化。PHP-...
閱讀 4620·2021-10-25 09:48
閱讀 3211·2021-09-07 09:59
閱讀 2167·2021-09-06 15:01
閱讀 2693·2021-09-02 15:21
閱讀 2732·2019-08-30 14:14
閱讀 2183·2019-08-29 13:59
閱讀 2514·2019-08-29 11:02
閱讀 2532·2019-08-26 13:33