$request->validate()原始碼解讀

zccccc發表於2020-09-04

:confused:作為一個新手,看laravel官方文件時,總會想去看看原始碼是怎麼實現的。

在看到表單驗證那一塊時,很好奇Request類呼叫validate方法與Validator::make()有什麼區別?

Validator::make()倒是一下子看懂了,其實這只是呼叫了個外觀類,但$request->validate()就有點看不懂了……

先去Request檔案看看

發現只寫了幾個註釋
@method array validate(array $rules, …$params)
並沒有相應的方法,去它的父類裡看發現也沒有

魔法方法__call()

這種時候就想到了__call() 可以呼叫非本類中的方法,一找發現還是沒有。
很納悶,用反射類獲取Request類的所有方法getMethods(),發現是有__call()的。
有點懵逼,遂發現Request用了幾個Traits,主意檢視,發現其中的Macroable是有__call()的

Macroable的__call()

那麼$request呼叫validate()一定是通過這個__call()的。看看裡面寫了啥。
發現這個方法非常簡單,就是看靜態陣列$macros中是否包含相應方法,有就呼叫。
那麼問題來了,$macros陣列中的方法是哪裡來的 :sob:laravel真的好繞

FoundationServiceProvider

Kernel在進行handle()處理請求時,會先進行bootstrap階段,這時會載入config/app中的provider,FoundationServiceProvider就是其中一個。它在register()階段,執行了registerRequestValidation()方法。

registerRequestValidation()

給靜態陣列$macros註冊validate、validateWithBag方法

原始碼:

file
// validator() 是在helper.php中
file
生成一個ValidationFactory(Illuminate\Contracts\Validation\Factory)的例項,並將該例項的validate方法註冊到$macros陣列中。
但是注意,這個Illuminate\Contracts\Validation\Factory是一個介面類,一定在什麼地方已經和一個具體類進行了繫結~ :speak_no_evil:

注意: 一般框架自帶的工具類,都會將簡稱和相應類名放在別名陣列中。知道是為什麼嗎?

在Illuminate\Foundation\Application的建構函式中,有一個registerCoreContainerAliases()方法,它裡面將一些簡稱和相應的類名關聯起來,放到aliases陣列和abstractAliases陣列中

file

做這些aliases陣列和abstractAliases陣列的目的呢,我之前沒想明白,現在明白了 就是在遇到像上面要例項化Illuminate\Contracts\Validation\Factory介面類時,自動做轉換,轉換為validator(而validator的繫結會在相應的provider中做掉)

結論

再來看看手動生成驗證器

Validator::make()呢其實就是通過Facade來操作例項

file
巧了,也是validator!說明手動生成驗證器和使用$request->validate() 其實呼叫的方法是一樣的。

Validator這種外觀類是怎麼實現的,我這裡就不說了,社群裡一篇帖子分享一下
部落格:深入淺出 Laravel 的 Facade 外觀系統

最後找找validator繫結的具體類

在config/app的providers中查詢,發現是在Illuminate\Validation\ValidationServiceProvider中register()時繫結了validator

file
繫結的類是Illuminate\Validation\Factory

一開始看laravel原始碼真的很痛苦,不過看多了會發現套路都差不多,努力學習!

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章