drsc10888 2011-06-13 06:19
浏览 80
已采纳

Readonly多维数组属性,PHP

I've been fooling with ArrayAccess and PHP's magic (__get, __set) for awhile now, and I'm stuck.

I'm trying to implement a class in which some properties, which are arrays, are read only. They will be set initially by the constructor, but should not be modifiable thereafter.

Using __get magic by reference, I can access array elements arbitrarily deep in the properties, and I was thinking I can throw exceptions when those properties are targeted via __set.

The problem is though, when I'm accessing the value of an array element, PHP is calling __get to return that part of the array by reference, and I have no knowledge of whether or not its a read or write action.

(The worst part is I knew this going in, but have been fooling with ArrayAccess as a possible workaround solution, given the properties were instances of an implemented object)

Simple example:

class Test{
    public function &__get($key){
        echo "[READ:{$key}]
";
    }
    public function __set($key, $value){
        echo "[WRITE:{$key}={$value}]
";
    }
}

$test = new Test;

$test->foo;
$test->foo = 'bar';

$test->foo['bar'];
$test->foo['bar'] = 'zip';

And the output:

[READ:foo]
[WRITE:foo=bar]
[READ:foo]
[READ:foo] // here's the problem

Realistically, I only need the value foo (as per my example) anyways, but I need to know it's a write action, not read.

I've already half accepted that this cannot be achieved, but I'm still hopeful. Does anyone have any idea how what I'm looking to accomplish can be done?

I was considering some possible workarounds with ArrayAccess, but so far as I can tell, I'll end up back at this spot, given I'm going to use the property notation that invokes __get.


Update: Another fun day with ArrayAccess.

(This is a different issue, but I suppose it works in. Posting just for kicks.)

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]);
    }

}
  • 写回答

2条回答 默认 最新

  • doufu1504 2011-06-13 06:31
    关注

    You need to use a second class, implementing ArrayAccess, to use instead of your arrays. Then you will be able to control what is added to the array with the offsetSet() method:

    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];
        }
    }
    

    You can then initialize your ReadOnlyArray with your original array:

    $readOnlyArray = new ReadOnlyArray(array('foo', 'bar'));
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 matlab数字图像处理频率域滤波
  • ¥15 ELGamal和paillier计算效率谁快?
  • ¥15 file converter 转换格式失败 报错 Error marking filters as finished,如何解决?
  • ¥15 ubuntu系统下挂载磁盘上执行./提示权限不够
  • ¥15 Arcgis相交分析无法绘制一个或多个图形
  • ¥15 关于#r语言#的问题:差异分析前数据准备,报错Error in data[, sampleName1] : subscript out of bounds请问怎么解决呀以下是全部代码:
  • ¥15 seatunnel-web使用SQL组件时候后台报错,无法找到表格
  • ¥15 fpga自动售货机数码管(相关搜索:数字时钟)
  • ¥15 用前端向数据库插入数据,通过debug发现数据能走到后端,但是放行之后就会提示错误
  • ¥30 3天&7天&&15天&销量如何统计同一行