PHP Reflection 應用集 用來讀取function, class 內容資
前言
PHP Reflection 最早出在php 5.0的時代就已經有了,Reflection可以用來讀取某個class的原始碼片段描述,或者function內容等等資訊,這次要來整理一下幾個應用場景
1.讀取Model class中記錄的自行定義的資料
2.讀取Model class中原有定義的Relation,例如has many, has one 等等
3.讀取某個function定義的Attribute
參考連結
https://developer.aliyun.com/article/33171
https://www.cnblogs.com/phpphp/p/17807799.html
讀取Model class中記錄的自行定義的資料
在某次的需求中,我們做到了讓controller自動判定哪些前端傳過來的欄位需要做檔案處理,因此我們將這些需要被當成檔案處理的資訊記錄在Model中,如以下
1 2 3 4 5 6 7 8 |
class Customer extends Model { ..... protected array $file_columns = [ 'files' ]; ..... } |
這樣子描述,我們就可以知道要寫入Customer這張表的資料有一個叫做files的欄位需要經過檔案處理才能寫入資料庫,這樣一來我們就可以在controller中像這樣處理它
1 2 3 4 5 6 7 8 9 10 11 12 |
class CustomerController extends Controller { public function create(Request $request) { $model_class = new (Customer::class); $target_model = new ReflectionClass($model_class); if($target_model->hasProperty('file_columns')){ $file_columns = $target_model->getProperty('file_columns')->getValue($model_class); //處理檔案的其他原始碼 } } } |
這時候可以預期$file_columns會是Customer Model中寫的”files”一個欄位
這樣就可以搭配前端傳過來的欄位照到對應的”files”來做剩下的檔案處理啦[可以參考這篇]
讀取Model class中原有定義的Relation,例如has many, has one 等等
如果你想到取得一個Model Class中定義的relation list,可以像以下這樣做
Model Class中我們先把relation定義好
1 2 3 4 5 6 7 8 9 10 11 12 |
class Customer extends Model { ..... public function contact_list(): HasMany { return $this->hasMany(CustomerContact::class, 'customer_id', 'id'); }, public function identity_list(): HasMany { return $this->hasMany(CustomerIdentity::class, 'customer_id', 'id'); } ..... } |
接著在Controller中就可以透過以下操作取得contact_list,以及identity_list兩者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
class CustomerController extends Controller { public function create(Request $request) { $model_class = new (Customer::class); $target_model = new ReflectionClass($model_class); $relations = array_keys(array_reduce( $target_model->getMethods(ReflectionMethod::IS_PUBLIC), function ($result, ReflectionMethod $method) { // If this function has a return type ($returnType = (string) $method->getReturnType()) && // And this function returns a relation is_subclass_of($returnType, Relation::class) && // Add name of this method to the relations array ($result = array_merge($result, [$method->getName() => $returnType])); return $result; }, [] )); } } |
讀取某個function定義的Attribute
上一篇,我們提到了如何定義Attribute,並且把它拿出來做使用
這邊我們就詳細來看一下怎麼透過Reflection取得Attribute
假設我們有一個Controller定義如下
1 2 3 4 5 6 7 |
class APIController extends Controller { #[APITag(name:'id_number',type: 'string',required: true,description: '統一編號')] #[APITag(name:'name',type: 'string',required: true,description: '公司名字')] public function company_verify(Request $request): bool { } } |
那麼,你可以寫一個Artisan Command就能查詢所有API的參數條件了,大概像這樣子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
$all_routes = [];//你的所有API route $Api_routes_data = []; foreach ($all_routes as $route){ list($controller,$method) = explode('@',$route->getActionName()); $controller_method = new ReflectionMethod($controller,$method); $attributes = $controller_method->getAttributes(APITag::class); $params = array_map(function ($attribute) { return $attribute->getArguments(); },$attributes); $api_element = [ 'method' => implode('|', $route->methods()), 'uri' => $route->uri(), 'param' => $params, ]; $Api_routes_data[] = $api_element; } |
$Api_routes_data儲存的結果就是所有API的Controller中Attribute所描述的內容以及URi , method name等等資訊啦
以上,近期開發中運用Reflection的紀錄