php从字段名称数组中获取对象数据

I have a result set from a query that gives me an object that has dozens of fields, the below example is a subset:

[79] => stdClass Object
    (
        [name] => John Doe
        [email] => john@doe.com
        [ext] => 4004
        [options] => stdClass Object
            (
                [type] => friend
                [rating] => Excellent
                [context] => default
            )
        [address] => 123 Anywhere St
    )

Instead of plowing through each field, because I only want a handful of them, I am trying to use an array to get what i want:

$fields = array('name','email','options->type','options->rating','address');

so then i do:

foreach ($result as $k => $v){
    foreach ($fields as $kk => $vv){
        echo $kk. " - " . $v->$kk."<br>";
    }
}

Which gives me field name and its value.

name - John Doe
email - john@doe.com
address - 123 Anywhere St.

However, anything in that sub object(options) is giving me a blank result.

You can use a recursive function providing that you don't mind changing the format of your $fields var to include arrays. In my opinion this makes it easier to read anyway, and easier to handle in code.

The benefit of using a recursive function is that it will handle any depth.

$o = (object) [
    'name' => 'John Doe',
    'email' => 'john@doe.com',
    'ext' => 4004,
    'options' => (object) [
        'type' => 'friend',
        'rating' => 'Excellent',
        'context' => 'default',
        'any' => (object) [
            'depth' => (object) [
                'will' => 'work'
            ]
        ]
    ],
    'address' => '123 Anywhere St'
];
$fields = [
    'name',
    'email',
    'options' => [
        'type',
        'rating',
        'any' => [
            'depth' => [
                'will'
            ]
        ]
    ],
    'address'
];

function getObjectProps($o, $fields, $parent = '') {
    if (strlen($parent)) {
        $parent .= '->';
    }
    foreach ($fields as $k => $v) {
        if (is_array($v)) {
            getObjectProps($o->{$k}, $v, $parent . $k);
        } else {
            echo $parent . $v . ' - ' . $o->{$v} . '<br/>';
        }
    }
}
getObjectProps($o, $fields);

Output:

name - John Doe
email - john@doe.com
options->type - friend
options->rating - Excellent
options->any->depth->will - work
address - 123 Anywhere St

Use a multidimensionnal array for $fields and change your foreach loop a little bit:

$fields = [
    'name',
    'email',
    'options' => [
        'type',
        'rating'
    ],
    'address'
];

foreach ($result as $obj) {
    foreach ($fields as $k => $v) {
        if (is_array($v)) {
            foreach ($v as $vv) {
                echo $vv . ' - ' . $obj->$k->$vv . '<br>';
            }
        } else {
            echo $v . ' - ' . $obj->$v . '<br>';
        }
    }
}

Here's what I came up with in the meantime

$someObject = new stdClass();
$someObject->name = 'Dale';
$someObject->options = new stdClass();
$someObject->options->address = 'The Address';

$fields = ['name', 'options' => ['address']];

function toArray($object, $fields) {

    $return = [];

    foreach($fields as $fieldKey => $fieldValue) {

        if(!is_array($fieldValue)) {
            $return [] = $object->$fieldValue;
        }
        else
        {
            $return = array_merge($return, toArray($object->$fieldKey, $fieldValue));
        }

    }

    return $return;
}

print_r(toArray($someObject, $fields));

Try this code:

$newResult = array_intersect_key((array)$result, array_flip($fields));

There is no easy way to access property like the way you are trying. But there's a symfony's property access component which you can use. But if you are focusing to use your own method then you might love the following code. I ran this code in PHP 7.2

$data = (object) [
    'name' => 'John Doe',
    'email' => 'john@doe.com',
    'ext' => 4004,
    'options' => (object) [
        'type' => "friend",
        'rating' => 'Excellent',
        'context' => 'default'
    ],
    'address' => '123 Anywhere St'
];

$fields = array('name','email','options->type','options->rating','address');

/*** way of initializing
$response = []; // get array value here
$response = ""; // get string value here
***/

$response = ""; //string value here... as output

/*** Don't you think that the below code now is clean and reusable? ***/

array_map(function($key) use($data, &$response) {
    $value = array_reduce(explode('->', $key), function ($o, $p) {
        return $o->$p;
    }, $data);
    is_array($response) ? ($response[$key] = $value) : ($response .= $key . ' - ' . $value . '<br>');
}, $fields);

echo $response;

In the above code if you initialize $response as an empty array then you'll get array as output. And if you initialize that as an empty string then you'll get string output. And I think instead of using for loop, use array_map and array_reduce, they work like magic and reduce your code too.

String as output:

String as output

Array as ouput:

Array as output