1

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] => [email protected]
        [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 - [email protected]
address - 123 Anywhere St.

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

3
  • What? Just use object notation or change your db query to only pull out the info you need Commented Jul 17, 2018 at 10:33
  • Its an API call to a system and the result set is 60 or so fields. i only care about 10-12 of the fields. Commented Jul 17, 2018 at 10:35
  • You would need to loop through all values within the options subarray in order to read their contents. Commented Jul 17, 2018 at 10:43

5 Answers 5

2

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' => '[email protected]',
    '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 - [email protected]
options->type - friend
options->rating - Excellent
options->any->depth->will - work
address - 123 Anywhere St
Sign up to request clarification or add additional context in comments.

Comments

0

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>';
        }
    }
}

Comments

0

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

Comments

0

Try this code:

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

Comments

0

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' => '[email protected]',
    '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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.