Защита переменных от «включенного загрязнения» в PHP - PullRequest
4 голосов
/ 05 ноября 2011

tl; dr: Есть ли способ предотвратить изменение ( по существу блокировки ) переменных, объявленных / определенных до вызова include(), включаемым файлом? Также несколько связан вопрос .


Мне интересно, какие меры можно предпринять, чтобы избежать переменного загрязнения от включенных файлов. Например, учитывая эту необычную маленькую функцию:

/**
 * Recursively loads values by include returns into
 * arguments of a callback
 * 
 * If $path is a file, only that file will be included.
 * If $path is a directory, all files in that directory
 * and all sub-directories will be included.
 * 
 * When a file is included, $callback is invoked passing
 * the returned value as an argument.
 *
 * @param string $path
 * @param callable $callback
 */
function load_values_recursive($path, $callback){
    $paths[] = path($path);
    while(!empty($paths)){
        $path = array_pop($paths);
        if(is_file($path)){
            if(true === $callback(include($path))){
                break;
            }
        }
        if(is_dir($path)){
            foreach(glob($path . '*') as $path){
                $paths[] = path($path);
            }
        }
    }
}

Я знаю, что в нем отсутствуют некоторые проверки типов и другие объяснения, давайте проигнорируем их.

В любом случае, эта функция в основном просеивает кучу файлов «данных», которые просто возвращают значения (, как правило, массивы конфигурации или таблицы маршрутизации, но независимо от ), а затем вызывают переданный обратный вызов, чтобы значение могло быть отфильтрованы или отсортированы или использованы как-то. Например:

$values = array();
load_values_recursive('path/to/dir/', function($value) use(&$values){
    $values[] = $value;
});

И path/to/dir/ может иметь несколько файлов, которые следуют этому шаблону:

return array(
    // yay, data!
);

Моя проблема возникает, когда эти файлы "конфигурации" ( или что-то еще, пытаясь сохранить этот портативный и кросс-функциональный ) начинают содержать даже элементарную логику. Всегда есть возможность загрязнения локальных для функции переменных. Например, файл конфигурации, который ради хитрости делает:

return array(
    'path_1' => $path = 'some/long/complicated/path/',
    'path_2' => $path . 'foo/',
    'path_3' => $path . 'bar/',
);

Теперь, учитывая, что $path является видимым каталогом относительно текущего, функция заработает:

// ...
if(is_file($path)){
    if(true === $callback(include($path))){ // path gets reset to 
        break;                              // some/long/complicated/path/
    }
}
if(is_dir($path)){                          // and gets added into the
    foreach(glob($path . '*') as $path){    // search tree
        $paths[] = path($path);
    }
}
// ...

Скорее всего, это дало бы плохие результаты. Единственное решение 1 , о котором я могу подумать, - это обернуть вызов include() еще одной анонимной функцией для изменения области действия:

// ...
if(true === call_user_func(function() use($callback, $path){
    return $callback($path);
})){
    break;
}
// ...

Таким образом, защищая $path ( и, что более важно, $callback) от побочных эффектов при каждой итерации.

Мне интересно, существует ли более простой способ "блокировать" переменные в PHP при таких обстоятельствах.

  1. Я просто хочу пойти на запись здесь; Я знаю, что мог бы использовать, например, elseif, чтобы решить одну из проблем, характерных для этой функции, однако мой вопрос больше интересует решения, не зависящие от обстоятельств, и универсальный подход, если хотите.

Ответы [ 2 ]

1 голос
/ 04 декабря 2011

Я включил следующее решение, чтобы включить загрязнение:

$value = call_user_func(function(){
    return include(func_get_arg(0));
}, $path);

$path нигде не видно при включении, и оно кажется самым элегантным.Конечно, вызов func_get_arg($i) из включенного файла даст пропущенные значения, но, хорошо ...

1 голос
/ 05 ноября 2011

взгляните на Давая PHP include () 'd файлы родительская переменная scope имеет довольно уникальный подход к проблеме, которую можно использовать здесь.

это равносильно отмене всехопределенные переменные перед включением, а затем их сброс после.

это конечно не элегантно, но это будет работать.

...