duan19913
duan19913
2018-07-17 10:30
浏览 149
已采纳

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.

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

5条回答 默认 最新

  • duangutian1426
    duangutian1426 2018-07-17 10:49
    已采纳

    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
    
    点赞 评论
  • duanji5116
    duanji5116 2018-07-17 10:52

    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>';
            }
        }
    }
    
    点赞 评论
  • dongzhuo3059
    dongzhuo3059 2018-07-17 10:52

    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));
    
    点赞 评论
  • doubai9014
    doubai9014 2018-07-17 11:00

    Try this code:

    $newResult = array_intersect_key((array)$result, array_flip($fields));
    
    点赞 评论
  • doudu9148
    doudu9148 2018-07-17 12:02

    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

    点赞 评论

相关推荐