¿Cómo puedo acceder a una propiedad de objeto profunda nombrada como una variable (notación de punto) en php?

Hay muchas preguntas similares a esto, sin embargo, esto es ligeramente diferente ya que se trata de acceso a propiedades de objetos profundos, no solo de un nivel de profundidad.

Digamos que tengo una variable que contiene la cadena foo.bar .

 $user = new User(); $user->foo = new Foo(); $user->foo->bar = "Hello World"; $variable = "foo.bar" 

Me gustaría repetir $user->foo->bar haciendo uso de $variable :

 echo $user->foo->bar 

Esto es lo que he intentado hasta ahora pero sin éxito (dice NULL ):

 $value = str_replace(".", "->", $value); echo $user->{$value}; 

Es muy fácil reducir la ruta del objeto utilizando la notación de propiedad variable ( $o->$p ):

 $path = 'foo.bar'; echo array_reduce(explode('.', $path), function ($o, $p) { return $o->$p; }, $user); 

Esto podría convertirse fácilmente en una pequeña función de ayuda.

Estoy publicando esto como un cumplido de una respuesta ( ¿Cómo escribir getter / setter para acceder a la matriz de varios niveles por nombres clave? ) Que hace lo mismo para las matrices.

Cree el array $path mediante explode() (o agréguelo a la función), luego use referencias.

 $path = explode('.', $variable); 

Adquiridor

 function get($path, $object) { $temp = &$object; foreach($path as $var) { $temp =& $temp->$var; } return $temp; } $value = get($path, $user); 

Y, por supuesto, el evil eval() , no recomendado:

 $value = str_replace('.', '->', $variable); eval("echo \$user->$value;"); 

Se agregó una pequeña mejora a la publicación de @deceze.

Esto permite manejar casos donde también necesita pasar por arreglos.

 $path = 'foo.bar.songs.0.title'; echo array_reduce(explode('.', $path), function ($o, $p) { return is_numeric($p) ? $o[$p] : $o->$p; }, $user); 

Editar:

Y si tiene PHP 7+, entonces lo siguiente devolverá nulo de manera segura si el nombre de una propiedad está mal escrito o si no existe.

 $path = 'foo.bar.songs.0FOOBAR.title'; echo array_reduce(explode('.', $path), function ($o, $p) { return is_numeric($p) ? ($o[$p] ?? null) : ($o->$p ?? null); }, $user); 

No hay una manera fácil de hacerlo.

Sin embargo, afortunadamente, muchas personas quieren hacer esto, por lo que hay bibliotecas que lo admiten, como PropertyAccessor de Symfony:

http://symfony.com/doc/current/components/property_access.html