關于 php 的 new Static 延遲靜態綁定,或者叫后期靜態綁定,在 laravel 中遇到一個使用上的問題。如下,在 laravel 中調用 model 新增數據的時候,首先給 model 加了一個獲取分表的方法:
protected?function?addToMessage($msgType,?$userID,?$commentID,?$replyCommentID,?$replyUserID,?$gameID) { ????if?(!$userID)?{ ????????return?false; ????} ? ????$table?=?'t_message_'?.?hashID($userID,?100); ????$this->message->setTable($table)->create([ ????????'msg_type'?????????=>?$msgType, ????????'user_id'??????????=>?$userID, ????????'comment_id'???????=>?$commentID, ????????'reply_comment_id'?=>?$replyCommentID, ????????'reply_user_id'????=>?$replyUserID, ????????'game_id'??????????=>?$gameID, ????????'is_read'??????????=>?0, ????????'created_at'???????=>?date('Y-m-d?H:i:s'), ????]); ????return?true; }
這里 setTable 方法是在 Model 里定義的獲取分表的方法:
public?function?setTable($table) { ????$this->table?=?$table; ????return?$this; }
從報錯日志中發現 $this->table 并沒有生效,但實際上在調用 create 方法之前打印表名的時候是期望的值,這里調用 create 方法為什么 $this->table 沒有被重置呢?
這里 $this->message 是一個繼承 Model 類的模型類,其中 create 方法:
public?static?function?create(array?$attributes?=?[]) { ????$model?=?new?static($attributes); ? ????$model->save(); ? ????return?$model; }
位于 vendorlaravelframeworksrcIlluminateDatabaseEloquentModel.php Line 557.
因為 Laravel 框架的這個 Model 類是一個 abstract 類型,PHP 中 abstract 類可以用 new static 后期靜態綁定的方式實例化,而 create 方法里 $model = new static($attributes) 實際上就是重新實例化了并返回,而調用者 Model 類沒有定義 table 屬性,所以這個時候 $this->table 是沒有值的。
解決辦法是用 save 方法即可,如圖所示。實際上 create 方法也調用了 save 方法。
實驗
一個抽象類 A,有個 create 方法,通過延遲靜態綁定實例化并返回。B 類繼承 A,test 方法中修改父類的 name 屬性。
<?php abstract class A { protected $name = "tanteng"; public static function create() { return new static(); } } class B extends A { //protected $name = '紙牌屋弗蘭克'; public function test() { $this->name?=?"Tony?Tan"; ????????return?$this; ????} } ? $obj1?=?(new?B)->test(); $obj2?=?(new?B)->test()->create(); var_dump($obj1); var_dump($obj2);
結果顯示 $obj1 和 $obj2 這兩個實例都是 B 的實例,調用 test 方法屬性 name 改變了,但是調用 create 方法后,name 屬性并沒有改變。這也就是在本文中說的在 lavarel 中遇到的場景。(這里如果把注釋打開,打印的 name 就是重寫的值)
如果把抽象類 A 改成普通類,new static 改成 new self 的方式實例化,結果就不同了,打印的屬性 name 都是各自類的屬性。
更多Laravel相關技術文章,請訪問Laravel框架入門教程欄目進行學習!