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的紀錄