Php vfsstream路径和realpath

Php vfsstream路径和realpath,php,mocking,phpunit,vfs-stream,Php,Mocking,Phpunit,Vfs Stream,我正在使用vfstream进行文件系统交互的单元测试,很快就遇到了一个重大障碍。测试代码所做的验证检查之一是在提供的输入路径上执行realpath(),以测试它是否为实际路径,而不是胡说八道。但是,realpath在vfstream路径上总是失败 下面的代码演示了任何特定类之外的问题 $content = "It rubs the lotion on its skin or else it gets the hose again"; $url = vfsStream::url

我正在使用vfstream进行文件系统交互的单元测试,很快就遇到了一个重大障碍。测试代码所做的验证检查之一是在提供的输入路径上执行realpath(),以测试它是否为实际路径,而不是胡说八道。但是,realpath在vfstream路径上总是失败

下面的代码演示了任何特定类之外的问题

$content    = "It rubs the lotion on its skin or else it gets the hose again";
$url        = vfsStream::url ('test/text.txt');
file_put_contents ($url, $content);
var_dump ($url);
var_dump (realpath ($url));
var_dump (file_get_contents ($url));
结果如下:

string(27) "vfs://FileClassMap/text.txt"
bool(false)
string(61) "It rubs the lotion on its skin or else it gets the hose again"
显然,vfsStream创建了该文件并将给定的内容写入其中,但我无法用realpath验证它的路径是否正确。由于realpath正在实际代码中使用,我需要一种方法来解决这个问题

我真的不认为删除realpath是一种明智的方法,因为它在代码中执行一个重要的功能,而取消一个重要的检查只是为了使代码可测试似乎是一个相当糟糕的解决方案。我还可以在测试中加入一个if,使其能够出于测试目的禁用它,但我也不认为这是一个好主意。另外,我不想在代码中调用realpath()的每一点都这样做。第三种选择是为文件系统单元测试设置一个RAM磁盘,但这也不理想。您必须自己清理(这是vfstream应该帮助您避免需要的),并且如何实际进行清理将因操作系统而异,因此单元测试将不再是操作系统不可知的

那么,有没有一种方法可以获得一个真正适用于realpath的格式的vfstream路径呢

为了完整性,下面是我试图实际测试的类的代码片段

if (($fullPath = realpath ($unvalidatedPath))
&& (is_file ($fullPath))
&& (is_writable ($fullPath))) {
对以下内容的重构(根据可能的解决方案2)允许我使用vfstream进行测试,但我认为在生产中可能会出现问题:

// If we can get a canonical path then do so (realpath can fail on URLs, stream wrappers, etc)
$fullPath   = realpath ($unvalidatedPath);
if (false === $fullPath) {
    $fullPath   = $unvalidatedPath;
}

if ((is_file ($fullPath))
&& (is_writable ($fullPath))) {

如果使用名称空间,则只能在测试类中重写realpath函数。我总是在vfstream测试用例中使用规范路径,因为我不想测试realpath()函数本身

namespace my\namespace;

/**
 * Override realpath() in current namespace for testing
 *
 * @param string $path     the file path
 *
 * @return string
 */
function realpath($path)
{
    return $path;
}

这里描述得很好:

我在vfstream上实现了Sebkrueger的方法,打开了一个bug:

等待他们的反馈,这是我的工作realpath():

/**
*此函数重写本机realpath($url)函数,删除
*url的所有“..”、“///”。与本地的相反,
* 
*@param string$url
*@param string | bool清除的url,如果不存在则为false
*/
函数realpath(字符串$url)
{
preg|u match(“|^(\w+:/)?(/)?(*)$|”,$url,$matches);
$protocol=$matches[1];
$root=$matches[2];
$rest=$matches[3];
$split=preg|u split(“|/|”,$rest);
美元=[];
foreach($拆分为$项目){
如果($item==”。| |$item==”){
//如果是a/,那么它什么都不是(只是那个dir),所以不要添加/删除任何内容
}elseif($item==='..'){
//删除自..以来添加的最后一项。将其否定。
$removed=array_pop($cleaned);
}否则{
$cleaned[]=$item;
}
}
$cleaned=$protocol.$root.intlode(“/”,$cleaned);
返回文件_存在($cleaned)?$cleaned:false;
}