PHP: Class property chaining in variable variables

2019-05-16 10:24发布

So, I have a object with structure similar to below, all of which are returned to me as stdClass objects

$person->contact->phone;
$person->contact->email;
$person->contact->address->line_1;
$person->contact->address->line_2;
$person->dob->day;
$person->dob->month;
$person->dob->year;
$album->name;
$album->image->height;
$album->image->width;
$album->artist->name;
$album->artist->id;

etc... (note these examples are not linked together).

Is it possible to use variable variables to call contact->phone as a direct property of $person?

For example:

$property = 'contact->phone';
echo $person->$property;

This will not work as is and throws a E_NOTICE so I am trying to work out an alternative method to achieve this.

Any ideas?

In response to answers relating to proxy methods:

And I would except this object is from a library and am using it to populate a new object with an array map as follows:

array(
  'contactPhone' => 'contact->phone', 
  'contactEmail' => 'contact->email'
);

and then foreaching through the map to populate the new object. I guess I could envole the mapper instead...

14条回答
别忘想泡老子
2楼-- · 2019-05-16 11:09

Simplest and cleanest way I know of.

function getValueByPath($obj,$path) {
    return eval('return $obj->'.$path.';');
}

Usage

echo getValueByPath($person,'contact->email');
// Returns the value of that object path
查看更多
干净又极端
3楼-- · 2019-05-16 11:13

If i was you I would create a simple method ->property(); that returns $this->contact->phone

查看更多
做自己的国王
4楼-- · 2019-05-16 11:13

Besides making function getPhone(){return $this->contact->phone;} you could make a magic method that would look through internal objects for requested field. Do remember that magic methods are somewhat slow though.

class Person {
    private $fields = array();

    //...

    public function __get($name) {
        if (empty($this->fields)) {
            $this->fields = get_class_vars(__CLASS__);
        }
        //Cycle through properties and see if one of them contains requested field:
        foreach ($this->fields as $propName => $default) {
            if (is_object($this->$propName) && isset($this->$propName->$name)) {
                return $this->$propName->$name;
            }
        }
        return NULL;
        //Or any other error handling
    }
}
查看更多
相关推荐>>
5楼-- · 2019-05-16 11:15

You could use type casting to change the object to an array.

$person = (array) $person;

echo $person['contact']['phone'];
查看更多
Explosion°爆炸
6楼-- · 2019-05-16 11:16

Is it possible to use variable variables to call contact->phone as a direct property of $person?

It's not possible to use expressions as variable variable names.

But you can always cheat:

class xyz {

    function __get($name) {

        if (strpos($name, "->")) {
            foreach (explode("->", $name) as $name) {
                $var = isset($var) ? $var->$name : $this->$name;
            }
            return $var;
        }
        else return $this->$name;
    }
}
查看更多
Summer. ? 凉城
7楼-- · 2019-05-16 11:16

I think this is a bad thing to to as it leads to unreadable code is is plain wrong on other levels too, but in general if you need to include variables in the object syntax you should wrap it in braces so that it gets parsed first.

For example:

$property = 'contact->phone';
echo $person->{$property};

The same applies if you need to access an object that has disalowed characters in the name which can happen with SimpleXML objects regularly.

$xml->{a-disallowed-field}
查看更多
登录 后发表回答