浅谈Laravel中的一个后期静态绑定
关于 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; }
位于 vendor\laravel\framework\src\illuminate\database\eloquent\model.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 都是各自类的属性。
参考链接
php中new self()和new static()的区别
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。