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
来缓解特定于此功能的问题之一,但是我的问题更感兴趣的是与环境无关的解决方案,如果您愿意,可以包揽一切。
看一下给PHP include()'d文件父变量作用域它有一个相当独特的方法来解决这个问题,可以在这里使用。
等于在include之前取消设置所有已定义的变量,然后在include之后重新设置它们。
我采用了以下解决方案来包含污染:
$value = call_user_func(function(){
return include(func_get_arg(0));
}, $path);
$path
没有在包含中看到,它似乎是最优雅的。当然,从包含的文件调用func_get_arg($i)
将产生传递的值,但是,好吧…