Проверьте, существует ли свойство в магически заданных свойствах
Есть много вопросов о предмете, особенно этот, но это мне не помогает.
Существует двусмысленность между property_exists
и isset
, поэтому, прежде чем задавать свой вопрос, я укажу:
property_exists
property_exists проверяет, содержит ли объект свойство, не глядя на его значение, он смотрит только на visibility.
Итак, в следующем примере:
<?php
class testA
{
private $a = null;
}
class testB extends testA
{
}
$test = new testA();
echo var_dump(property_exists($test, 'a')); // true
// parent 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
с волшебными добавленными свойствами?
Ответы
Ответ 1
Я не верю, что есть способ изменить функциональность 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() возвращает ожидаемый результат, когда задано значение null.
Это имеет недостаток, а именно, что переопределенная функциональность не дает тех же результатов, что и функция isset() по умолчанию. Таким образом, если этот объект необходимо использовать прозрачно с другими объектами (возможно, stdClass), то isset() вернет true для нулевых значений в объектах этого класса и false для нулевых значений в обычных объектах.
В зависимости от ваших потребностей это может быть или не быть жизнеспособным решением. Если вышеуказанная проблема является помехой, другой вариант может заключаться в определении интерфейса с помощью свойства keyIsSet() и применении этого интерфейса ко всем объектам, которые будут проверяться. Затем используйте $obj-> keyIsSet ("ключ"), а не isset ($obj-> $ key). Не так элегантно, но немного лучше.
Ответ 2
Проблема заключается в реализации функций __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));
?>