Check if a property exists on magically set properties

筅森魡賤 提交于 2019-12-04 10:26:07

问题


There is a lot of SO questions about the subject, notably this one, but it does not help me.

There is an ambiguity between property_exists and isset so before asking my question, I'm going to pointing it out:

property_exists

property_exists checks if an object contains a property without looking at its value, it only looks at its visibility.

So in the following example:

<?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 checks if a value exists in a property, considering that is is not set if a value equals false and 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 and property_exists's behaviour on magically added properties

A property can exist with a null value, so I can't use __isset magic method to know if a property exist or not. I also can't use property_exists as properties are added using magic methods.

Here is a sample, but this is just a sample because in my app, properties magically set are stored outside the 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

So here is my question :

Is there a magic method or an SPL interface to implement property_exist with magically added properties ?


回答1:


I don't believe there's a way to alter the functionality of property_exists() using magic methods; here's a list of available magic methods in PHP. However, you should be able to alter isset() to use any logic you like.

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

This effectively fixes the (annoying) problem with isset and nulls by overriding its functionality through the magic method. Instead of using isset() within __isset() however, we use array_key_exists (which handles nulls as you would expect). Thus __isset() returns the expected result when a null value is set.

This has a downside, namely that the overridden functionality does not produce the same results as default isset() functionality. So, if this object needs to be used transparently with other (perhaps stdClass) objects, then isset() will return true for null values in objects of this class, and false for null values in normal objects.

Depending on your needs then this may or may not be a viable solution. If the above issue is a hindrance, then another option might be to define an interface with a keyIsSet() property, and apply that interface to all objects to be tested. Then use $obj->keyIsSet('key') rather than isset($obj->$key). Not as elegant, but a bit better oo.




回答2:


Problem is with the implementation of __set and __get functions, I modified them and is works for both isset and 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));
?>


来源:https://stackoverflow.com/questions/16729830/check-if-a-property-exists-on-magically-set-properties

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!