关于 PHP 的 new static 延迟静态绑定,或者叫后期静态绑定,在 Laravel 中遇到一个使用上的问题。如下,在 Laravel 中调用 Model 新增数据的时候,首先给 Model 加了一个获取分表的方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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 里定义的获取分表的方法:
1
2
3
4
5
|
public function setTable( $table )
{
$this ->table = $table ;
return $this ;
}
|
从报错日志中发现 $this->table 并没有生效,但实际上在调用 create 方法之前打印表名的时候是期望的值,这里调用 create 方法为什么 $this->table 没有被重置呢?
这里 $this->message 是一个继承 Model 类的模型类,其中 create 方法:
1
2
3
4
5
6
7
8
|
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 属性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
<?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()的区别
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.tanteng.me/2017/08/php-new-static/