Problem: ArrayObject :: offsetGet () function returns null if item is not in array

I originally thought it would be a piece of cake .. not for me ..

I am trying to extend the offsetGet () function to return null if the element is not present in the ArrayObject. So far, I cannot get it to work without errors.

php -v: 5.3.29

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

My extended ArrayObject class:

class IssetArray extends \ArrayObject {

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

      

This is how I call 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 a regular ArrayObject, I don't get an indirect modification error. I am so confused about this issue.

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

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

While trying to do the same with ArrayAccess, I ran into the same problem. 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 leads to the same problem as ArrayObject. Please note, indirect modification of the overloaded element from \ IssetArray has no effect on the line -

+3


source to share


2 answers


Short answer: This is a nasty side effect of method overloading offsetGet()

from ArrayObject

.

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

      

As part of the destination, it is called ArrayObject::offsetGet('something')

and the return value is expected to return a reference; the problem is that, despite the definition &offsetGet()

, it doesn't actually return a link.

What you are actually returning is a temporary variable and therefore the notification is correct to assert that any changes made to that variable will not be reflected in the final array.



Btw, this doesn't happen if you implement ArrayAccess

; of course you don't get all the methods that come with ArrayObject

:(

Update

It seems from this report that HHVM exhibits correct behavior and PHP 7 does not generate any notifications (but has incorrect assignment behavior).

+2


source


I was able to follow the below implementation of ArrayAccess for my needs. I hope this helps anyone who has the same problems as me.

Thanks @Jack for helping me go in the right 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];
    }
}

      

+1


source







All Articles