在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's private property becomes invisible for its child $test = new testB(); echo var_dump(property_exists($test,'a')); // false
isset
isset检查属性中是否存在值,如果值等于false,则检查是否未设置.
<?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在神奇添加的属性上的行为
一个属性可以存在一个空值,所以我不能使用__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
所以这里是我的问题:
Is there a magic method or an SPL interface to implement
property_exist
with magically added properties ?
class test { private $data = array(); public function __get($key) { echo "get $key\n"; return array_key_exists($key,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和null.而不是在__isset()中使用isset(),而是使用array_key_exists(它将按预期处理null).因此__isset()在设置空值时返回预期结果.
这有一个缺点,即覆盖的功能不会产生与default isset()功能相同的结果.因此,如果此对象需要与其他(可能是stdClass)对象透明地使用,则isset()将为此类的对象中的空值返回true,对于正常对象中的空值为false.
根据您的需求,这可能是或可能不是一个可行的解决方案.如果上述问题是一个障碍,那么另一个选择可能是定义一个具有keyIsSet()属性的接口,并将该接口应用于要测试的所有对象.然后使用$obj-> keyIsSet(‘key’)而不是isset($obj-> $key).不如优雅,但有点好哦.