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:
Array as ouput: