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 при таких обстоятельствах.
- Я просто хочу пойти на запись здесь; Я знаю, что мог бы использовать, например,
elseif
, чтобы решить одну из проблем, характерных для этой функции, однако мой вопрос больше интересует решения, не зависящие от обстоятельств, и универсальный подход, если хотите.