动态访问嵌套对象

Posted

技术标签:

【中文标题】动态访问嵌套对象【英文标题】:Dynamically access nested object 【发布时间】:2011-10-25 14:52:12 【问题描述】:

我正在构建一个地理编码类,它可以利用多种网络服务进行地理编码(即 Google、Yahoo、Bing 等)。我正在尝试以一种可以轻松配置新 Web 服务的方式来实现它。大多数 Web 服务返回 XML/JSON.. 对于 php,我选择 XML 作为我的主要关注点。所有代码都已经到位,但现在 Google 例如返回以下 XML(转换为 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
                                    )

                            )

                    )

            )
)

我需要的信息在 [location] 标签中,所以我尝试将路径存储在 var 中:

$lat_path = 'result[0]->geometry->location->lat;

然后尝试以这种方式访问​​该值:

(suppose $xml is the object)
$xml->$lat_path;

但这不起作用。有什么方法可以动态或基于变量访问信息。我不想用 Google 特定的代码破坏我的地理编码方法。

谢谢!

【问题讨论】:

使用 SimpleXMLElement::xpath 代替 php 反对表示法。 (如果你能展示一些xml,我会尝试提供一个示例实现) 你可以为此编写方法然后忘记.. 我也尝试过使用 Xpath,但它不起作用:( print_r($xml->Xpath('geometry/location')); 给了我一个空数组。 【参考方案1】:

当你这样做时

$xml->$lat_path;

PHP 将使用$lat_path 中的任何内容作为变量名。它不会进入对象图或完全服从T_OBJECT_OPERATOR。它只会寻找一个属性

 'result[0]->geometry->location->lat;'

$xml。尝试运行此代码作为示例:

$obj = new StdClass;
$obj->'result[0]->geometry->location->lat;' = 1;
print_r($obj);

会输出

stdClass Object
(
    [result[0]->geometry->location->lat;] => 1
)

如您所见,它是一个单一属性,而不是嵌套对象图。

像 cmets 中建议的那样,要么使用 XPath,要么直接转到所需的值:

$xml->result[0]->geometry->location->lat;

【讨论】:

【参考方案2】:

如果您无法使用 xPath 并且需要动态访问对象,您可以使用以下方法:

$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;
    

【讨论】:

【参考方案3】:

我今天遇到了这个问题。这是我的解决方案。

<?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'

【讨论】:

以上是关于动态访问嵌套对象的主要内容,如果未能解决你的问题,请参考以下文章

在 for 循环期间访问嵌套对象 VueJS

在 flash actionscript 2 中动态访问嵌套的影片剪辑

如何动态访问嵌套错误/触及formik字段

使用 Linq.Expression 访问具有动态 lambda 的嵌套属性

访问另一个 NSMutableArray 中的对象的 NSMutableArray(即嵌套对象访问)

如何解析具有动态键名的嵌套 json