如何通過查原始碼的方式解決程式設計中遇到的問題?

語言: CN / TW / HK

點選進入“PHP開源社群”    

免費獲取進階面試、文件、視訊資源

一.首先丟擲疑問:

1.laravel的底層是如何處理HTTP請求的?

2.laravel的Request是如何實現的?

3.為什麼不需要配置Nginx的url解析,也不需要在laravel的router中配置引數名稱,卻可以通過Request接收到引數呢?實現原理是什麼?

二. 下面開始進入查原始碼之旅:

1.首先調研了一下laravel的request是基於什麼實現的?

2.知識點如下:laravel的很多底層元件是基於Symfony實現的,比如:請求、響應、cookie、命令列,檔案等。其中HttpFoundation元件是http請求中比較重要的基礎元件,它可以獨立於Symfony使用的,laravel基於此做了進一步的封裝,使用示例如下

$request->input('param');

$request->cookie('cookie');

$request->file('file');

3.考慮到laravel專案所有的HTTP請求都會轉發到laravel的入口檔案(public/index.php),所以我們檢視這個檔案一探究竟:

//建立Application例項,作為服務容器

$app = new Illuminate\Foundation\Application(

realpath(__DIR__.'/../')

);



//以單例方式在服務容器中將 App\Http\Kernel 例項繫結到 Illuminate\Contracts\Http\Kernel 介面

$app->singleton(

Illuminate\Contracts\Http\Kernel::class,

App\Http\Kernel::class

);



//服務容器建立處理 HTTP 請求的核心例項(Kernel)

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);



//核心方法:處理 HTTP 請求的核心程式碼(核心程式碼會在下一部分展開來講,先從上而下理清流程)

$response = $kernel->handle(

$request = Illuminate\Http\Request::capture()

);



//傳送響應給傳送請求的客戶端

$response->send();



//核心例項終止程式,基於傳入的request和response做一些收尾工作

$kernel->terminate($request, $response);

4.上面的註釋已經比較清楚的解釋了laravel處理HTTP請求的內部實現流程。

5.我們再繼續深入核心程式碼,研究一下“laravel為什麼在路由中無需指定引數是什麼,在控制器方法中傳入Request就可以獲得引數了呢?”

比如:

//路由

Route::resource('/index', 'IndexController');



//controller中的方法

function index(Request $request)

{

switch ($request->type) {

.

.

.

}

}

6.下面的非核心程式碼用豎著的3個.省略,避免誤導

//laravel專案的入口檔案 index.php

.

.

.

//重點1:handle()方法

$response = $kernel->handle(

$request = Illuminate\Http\Request::capture()

);

.

.

.





//深入原始碼1 capture()

public static function capture()

{

static::enableHttpMethodParameterOverride();

//重點2:createFromBase() 方法

return static::createFromBase(SymfonyRequest::createFromGlobals());

}



//我們再深入原始碼2 createFromBase()

public static function createFromBase(SymfonyRequest $request)

{

if ($request instanceof static) {

return $request;

}



$content = $request->content;



//這是解決疑問的關鍵程式碼 duplicate 意為複製一份

$request = (new static)->duplicate(

$request->query->all(), $request->request->all(), $request->attributes->all(),

$request->cookies->all(), $request->files->all(), $request->server->all()

);



$request->content = $content;



$request->request = $request->getInputSource();



return $request;

}

7.發現了一個神奇的方法:duplicate(),意為複製一份。

8.duplicate()方法的引數,包括$request->query->all(), $request->request->all()…等,即底層已經實現了所有query和request的接收,我們不需要單獨宣告也是可以接收到所有請求引數的。

$request = (new static)->duplicate(

$request->query->all(), $request->request->all(), $request->attributes->all(),

$request->cookies->all(), $request->files->all(), $request->server->all()

);

9.上 面就是我查詢原始碼的流程:

a.明確自己的問題(Request的底層實現)

b明確自己排查問題的邊界(從入口檔案入手)

c.一層一層的深入查詢原始碼(原始碼1->原始碼2–>原始碼3)

d.排除非核心程式碼,找到最核心程式碼(duplicate()方法)

三.最後 還有一個小插曲:

原始碼這麼寫的原因是什麼?不是重複操作嗎?

不認真呀,仔細看一下,2中的request是通過 (new static)->duplicate()克隆的新物件,和1中的request並不是相同的例項。

*宣告:本文於網路整理,版權歸原作者所有,如來源資訊有誤或侵犯權益,請聯絡我們刪除或授權事宜。

END

PHP開源社群

掃描關注  進入”PHP資料“

免費獲取進階

面試、文件、視訊資源

點選“檢視原文”獲取更多