Fluent 的一个坑
Fluent 是一个很方便的 model ,有一处需要注意的地方,就是用数组方式操作 (ArrayAccess
) 时可能会直接读写到已定义的属性(property)。
比如 setter 方法:
public function __set($key, $value)
{
$this->attributes[$key] = $value;
}
public function offsetSet($offset, $value)
{
$this->{$offset} = $value;
}
如果我们的 Fluent 子类有一个属性 $foo
,那么调用 $model['foo'] = 'bar';
会直接覆盖 $foo
这个属性值,不论 $foo
是 private 还是 public 的;而 $model->foo = 'bar';
则是修改 $attributes['foo'] = 'bar'
.
:warning: 数组方式的 get, set, isset, unset 操作 Fluent 都存在这个问题。
>>> $model = new Illuminate\Support\Fluent; $model->attributes = 'bar'; dd($model);
Illuminate\Support\Fluent {#935
#attributes: array:1 [
"attributes" => "bar"
]
}
>>> $model = new Illuminate\Support\Fluent; $model['attributes'] = 'bar'; dd($model);
Illuminate\Support\Fluent {#936
#attributes: "bar"
}
这个是 Laravel 的一个历史遗留问题,我也提交过一个 PR 让数组方式直接操作 $attributes 数组,但是因为此修改对用户代码的影响太大,PR 被关闭了。
建议使用 Fluent 时重写相关方法,以避免私有的 property 被覆盖或者 $model['attributes'] = ...
导致程序崩溃。
trait FluentArrayAccess
{
/**
* Get an attribute from the container.
*
* @param string $key
* @param mixed $default
* @return mixed
*/
abstract public function get($key, $default = null);
/**
* Determine if the given offset exists.
*
* @param string $offset
* @return bool
*/
public function offsetExists($offset)
{
return isset($this->attributes[$offset]);
}
/**
* Get the value for a given offset.
*
* @param string $offset
* @return mixed
*/
public function offsetGet($offset)
{
return $this->get($offset);
}
/**
* Set the value at the given offset.
*
* @param string $offset
* @param mixed $value
* @return void
*/
public function offsetSet($offset, $value)
{
$this->attributes[$offset] = $value;
}
/**
* Unset the value at the given offset.
*
* @param string $offset
* @return void
*/
public function offsetUnset($offset)
{
unset($this->attributes[$offset]);
}
}
:point_right: Laravel 官网镜像 :cn:
Fluent这个类是用来做什么的?
@相惜恨离 就是个 model 的基类,用一个数组维护动态属性,提供了数组存取方式访问和修改这些动态属性值。简易版的 Eloquent.
兄dei,过了10个月了你理解了吗?
这两个方法是想让你在调用
offsetSet
时会自动重载到__set
的意思呀,attributes
当做个关键字不要用就好了