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:01

In most cases where you have nested internal objects, it might be a good time to re-evaluate your data structures.

In the example above, person has contact and dob. The contact also contains address. Trying to access the data from the uppermost level is not uncommon when writing complex database applications. However, you might find your the best solution to this is to consolidate data up into the person class instead of trying to essentially "mine" into the internal objects.

查看更多
在下西门庆
3楼-- · 2019-05-16 11:04

try this code

$property = $contact->phone;
echo $person->$property;
查看更多
可以哭但决不认输i
4楼-- · 2019-05-16 11:05

I have decided to scrap this whole approach and go with a more long-winded but cleaner and most probably more efficient. I wasn't too keen on this idea in the first place, and the majority has spoken on here to make my mind up for me. Thank for you for your answers.

Edit:

If you are interested:

public function __construct($data)
{
  $this->_raw = $data;
}

public function getContactPhone()
{
  return $this->contact->phone;
}

public function __get($name) 
{
  if (isset($this->$name)) {
    return $this->$name;
  }

  if (isset($this->_raw->$name)) {
    return $this->_raw->$name;
  }

  return null;
}
查看更多
\"骚年 ilove
5楼-- · 2019-05-16 11:07

If it is legal it does not mean it is also moral. And this is the main issue with PHP, yes, you can do almost whatever you can think of, but that does not make it right. Take a look at the law of demeter:

Law of Demeter

try this if you really really want to: json_decode(json_encode($person),true);

you will be able to parse it as an array not an object but it does your job for the getting not for the setting.

EDIT:

class Adapter {

  public static function adapt($data,$type) {

  $vars = get_class_vars($type);

  if(class_exists($type)) {
     $adaptedData = new $type();
  } else {
    print_R($data);
    throw new Exception("Class ".$type." does not exist for data ".$data);
  }

  $vars = array_keys($vars);

  foreach($vars as $v) {

    if($v) {        
      if(is_object($data->$v)) {
          // I store the $type inside the object
          $adaptedData->$v = Adapter::adapt($data->$v,$data->$v->type);
      } else {
          $adaptedData->$v =  $data->$v;
      }
    }
  }
  return $adaptedData;

  }

}

查看更多
甜甜的少女心
6楼-- · 2019-05-16 11:07

As much as I hate saying it, you could do an eval :

foreach ($properties as $property) {
     echo eval("return \$person->$property;");
}
查看更多
Summer. ? 凉城
7楼-- · 2019-05-16 11:09

If you know the two function's names, could you do this? (not tested)

$a = [
    'contactPhone' => 'contact->phone', 
    'contactEmail' => 'contact->email'
];

foreach ($a as $name => $chain) {
    $std = new stdClass();
    list($f1, $f2) = explode('->', $chain);
    echo $std->{$f1}()->{$f2}(); // This works
}

If it's not always two functions, you could hack it more to make it work. Point is, you can call chained functions using variable variables, as long as you use the bracket format.

查看更多
登录 后发表回答