使用节点的字符串表示形式访问stdClass对象上的嵌套属性

时间:2019-04-21 19:44:49

标签: php object properties

给出一个包含该字符串的变量:

$property = 'parent->requestdata->inputs->firstname';

还有一个对象:

$obj->parent->requestdata->inputs->firstname = 'Travis';

如何使用字符串访问值“ Travis”?我尝试过:

$obj->{$property}

但它会查找名为“ parent-> requestdata-> inputs-> firstname”的属性,而不是位于$ obj-> parent-> requestdtaa-> inputs-> firstname`的属性

我尝试了各种类型的串联,使用var_export()以及其他方法。我可以将其分解为数组,然后像在this question中那样循环数组。

但是变量'$ property'可以容纳16个深度的值。而且,我正在解析的数据可以具有数百个我需要导入的属性,因此,在每次迭代之前循环遍历并返回值,直到达到16 X 100级为止似乎效率很低。尤其是考虑到我一开始就知道该属性的实际位置。

在给定'Travis'(stdClass)$obj的情况下,如何获得值(string)$property

2 个答案:

答案 0 :(得分:0)

您是正确的,您必须为每个嵌套对象进行循环迭代,但是您不必为每个嵌套对象循环“数百个属性”,您只需访问要查找的对象即可用于:

$obj = new SomeObject;
$property = 'parent->requestdata->inputs->firstname';
$props = explode("->", $property);
while ($props) {
    $prop = array_shift($props);
    $obj = $obj->$prop ?? null;
}

完全未经测试,但似乎应该可以正常运行。就是说,这听起来像是an X-Y problem

答案 1 :(得分:0)

我的最初搜索没有产生很多结果,但是,在考虑了更广泛的搜索词之后,我在SO上发现了其他类似问题的问题。我提出了三种解决方案。所有人都会工作,但并非所有人都能工作。

解决方案1-循环播放

使用与原始问题中引用的问题类似的方法或@ miken32提出的循环将起作用。

解决方案2-匿名功能

该字符串可以分解为数组。然后可以使用array_reduce()解析该数组以产生结果。就我而言,工作代码(检查不正确/不存在的属性名称/拼写)是(PHP 7 +):

//create object - this comes from and external API in my case, but I'll include it here 
//so that others can copy and paste for testing purposes

$obj = (object)[
    'parent' => (object)[
        'requestdata' => (object)[
            'inputs' => (object)[
                'firstname' => 'Travis'
             ]
         ]
    ]
];

//string representing the property we want to get on the object

$property = 'parent->requestdata->inputs->firstname';

$name = array_reduce(explode('->', $property), function ($previous, $current) {
    return is_numeric($current) ? ($previous[$current] ?? null) : ($previous->$current ?? null); }, $obj);

var_dump($name); //outputs Travis

有关潜在的相关信息和我基于其答案的代码,请参见this question

解决方案3-symfony属性访问组件

就我而言,使用作曲家很容易需要此组件。它允许使用简单的字符串访问数组和对象的属性。您可以在symfony网站上read about how to use it。对我来说,与其他选项相比,它的主要好处是错误检查。

我的代码最终看起来像这样:

//create object - this comes from and external API in my case, but I'll include it here 
//so that others can copy and paste for testing purposes
//don't forget to include the component at the top of your class
//'use Symfony\Component\PropertyAccess\PropertyAccess;'

$obj = (object)[
    'parent' => (object)[
        'requestdata' => (object)[
            'inputs' => (object)[
                'firstname' => 'Travis'
             ]
         ]
    ]
];

//string representing the property we want to get on the object
//NOTE: syfony uses dot notation. I could not get standard '->' object notation to work.

$property = 'parent.requestdata.inputs.firstname';

//create symfony property access factory

$propertyAccessor = PropertyAccess::createPropertyAccessor();

//get the desired value

$name = $propertyAccessor->getValue($obj, $property);

var_dump($name); //outputs 'Travis'

所有三个选项都将起作用。选择最适合您的一款。