PHP: a chain of class properties in variable variables

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

$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 that these examples are not related to each other).

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

For instance:

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

This will not work as it is and throws it away E_NOTICE, so I am trying to devise an alternative method for this.

Any ideas?

In response to responses related to proxy methods:

And I would like to exclude this object from the library and use it to populate a new object with an array map as follows:

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

and then go through the map to fill in the new facility. I guess I could lure the mapper ...

+3
14

, , , . , , . .

Edit:

:

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;
}
0

, ->property();, $this->contact->phone

+3

contact- > phone $person?

.

:

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;
    }
}
+3

$property = $contact->phone;
echo $person->$property;
+2

, , , , , , , .

:

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

, disavowed , SimpleXML .

$xml->{a-disallowed-field}
+2

, , . PHP, , , , . demeter:

, : json_decode (json_encode ($ ), );

, , .

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;

  }

}

+2

. , , phone person. .

"" , , , , . , (, , ) :

class conv {
 static function phone( $person ) {
   return $person->contact->phone;
 }

}

// imagine getting a Person from db
$person = getpersonfromDB();

print conv::phone( $p );

, . imho the nices: , , /.

- "" person , :

class ConvPerson extends Person {
   function __construct( $person ) {
     Person::__construct( $person->contact, $person->name, ... );
   }
   function phone() { return $this->contact->phone; }
}

// imagine getting a Person from db
$person = getpersonfromDB();
$p=new ConvPerson( $person );
print $p->phone();
0

.

$person = (array) $person;

echo $person['contact']['phone'];
0

, , , .

dob. . . , - person, "" .

0

, eval:

foreach ($properties as $property) {
     echo eval("return \$person->$property;");
}
0

function getPhone(){return $this->contact->phone;}, , . , , .

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
    }
}
0

, node. "" .

:

function retrieve( $obj, $path ) {
    $element=$obj;
    foreach( $path as $step ) { 
       $element=$element[$step];
    }
    return $element;
}

function decorate( $decos, &$object ) {
   foreach( $decos as $name=>$path ) {
      $object[$name]=retrieve($object,$path);
   }
}

$o=array( 
  "id"=>array("name"=>"Ben","surname"=>"Taylor"),
  "contact"=>array( "phone"=>"0101010" )
);

$decorations=array(
  "phone"=>array("contact","phone"),
  "name"=>array("id","name")  
);

// this is where the action is
decorate( $decorations, &$o);
print $o->name;
print $o->phone;

( codepad)

0

, ? ( )

$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 these are not always two functions, you can hack it more so that it works. Point, you can call related functions using variable variables if you use the bracket format.

0
source

The easiest and cleanest way I know about.

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

Using

echo getValueByPath($person,'contact->email');
// Returns the value of that object path
-1
source

All Articles