PHP: как исправить array_pop и значение 0 - PullRequest
0 голосов
/ 15 декабря 2018

Я пытаюсь по разным путям сгенерировать размерный массив.Для этого я использую найденную здесь функцию .

Мой код

function get_dir_content_to_array( string $dir_path, string $dir_filter = null, string $file_filter = null ) {
    if( is_dir_empty( $dir_path ) )
        return false;
    $output = array();
    $files = get_subdir_filtered( $dir_path, $dir_filter, $file_filter );
    if ( isset( $files ) ) {
        foreach ( $files as $name => $object ) {
            if ( $object->getFilename() !== "." && $object->getFilename() !== ".." ) {
                // Split by the delimiter.
                $delimiter       = "/";
                $name            = str_replace( "\\", $delimiter, $name );
                $relative_path   = str_replace( $dir_path, "", $name );
                $a_relative_path = explode( $delimiter, $relative_path );
                $path = [ array_pop( $a_relative_path ) ];
                foreach ( array_reverse( $a_relative_path ) as $pathPart ) {
                    $path = [ $pathPart => $path ];
                }

                // Add it to a temp list.
                $paths[] = $path;
            }
            $output = call_user_func_array( 'array_merge_recursive', $paths );

        }
    }
    return $output;
}

function get_subdir_filtered( $dir_path, $dir_filter, $file_filter ) {
    $path      = realpath( $dir_path );
    $directory = new \RecursiveDirectoryIterator( $path );
    $files = null;
    if ( ! empty( $dir_filter ) || ! empty( $file_filter ) ) {
        if ( ! empty( $dir_filter ) ) {
            $filter = new DirnameFilter( $directory, $dir_filter );
        }
        if ( ! empty( $file_filter ) ) {
            $filter = new FilenameFilter( $filter, $file_filter );
        }
        $files = new \RecursiveIteratorIterator( $filter );
    } else {
        $files = new \RecursiveIteratorIterator( $directory );
    }
    return $files;
}

class DirnameFilter extends FilesystemRegexFilter {
    // Filter directories against the regex
    public function accept() {
        return ( ! $this->isDir() || preg_match( $this->regex, $this->getFilename() ) );
    }
}

Это работает, за исключением случаев, когда папка называется "0 "

Как я могу это исправить?Почему array_pop пропускает значение «0», даже если это строка?

Ответы [ 2 ]

0 голосов
/ 15 декабря 2018

В моем случае я получил этот путь: update.json and 0/1/0/filename.zip

Как и сказал @Barmar, проблема в том, когда я пытаюсь преобразовать массив в объект json.

В PHP массив на самом деле все время является объектом, поэтому ... $ arr = ["0" => ["1" => ...]] для php равно: $ arr = [0 => [1 => ...]].В PHP 7.2.x каждый раз, когда вы будете объединять объекты, "0" как строковый ключ будет приведен к 0 как int.

Последствия

1.с кодом json

echo json_encode( get_dir_content_to_array(...) );

//result = ["update.json",{"1":[["filename.zip"]]}]

2.с кодом json и JSON_FORCE_OBJECT

echo json_encode( get_dir_content_to_array(...), JSON_FORCE_OBJECT );

//result = {"0":"update.json","1":{"1":{"0":{"0":"filename.zip"}}}}
//I got 1,0,0,filename.zip instead of 0,1,0,filename.zip 

3.Добавить (строка)

 $path = [array_pop( $a_relative_path)];
 foreach ( array_reverse( $a_relative_path ) as $pathPart ) {
    $path = [ (string) $pathPart => $path ];
 }
 //Same result of 2.

Чтобы сохранить правильный порядок для пути, я нашел на данный момент хакерское решение:

Добавьте подчеркивание перед каждым ключом

foreach ( array_reverse(  $a_relative_path ) as $pathPart ) {
    $path = [ "_" .  $a_relative_path => $path ];
}
//result = {"0":"update.json", "_0":{"_1":{"_0":{"0":"filenamezip"}}}} 

//With a new file path, I got this :
// {"0":"update.json","_toto":{"_foo":{"0":"test.txt"}},"_0":{"_1":{"_0":{"0":"filename.zip"}}}}

Это решение взломано, но я могу сделать разницу между ключом, который является путем "_0":{"_1":{"_0", и ключом для индексации файла "0":"filename.zip"

0 голосов
/ 15 декабря 2018

Когда json_encode() кодирует массив, ключи которого являются последовательными целыми числами, начиная с 0, или их строковыми эквивалентами, он создает массив JSON, а не объект.

Вы можете использовать JSON_FORCE_OBJECT flag, но это затем превратит массивы имен файлов в папке в объекты, которые вам не нужны.

Что вы можете сделать, это использовать объект PHP вместо массива для представления папки.json_encode() закодирует это как объект, даже если он имеет числовые свойства.

Я думаю, что это могло бы сделать это:

function get_dir_content_to_array( string $dir_path, string $dir_filter = null, string $file_filter = null ) {
    if( is_dir_empty( $dir_path ) )
        return false;
    $output = array();
    $files = get_subdir_filtered( $dir_path, $dir_filter, $file_filter );
    if ( isset( $files ) ) {
        foreach ( $files as $name => $object ) {
            if ( $object->getFilename() !== "." && $object->getFilename() !== ".." ) {
                // Split by the delimiter.
                $delimiter       = "/";
                $name            = str_replace( "\\", $delimiter, $name );
                $relative_path   = str_replace( $dir_path, "", $name );
                $a_relative_path = explode( $delimiter, $relative_path );
                $path = [ array_pop( $a_relative_path ) ];
                foreach ( array_reverse( $a_relative_path ) as $pathPart ) {
                    $folder = new StdClass;
                    $folder->{$pathPart} = $path;
                    $path = $folder;
                }

                // Add it to a temp list.
                $paths[] = $path;
            }
            $output = call_user_func_array( 'array_merge_recursive', $paths);

        }
    }
    return $output;
}

Я не проверял это, потому что я не проверяюиметь функцию get_subdir_filtered().Возможно, что array_merge_recursive не выполнит правильное слияние.Возможно, вам также понадобится объединить объекты. Этот урок содержит реализацию mergeObjectsRecursively, которая, на мой взгляд, должна быть полезной заменой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...