Неожиданное содержимое массива в классе с использованием __get, __set и __unset - PullRequest
0 голосов
/ 23 июня 2010

Я создал короткую демонстрацию проблемы, с которой я столкнулся. Это не совсем то, как я это реализую, но, похоже, приводит к тому же результату.

<?php

class mainclass {

    var $vardata = array();

    function &__get ($var) {
        if ($this->vardata[$var]) return $this->vardata[$var];
        if ($var == 'foo') return $this->_loadFoo();
        return NULL;
    }

    function __set ($var, $val) {
        $this->vardata[$var] = $val;
    }

    function __unset($var) {
        unset($this->vardata[$var]);
    }

}

class extender extends mainclass {

    function __construct() {

        var_dump($this->foo);
        $this->_loadFoo();
        echo '<br>';
        var_dump($this->foo);

    }

    function _loadFoo () {

        unset($this->foo);
        $this->foo = array();

        $this->foo[] = 'apples';
        $this->foo[] = 'oranges';
        $this->foo[] = 'pears';

        return $this->foo;

    }

}


$test = new extender;

?>

Вывод вышеуказанного кода:

array(3) { [0]=>  string(6) "apples" [1]=>  string(7) "oranges" [2]=>  string(5) "pears" }
array(5) { [0]=> string(6) "apples" [1]=> string(7) "oranges" [2]=> string(5) "pears" [3]=> string(7) "oranges" [4]=> string(5) "pears" } 

Где, как я ожидал:

array(3) { [0]=>  string(6) "apples" [1]=>  string(7) "oranges" [2]=>  string(5) "pears" }
array(3) { [0]=>  string(6) "apples" [1]=>  string(7) "oranges" [2]=>  string(5) "pears" }

Все функции __get, __set и __unset вызываются в нужных местах, и поэтому я ожидал, что второй прямой вызов функции просто сбросит $ this-> foo и снова заполнит ее теми же данными. Это означает, что var_dumping даст тот же результат. Вместо этого он заканчивает тем, что делал выше ... заполняя его двумя непосредственно установленными тремя строками и сохраняя первые три первоначально установленных строки.

Возможно, просто глупая ошибка или неправильное понимание функций перегрузки - в любом случае, я застрял здесь слишком долго, и поэтому любая помощь очень ценится!

1 Ответ

0 голосов
/ 23 июня 2010

В вашем коде было много ошибок:

  • if ($this->vardata[$var]) - это не способ проверить, существует ли переменная;isset или (если разрешены нули, array_key_exists) - это.
  • mainclass вызвал функцию, которой у него нет.Вы должны были объявить его абстрактным (в противном случае он все равно работал бы, но вы бы столкнулись с ошибками, если бы создали экземпляр основного класса).отсутствует элемент массива (работа с побочными эффектами) или возвращает значение по умолчанию для свойства foo.Поскольку вы возвращаетесь по ссылке в __get, я полагаю, вы хотите иметь фактическую переменную, а не просто возвращаемое значение, поэтому я пошел по первому маршруту.Вы _loadFoo делали обе вещи - устанавливали индекс отсутствующего массива и возвращали значение;чтобы усложнить то, что вы не устанавливали индекс массива напрямую, вы полагались на перегрузки.

Исправленная версия:

<?php

abstract class mainclass {

    var $vardata = array();

    function &__get ($var) {
        if (isset($this->vardata[$var])) return $this->vardata[$var];
        if ($var == 'foo') {
            $this->_loadFoo(); /* called for collaterals */
            return $this->foo;
        }
        return NULL;
    }

    abstract function _loadFoo();

    function __set ($var, $val) {
        $this->vardata[$var] = $val;
    }

    function __unset($var) {
        unset($this->vardata[$var]);
    }

}

class extender extends mainclass {

    function __construct() {

        var_dump($this->foo);
        $this->_loadFoo();
        echo '<br>';
        var_dump($this->foo);

    }

    function _loadFoo () {

        unset($this->foo);
        $this->foo = array();

        $this->foo[] = 'apples';
        $this->foo[] = 'oranges';
        $this->foo[] = 'pears';

    }

}

$test = new extender;
...