简体   繁体   中英

PHP 5.6: ArrayAccess: Function isset calls offsetGet and causes undefined index notice

I wrote simple PHP class that implements ArrayAccess Interface:

class MyArray implements ArrayAccess
{
    public $value;

    public function __construct($value = null)
    {
        $this->value = $value;
    }

    public function &offsetGet($offset)
    {
        var_dump(__METHOD__);

        if (!isset($this->value[$offset])) {
            throw new Exception('Undefined index: ' . $offset);
        }

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

    public function offsetExists($offset)
    {
        var_dump(__METHOD__);

        return isset($this->value[$offset]);
    }

    public function offsetSet($offset, $value)
    {
        var_dump(__METHOD__);

        $this->value[$offset] = $value;
    }

    public function offsetUnset($offset)
    {
        var_dump(__METHOD__);

        $this->value[$offset] = null;
    }
}

It works normally in PHP 7, but the problem in PHP 5.6 and HHVM.

If I call function isset() on undefined index, the PHP will call offsetGet() instead of offsetExists() which will cause Undefined index notice.

In PHP 7, it calls offsetGet() only if offsetExists() returns true , so there is no error.

I think that this is related to PHP bug 62059 .

The code is avalible at 3V4L, so you can see what is wrong. I added few more debug calls and throw exception if index is undefined because notices aren't shown in 3V4L: https://3v4l.org/7C2Fs

There shouldn't be any notice otherwise PHPUnit tests will fail. How can I fix this error?

It looks like this is a PHP bug in old versions of PHP and HHVM. Because PHP 5.6 is not supported anymore, this bug will not be fixed.

Quick fix is to add additional check in method offsetGet() and return null if index is undefined:

class MyArray implements ArrayAccess
{
    public $value;

    public function __construct($value = null)
    {
        $this->value = $value;
    }

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

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

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

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

    public function offsetUnset($offset)
    {
        $this->value[$offset] = null;
    }
}

See code at 3V4L and zerkms 's comments ( first , second , third ).

Im not sure i understood your question but maybe you could try

public function __construct($value =[]){
    $this->value = $value;
}

instead of:

public function __construct($value = null){
$this->value = $value;
}

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