php realpath 无效,每日一博 | PHP7 realpath 函数一个长期存在的 bug

实在是忍不住要吐槽一下,从7.0.0到7.0.4的时候,我一直在看这个bug,而且也发去php issues了,已经说修复了,但是显然并没有修复。后来忙,就没管这个问题了,可是到今天,都7.0.14了,7.1.0都发布了,还是没修复啊!

phar包

假定我有一个phar包,包内结构如下:

bdabe262e28b557e1b33b067a49d9ab1.png $paths = [

'phar://phar_test.phar/hello',

'phar://phar_test.phar/hello/a.php',

];

上述的这个路径,是存在的。

第一次测试

执行测试: foreach ($paths as $path) {

var_dump(file_exists($path)); // return true

var_dump(realpath($path)); // return false

}

输出结果如下:

4b6151f080f2cdb9296ddf5dbd2ed152.png

如果用file_exists检查,那么他是返回true的,文件是存在的。

用realpath检查,他返回了false,就是返回真实路径的时候,他无法返回相对应的真实路径。

所以,一般到这里,会让我们得出一个 想当然的结论:realpath显然不支持phar包。

第二次测试

问题并没有结束,显然realpath是支持phar的,这次我们加一个函数: function let_it_work(string $path)

{

$realPath = realpath($path);

if ($realPath !== false) {

$path = $realPath;

}

return $path;

}

这个函数其实没啥特别,但是他却能让我们得到想要的结果。

执行下列测试程序: foreach ($paths as $path) {

var_dump(file_exists($path)); // return true

var_dump(realpath($path)); // return false

var_dump(let_it_work($path)); // 输出 "phar://phar_test.phar/hello" 和 "phar://phar_test.phar/hello/a.php"

}

我们会得到如下的结果:

0299b51a693491cb21f9cae43f47548f.png

显然realpath函数还是生效了。不然是不会得到真实路径的。

第三次测试

那么是不是给realpath包一层函数,就能得到我们想要的结果呢?那我再加一个函数: function realpath2(string $path)

{

return realpath($path);

}

执行以下测试: foreach ($paths as $path) {

var_dump(file_exists($path)); // return true

var_dump(realpath($path)); // return false

var_dump(let_it_work($path)); // 输出 "phar://phar_test.phar/hello" 和 "phar://phar_test.phar/hello/a.php"

var_dump(realpath2($path)); // 和realpath返回结果一样

}

得到如下的结果:

be0361fd36b1694a20afb2775aa76985.png

显然包一层函数是不能解决问题的。

第四次测试

这个问题,并不止于realpath函数,所有获取realpath的函数,都存在这个问题。比如目录迭代器 DirectoryIterator,我们再写一个函数: function entry(DirectoryIterator $dir)

{

foreach ($dir as $item) {

$path = $item->getPathname();

var_dump(file_exists($path)); // true

var_dump($item->getRealPath()); // false

var_dump(let_it_work($path)); // 这里返回的结果,是正确的

}

}

entry(new DirectoryIterator('phar://phar_test.phar'));

这个测试很简单,就是传入一个目录迭代器,然后遍历目录下的内容,然后调用 getRealPath 方法以进行测试。

执行结果如下:

04d63d8ce69957b770db6b2784a35987.png

不出所料,getRealPath返回还是返回无效的结果。

结论

其实这个问题看上去,并不是一个很严重的问题,而且也有解决方案了,所以也没什么可抱怨的。

但是冷静分析一下let_it_work的函数,问题的关键在于: if ($realPath !== false) {

$path = $realPath;

}

$path变量是函数的参数传入的,但是到这里,我把他和false做了一次比较,然后又把他写入了另一个变量的结果,这样就改变了结果。这里其实是一个很严重的问题,就是变量的内存地址问题。也就是说,通过一些操作,就让一个变量的内存地址发生了变化,取回了正确的值。怎么想都觉得非常诡异,莫名其妙。

这个问题从7.0.0发布的时候我就发现了,因为这个问题,这一年来我一直在认真考虑转Java还是C#的问题。

当然,也许我可以通过一些内存跟踪的手段去明确这个问题的根本,但我实在懒得折腾了。

其实PHP7还有一些让我不太满意的问题,比如ArrayObject的问题,比如:ArrayObject->item += 1,是无法触发offsetSet和offsetGet接口的。这个可能不算bug,也许到php7,关闭了这个特性。

无论如何,我对PHP的态度是,我只是这个语言的使用者,如果你让我折腾C,我不如去写Go、Java、C#等等,多了去的选择。所以如果这个语言本身不可靠,那我真的应该考虑换一个语言了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值