Проверьте, существует ли свойство в волшебных свойствах

Есть много ТАК вопросов по этому вопросу, особенно этот, но это не помогает меня.

Между property_exists и isset существует двусмысленность, поэтому, прежде чем задать свой вопрос, я укажу на это:

свойство_существует

property_exists проверяет, содержит ли объект свойство, не глядя на его значение. смотрит только на его видимость.

Итак, в следующем примере:

<?php

class testA
{
  private $a = null;
}
class testB extends testA
{
}

$test = new testA();
echo var_dump(property_exists($test, 'a')); // true

// parent's private property becomes invisible for its child

$test = new testB();
echo var_dump(property_exists($test, 'a')); // false

иссет

isset проверяет, существует ли значение в свойстве, учитывая, что это не так. устанавливается, если значение равно false и null.

<?php

$var = null;
echo var_dump(isset($var)); // false

$var = '';
echo var_dump(isset($var)); // true

$var = false;
echo var_dump(isset($var)); // true

$var = 0;
echo var_dump(isset($var)); // true

$var = '0';
echo var_dump(isset($var)); // true

Поведение isset и property_exists в магически добавленных свойствах

Свойство может существовать со значением null, поэтому я не могу использовать магический метод __isset, чтобы узнать, существует свойство или нет. Я также не могу использовать property_exists, так как свойства добавляются с помощью магических методов.

Вот пример, но это всего лишь пример, потому что в моем приложении свойства, заданные магическим образом, хранятся вне объекта.

class test {

    private $data = array();

    public function __get($key) {
        echo "get $key\n";
        return array_key_exists($key, $data) ? $data[$key] : null;
    }

    public function __set($key, $value) {
        echo "set $key = $value\n";
        $this->data[$key] = $value;
    }

    public function __isset($key) {
       echo sprintf("isset $key ( returns %b )", isset($this->data[$key]));
       return isset($this->data[$key]);
    }

}

$test = new test();
$test->x = 42;
isset($test->x); // 1

$test->y = null;
isset($test->y); // 0
property_exists($test, 'y'); // 0

Вот мой вопрос :

Есть ли волшебный метод или интерфейс SPL для реализации property_exist с волшебным образом добавленными свойствами?


person Alain Tiemblo    schedule 24.05.2013    source источник
comment
Предложение: используйте var_dump(), а не echo sprintf....   -  person Barmar    schedule 24.05.2013
comment
Также printf делает ровно echo sprintf   -  person Fyfey    schedule 01.10.2015


Ответы (2)


Я не верю, что есть способ изменить функциональность property_exists() с помощью магических методов; вот список доступных магических методов< /а> в PHP. Однако вы должны иметь возможность изменить isset(), чтобы использовать любую логику, которая вам нравится.

class test {

    private $data = array();

    public function __get($key) {
        echo "get $key\n";
        return array_key_exists($key, $this->data) ? $this->data[$key] : null;
    }

    public function __set($key, $value) {
        echo "set $key = $value\n";
        $this->data[$key] = $value;
    }

    public function __isset($key) {
       echo sprintf("isset $key ( returns %b )", array_key_exists($key, $this->data));
       return array_key_exists($key, $this->data);
    }

}

$test = new test();
$test->x = 42;
isset($test->x); // 1

$test->y = null;
isset($test->y); // 1

Это эффективно устраняет (раздражающую) проблему с isset и nulls, переопределяя его функциональность с помощью магического метода. Однако вместо использования isset() внутри __isset() мы используем array_key_exists (который обрабатывает нули, как и следовало ожидать). Таким образом, __isset() возвращает ожидаемый результат, когда установлено нулевое значение.

У этого есть обратная сторона, а именно то, что переопределенная функциональность не дает тех же результатов, что и функциональность isset() по умолчанию. Таким образом, если этот объект необходимо использовать прозрачно с другими (например, stdClass) объектами, то isset() вернет true для нулевых значений в объектах этого класса и false для нулевых значений в обычных объектах.

В зависимости от ваших потребностей это может быть или не быть жизнеспособным решением. Если указанная выше проблема является препятствием, другим вариантом может быть определение интерфейса со свойством keyIsSet() и применение этого интерфейса ко всем тестируемым объектам. Затем используйте $obj->keyIsSet('key'), а не isset($obj->$key). Не так элегантно, но немного лучше оо.

person opensourcejunkie    schedule 13.01.2014
comment
Просто, я не знаю, как я мог не подумать о array_key_exists раньше. Спасибо. - person Alain Tiemblo; 14.01.2014
comment
Хорошо, теперь я помню, когда мне это было нужно, мои свойства хранились ВНЕ текущего класса (в родительском), поэтому было невозможно использовать массив для их хранения, так как __get не должен был вызываться как свойство на самом деле существовал на конечном объекте. В любом случае, это старый вопрос, поэтому я оставляю ваш ответ принятым. - person Alain Tiemblo; 14.01.2014
comment
@AlainTiemblo Неважно, где вы храните свойства. property_exists() вернет true, если свойство установлено в родительском классе. Проблема возникает, когда вы не устанавливаете волшебное свойство, в котором свойство property_exists() найдет его, так как оно не может быть изменено. Смотрите мой ответ на это. - person bucabay; 06.11.2014

Проблема в реализации функций __set и __get, я изменил их и работает как для isset, так и для property_exists

<?php

class test {

    private $data = array();

    public function __get($key) {
        echo "get $key\n";
        return $$key;
    }

    public function __set($key, $value) {
        echo "set $key = $value\n";
        $this->$key = $value;
    }

    public function __isset($key) {
       echo sprintf("isset $key ( returns %b )", isset($this->$key));
       return isset($this->$key);
    }

}

$test = new test();
var_dump(property_exists($test, 'x'));
var_dump(isset($test->x));

$test->x = 42;

var_dump(property_exists($test, 'x'));
var_dump(isset($test->x));
?>
person Tahir Yasin    schedule 24.05.2013
comment
Как уже упоминалось, properties magically set are stored outside the object. Спасибо, в любом случае. - person Alain Tiemblo; 24.05.2013