问题描述
||
我一直在和
ArrayAccess
和PHP \'s magic(__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
(根据我的示例),但是我需要知道这是写操作,而不是读操作。
我已经一半接受了这一目标,但我仍然充满希望。有谁知道我要完成的目标吗?
我正在考虑使用ѭ0的一些可能的解决方法,但据我所知,假设我将使用调用ѭ1的属性符号,那么我将回到这个位置。
更新:Another0ѭ又是有趣的一天。
(这是一个不同的问题,但是我想它可以使用。仅用于踢球。)
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,$this)
: $value;
}
}
public function offsetExists($offset){
return isset($this->_data[$offset]);
}
public function offsetUnset($offset){
unset($this->_data[$offset]);
}
}
解决方法
您需要使用实现implementing0ѭ的第二个类来代替数组。然后,您将可以使用
offsetSet()
方法控制添加到数组的内容:
class ReadOnlyArray implements ArrayAccess {
private $container = array();
public function __construct(array $array) {
$this->container = $array;
}
public function offsetSet($offset,$value) {
throw new Exception(\'Read-only\');
}
public function offsetExists($offset) {
return isset($this->container[$offset]);
}
public function offsetUnset($offset) {
unset($this->container[$offset]);
}
public function offsetGet($offset) {
if (! array_key_exists($offset,$this->container)) {
throw new Exception(\'Undefined offset\');
}
return $this->container[$offset];
}
}
然后可以用原始数组初始化ReadOnlyArray
:
$readOnlyArray = new ReadOnlyArray(array(\'foo\',\'bar\'));
, 您不能通过ref返回,这将解决可更改性问题,但不允许更改允许更改的某些值。
另外,您也需要将每个返回的数组都包装在ArrayAccess中-并禁止在那里进行写访问。