Dynamically access nested object
I'm building a Geocoding class that can utilize multiple webservices for Geocoding (ie Google, Yahoo, Bing, etc.). I'm trying to make it in a such a way that new webservices can be easily configured. Most of the webservices return either XML/JSON.. for PHP I chose XML as my primary focus. All the code is already in place, but now Google for instance returns the following XML (transformed to a simple_xml_element)
SimpleXMLElement Object
(
[status] => OK
[result] => Array
(
[0] => SimpleXMLElement Object
(
[type] => postal_code
[formatted_address] => 1010 Lausanne, Switzerland
[address_component] => Array
(
[0] => SimpleXMLElement Object
(
[long_name] => 1010
[short_name] => 1010
[type] => postal_code
)
[1] => SimpleXMLElement Object
(
[long_name] => Lausanne
[short_name] => Lausanne
[type] => Array
(
[0] => locality
[1] => political
)
)
[2] => SimpleXMLElement Object
(
[long_name] => Vaud
[short_name] => VD
[type] => Array
(
[0] => administrative_area_level_1
[1] => political
)
)
[3] => SimpleXMLElement Object
(
[long_name] => Switzerland
[short_name] => CH
[type] => Array
(
[0] => country
[1] => political
开发者_运维技巧 )
)
)
[geometry] => SimpleXMLElement Object
(
[location] => SimpleXMLElement Object
(
[lat] => 46.5376186
[lng] => 6.6539665
)
[location_type] => APPROXIMATE
[viewport] => SimpleXMLElement Object
(
[southwest] => SimpleXMLElement Object
(
[lat] => 46.5253574
[lng] => 6.6384420
)
[northeast] => SimpleXMLElement Object
(
[lat] => 46.5467887
[lng] => 6.6745222
)
)
[bounds] => SimpleXMLElement Object
(
[southwest] => SimpleXMLElement Object
(
[lat] => 46.5253574
[lng] => 6.6384420
)
[northeast] => SimpleXMLElement Object
(
[lat] => 46.5467887
[lng] => 6.6745222
)
)
)
)
)
The information I need is in the [location] tag, so I've tried storing the path in a var:
$lat_path = 'result[0]->geometry->location->lat;
And then try to access the value this way:
(suppose $xml is the object)
$xml->{$lat_path};
But this doens't work. Is there any way I can access the information dynamically or variable based. I do not want to ruin my Geocoding method with Google specific code.
Thanks!
When you do
$xml->{$lat_path};
PHP will use anything within $lat_path
as the variable name. It will not go into the object graph or obey the T_OBJECT_OPERATOR
at all. It will simply look for a property
'result[0]->geometry->location->lat;'
in $xml
. Try to run this code for an example:
$obj = new StdClass;
$obj->{'result[0]->geometry->location->lat;'} = 1;
print_r($obj);
It will output
stdClass Object
(
[result[0]->geometry->location->lat;] => 1
)
As you can see, it is one single property, not a nested object graph.
Like suggested in the comments, either use XPath or go to the desired value directly:
$xml->result[0]->geometry->location->lat;
If you're not able to use xPath and need to access a object dynamically, you can use the following approach:
$oObj = new StdClass;
$oObj->Root->Parent->ID = 1;
$oObj->Root->Parent->Child->ID = 2;
$sSeachInTree = 'Root\\Parent\\Child\\ID';
$aElements = explode("\\",$sSeachInTree);
foreach($aElements as $sElement)
{
if (isset($oObj->{$sElement}))
{
if (end($aElements) == $sElement)
{
echo "Found: " . $sElement . " = " . $oObj->{$sElement};
}
$oObj = $oObj->{$sElement};
}
}
I ran into this issue today. Here was my solution.
<?php
/**
* Traverse an object by splitting the path in the argument
* Only returns values that are in nested objects not arrays
*/
function get_property_from_nested_objects(object $object, string $path, $default_fallback = null)
{
if (strpos($path, '->') !== false) {
$path_properties = explode('->', $path);
} else {
return isset($object->$path) ? $object->$path : $default_fallback;
}
$nested_objects = [];
foreach ($path_properties as $nested_obj_index => $object_key) {
if (isset($object->$object_key) && is_object($object->$object_key)) {
$nested_objects[$nested_obj_index] = $object->$object_key;
continue;
} elseif (isset($nested_objects[$nested_obj_index - 1]->$object_key) && is_object($nested_objects[$nested_obj_index - 1]->$object_key)) {
$nested_objects[$nested_obj_index] = $nested_objects[$nested_obj_index - 1]->$object_key;
continue;
} elseif (isset($nested_objects[$nested_obj_index - 1]->$object_key) && !is_object($nested_objects[$nested_obj_index - 1]->$object_key)) {
return $nested_objects[$nested_obj_index - 1]->$object_key;
} else {
return $default_fallback;
}
}
}
echo get_property_from_nested_objects((object)[
'obj1' => (object) [
'prop' => 'works'
]
], 'obj1->prop');
// output: 'works'
精彩评论