15

关于这个主题有很多 SO 问题,尤其是这个问题,但这对我没有帮助。

和之间有歧义property_existsisset所以在问我的问题之前,我要指出:

property_exists

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检查属性中是否存在值,如果值等于falseand ,则考虑 is 未设置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

issetproperty_exists对神奇添加的属性的行为

一个属性可以存在一个null值,所以我不能使用__isset魔术方法来知道一个属性是否存在。我也不能property_exists使用魔法方法添加属性。

这是一个示例,但这只是一个示例,因为在我的应用程序中,神奇地设置的属性存储在 object 之外

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神奇添加的属性?

4

2 回答 2

7

我不相信有办法使用魔术方法来改变 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,对于普通对象中的 null 值返回 false。

根据您的需求,这可能是也可能不是可行的解决方案。如果上述问题是一个障碍,那么另一种选择可能是定义一个带有 keyIsSet() 属性的接口,并将该接口应用于所有要测试的对象。然后使用 $obj->keyIsSet('key') 而不是 isset($obj->$key)。没有那么优雅,但更好一点。

于 2014-01-13T22:22:44.970 回答
-1

问题在于__set__get功能的实现,我修改了它们并且适用于issetproperty_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));
?>
于 2013-05-24T07:47:30.387 回答