简体   繁体   中英

Trouble extending ArrayObject::offsetGet() function to return null if item not in array

Originally I was thinking this was going to be a piece of cake.. not for me..

I am trying to extend the offsetGet() function to return null if the item is not in the ArrayObject. So far I can not seem to get it working without errors.

php -v: 5.3.29

What am I doing wrong? Below is my code and the error:

My extended ArrayObject class:

class IssetArray extends \ArrayObject {

    public function &offsetGet($offset) {
        $var = $this->offsetExists($offset) ? parent::offsetGet($offset) : null;
        return $var;
    }
}

Here is how I am calling it:

$array = new \IssetArray();

$array['item'] = 123;
var_dump($array['item']);

var_dump($array['something']['noItem']);

$array['something']['foo'] = 'bar';
var_dump($array['something']['foo']);

$normalArrayObject = new \ArrayObject();
$normalArrayObject['something']['foo'] = 'bar';
var_dump($normalArrayObject['something']['foo']);
var_dump($normalArrayObject['something']['noItem']);

Outputs:

int(123)
NULL
Notice: Indirect modification of overloaded element of \IssetArray has no effect in -- on line --
NULL
string(3) "bar"
Notice: Undefined index: noItem in -- on line --
NULL

What am I doing wrong?? If I call the normal ArrayObject I don't get the indirect modification error. I am so confused at this point.

Any help would be wonderful. I have googled and googled with no luck.

Update -----------

When trying to do the same thing with ArrayAccess I run into the same issue. How can I get around this with ArrayAccess?

My implementation:

class IssetArray implements \ArrayAccess {

    private $container = array();

    public function __construct() {}

    public function offsetSet($offset, $value) {
        if (is_null($offset)) {
            $this->container[] = $value;
        } else {
            $this->container[$offset] = $value;
        }
    }

    public function offsetExists($offset) {
        return isset($this->container[$offset]);
    }

    public function offsetUnset($offset) {
        unset($this->container[$offset]);
    }

    public function &offsetGet($offset) {
        $var = isset($this->container[$offset]) ? $this->container[$offset] : null;

        return $var;
    }
}

This results in the same issue I am seeing with ArrayObject. Notice: Indirect modification of overloaded element of \\IssetArray has no effect in -- on line --

Short answer: this is a nasty side effect of overloading the offsetGet() method from ArrayObject .

$array['something']['foo'] = 'bar';

As part of the assignment, ArrayObject::offsetGet('something') is called and the return value is expected to return a reference; the problem is that, despite the definition of &offsetGet() , it doesn't in fact return a reference.

What you're really returning is a temporary variable and therefore the notice is correct to assert that any changes made on that variable will not be reflected in the final array.

Btw, this doesn't happen if you implement ArrayAccess instead; of course, you won't get all the methods that come with ArrayObject either :(

Update

It seems from this report that HHVM exhibits the correct behaviour and PHP 7 will not generate any notices (but has the wrong behaviour during assignment).

I was able to make the below implementation of ArrayAccess work perfectly for my needs. I hope this helps anyone who has the same type of problems that I had.

Thank you @Jack for helping me go in the correct direction!

class IssetArray implements \ArrayAccess {

    private $container = array();

    public function __construct() {}

    public function offsetSet($offset, $value) {
        if (is_null($offset)) {
            $this->container[] = $value;
        } else {
            $this->container[$offset] = $value;
        }
    }

    public function offsetExists($offset) {
        return isset($this->container[$offset]);
    }

    public function offsetUnset($offset) {
        unset($this->container[$offset]);
    }

    public function &offsetGet($offset) {
        if(!isset($this->container[$offset])) {
            $this->container[$offset] = null;
        }

        return $this->container[$offset];
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM