Проблема с расширением функции ArrayObject::offsetGet() для возврата значения null, если элемент не находится в массиве

Первоначально я думал, что это будет кусок пирога.. не для меня..

Я пытаюсь расширить функцию offsetGet(), чтобы она возвращала ноль, если элемент отсутствует в ArrayObject. Пока я не могу заставить его работать без ошибок.

php -v: 5.3.29

Что я делаю неправильно? Ниже мой код и ошибка:

Мой расширенный класс ArrayObject:

class IssetArray extends \ArrayObject {

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

Вот как я это называю:

$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']);

Выходы:

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

Что я делаю неправильно?? Если я вызываю обычный ArrayObject, я не получаю косвенную ошибку модификации. Я в таком замешательстве.

Любая помощь будет замечательной. Я гуглил и гуглил без удачи.

Обновить -----------

При попытке сделать то же самое с ArrayAccess я сталкиваюсь с той же проблемой. Как я могу обойти это с ArrayAccess?

Моя реализация:

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

Это приводит к той же самой проблеме, которую я вижу с ArrayObject. Примечание: косвенное изменение перегруженного элемента \IssetArray не оказывает никакого влияния на

2 ответа

Решение

Короткий ответ: это неприятный побочный эффект перегрузки offsetGet() метод из ArrayObject,

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

Как часть задания, ArrayObject::offsetGet('something') вызывается и ожидается, что возвращаемое значение вернет ссылку; проблема в том, что, несмотря на определение &offsetGet(), это на самом деле не возвращает ссылку.

То, что вы действительно возвращаете, является временной переменной, и, следовательно, уведомление является правильным, чтобы утверждать, что любые изменения, внесенные в эту переменную, не будут отражены в конечном массиве.

Кстати, это не произойдет, если вы реализуете ArrayAccess вместо; конечно, вы не получите все методы, которые идут с ArrayObject или:(

Обновить

Из этого отчета видно, что HHVM демонстрирует правильное поведение, а PHP 7 не будет генерировать никаких уведомлений (но имеет неправильное поведение во время назначения).

Мне удалось заставить приведенную ниже реализацию ArrayAccess работать идеально для моих нужд. Надеюсь, это поможет всем, у кого проблемы такого же типа, как у меня.

Спасибо @Jack за помощь в правильном направлении!

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];
    }
}
Другие вопросы по тегам