递归函数中的意外行为

时间:2019-01-20 01:35:15

标签: php arrays recursion

任务是递归地删除具有错误=> 4(即具有该值的键)及其键的数组,然后将剩余的数组变成对象。 传入数组的结构可能有所不同。这是两个例子:

// Example input #1
$ex_input_1 = array(
    'files' => array(
        0 => array(
            'name' => 'file.jpg',
            'size' => '244235',
            'tmp_name' => '/usr/tmp/24ffds.tmp',
            'error' => 0
        ),

        1 => array(
            'name' => '',
            'size' => '',
            'tmp_name' => '',
            'error' => 4
        )
    ),

    'cover' => array(
        'name' => '',
        'size' => '',
        'tmp_name' => '',
        'error' => 4
    ),

    'document' => array(
        'name' => 'file.doc',
        'size' => '244235',
        'tmp_name' => '/usr/tmp/24ffds.tmp',
        'error' => 0
    )
);

// Example input #2
$ex_input_2 = array(
    0 => array(
        'name' => 'file.jpg',
        'size' => '244235',
        'tmp_name' => '/usr/tmp/24ffds.tmp',
        'error' => 0
    ),

    1 => array(
        'name' => '',
        'size' => '',
        'tmp_name' => '',
        'error' => 4
    )
);

即具有name, size, tmp_name, error键的数组可能处于任意级别。

我尝试过的事情:

试图用两种方法编写一个简单的处理程序,其中第一种是递归处理程序,第二种是水合器方法。相关部分如下:

<?php

class FileInputParser
{
    /**
     * Recursively hydrate array entires skipping empty files
     * 
     * @param array $files
     * @return array
     */
    public function hydrateAll(array $files)
    {
        foreach ($files as $name => $file) {
            if (!is_array($file)) {
                continue;
            }

            foreach ($file as $key => $value) {
                if (is_array($value)) {
                    // Recursise call
                    $files[$name] = $this->hydrateAll($files[$name]);
                } else {
                    $target = $this->hydrateSingle($file);

                    // Here I'm EXPLICTLY asking not to push an array, which has error = 4
                    // But it pushes anyway!!
                    if ($target !== false) {
                        unset($files[$name]);
                    }
                }
            }
        }

        return $files;
    }

    /**
     * Hydrates a single file item
     * 
     * @param array $file
     * @return mixed
     */
    private function hydrateSingle(array $file)
    {
        $entity = new stdclass;
        $entity->name = $file['name'];
        $entity->tmp_name = $file['tmp_name'];
        $entity->error = $file['error'];
        $entity->size = $file['size'];

        if ($entity->error != 4) {
            return $entity;
        } else {
            // Returning false to indicate, that this one should not be pushed in output
            return false;
        }
    }
}

问题

乍一看它是有效的,但问题是,当我明确要求不要添加要输出的错误= 4的数组时,它会继续添加!

您可以使用输入示例运行上述代码:

<?php

$parser = new FileInputParser();
$output = $parser->hydrateAll($ex_input_1);

echo '<pre>', print_r($output, true);

看到它还会返回不需要的数组(即错误= 4的数组)。

问题

为什么继续向输出添加错误= 4的数组? 如果您有更好的处理方法,我很想听听。

1 个答案:

答案 0 :(得分:1)

这是一个递归函数,它将执行您想要的过滤。当到达树的底部时,它将检查array_filter,如果是,则返回一个空数组,否则返回当前数组。在下一级,function array_filter_recursive($array) { if (isset($array['error'])) { // bottom of tree return $array['error'] == 4 ? array() : $array; } foreach ($array as $key => $value) { $array[$key] = array_filter_recursive($value); } // remove any empty values return array_filter($array); } 会删除所有返回的空值:

Array ( 
    [files] => Array (
        [0] => Array ( 
            [name] => file.jpg
            [size] => 244235
            [tmp_name] => /usr/tmp/24ffds.tmp
            [error] => 0
        )
    )
    [document] => Array (
         [name] => file.doc
         [size] => 244235
         [tmp_name] => /usr/tmp/24ffds.tmp
         [error] => 0
    ) 
)

Array ( 
    [0] => Array (
        [name] => file.jpg
        [size] => 244235
        [tmp_name] => /usr/tmp/24ffds.tmp
        [error] => 0
    )
)

过滤两个输入数组的输出:

li

Demo on 3v4l.org