我一直在ArrayAccess
和 PHP 的魔法 ( __get
,__set
) 开玩笑,现在我被困住了。
我正在尝试实现一个类,其中某些属性(即数组)是只读的。它们将由构造函数最初设置,但此后不应修改。
通过引用使用__get
魔法,我可以在属性中任意深度访问数组元素,我想当这些属性通过__set
.
问题是,当我访问数组元素的值时,PHP 调用__get
以通过引用返回数组的那一部分,我不知道它是读取还是写入操作。
(最糟糕的部分是我知道这会发生,但是考虑到属性是已实现对象的实例,我一直在愚弄ArrayAccess
作为一种可能的解决方法)
简单的例子:
class Test{
public function &__get($key){
echo "[READ:{$key}]\n";
}
public function __set($key, $value){
echo "[WRITE:{$key}={$value}]\n";
}
}
$test = new Test;
$test->foo;
$test->foo = 'bar';
$test->foo['bar'];
$test->foo['bar'] = 'zip';
和输出:
[READ:foo]
[WRITE:foo=bar]
[READ:foo]
[READ:foo] // here's the problem
实际上,无论如何我只需要该值foo
(根据我的示例),但我需要知道这是一个写入操作,而不是读取。
我已经接受了一半,这是无法实现的,但我仍然充满希望。有谁知道我想要完成的事情是如何完成的?
我正在考虑一些可能的解决方法ArrayAccess
,但据我所知,我最终会回到这个位置,因为我将使用调用__get
.
更新:另一个有趣的一天ArrayAccess
。
(这是一个不同的问题,但我想它可以解决。发帖只是为了好玩。)
class Mf_Params implements ArrayAccess{
private $_key = null;
private $_parent = null;
private $_data = array();
private $_temp = array();
public function __construct(Array $data = array(), $key = null, self $parent = null){
$this->_parent = $parent;
$this->_key = $key;
foreach($data as $key => $value){
$this->_data[$key] = is_array($value)
? new self($value, $key, $this)
: $value;
}
}
public function toArray(){
$array = array();
foreach($this->_data as $key => $value){
$array[$key] = $value instanceof self
? $value->toArray()
: $value;
}
return $array;
}
public function offsetGet($offset){
if(isset($this->_data[$offset])){
return $this->_data[$offset];
}
// if offset not exist return temp instance
return $this->_temp[$offset] = new self(array(), $offset, $this);
}
public function offsetSet($offset, $value){
$child = $this;
// copy temp instances to data after array reference chain
while(!is_null($parent = $child->_parent) && $parent->_temp[$child->_key] === $child){
$parent->_data[$child->_key] = $parent->_temp[$child->_key];
$child = $parent;
}
// drop temp
foreach($child->_temp as &$temp){
unset($temp);
}
if(is_null($offset)){
$this->_data[] = is_array($value)
? new self($value, null, $this)
: $value;
}else{
$this->_data[$offset] = is_array($value)
? new self($value, $offset, $this)
: $value;
}
}
public function offsetExists($offset){
return isset($this->_data[$offset]);
}
public function offsetUnset($offset){
unset($this->_data[$offset]);
}
}