PHP中require方法为何有时返回整数?附复现步骤
问题
我编写了如下PHP代码:将一段返回空数组的PHP代码写入/tmp/t.php文件,随后通过require加载该文件。当同时启动两个PHP进程运行这段代码时,有时require方法会返回整数,而非预期的数组,请问这是什么原因?
demo.php
<?php $f = function() use($a){ $cachePath = '/tmp/t.php'; $code = '<?php'; $code .= "\n\n"; $code .= 'return ' . var_export([], true) . ';'; file_put_contents($cachePath, $code, LOCK_EX); if (file_exists($cachePath)) { // 有时下面这行会返回整数,为什么? $result = require($cachePath); if (!is_array($result)) { var_dump($result, $cachePath, file_get_contents($cachePath)); exit("ok"); } var_dump($result); } }; for($i=0;$i<1000000;$i++) { $f(); }
复现方式
通过以下命令同时启动两个PHP进程运行上述代码:
php demo.php
原因分析
问题出在文件写入的原子性和require的执行时机上:
- 虽然
file_put_contents用了LOCK_EX独占锁,但这个锁仅阻止其他进程写入文件,无法阻止进程读取文件。 - 当进程A执行
file_put_contents时,会先打开文件(默认模式下会直接截断原有内容),再逐步写入代码。如果进程A还没写完所有内容,进程B就执行到file_exists($cachePath),会判定文件存在,随即调用require加载这个内容不完整的文件。 - 不完整的文件可能只有
<?php开头,还没写入return [];语句。此时PHP解析文件时,因为没有语法错误但也没有return语句,require会返回true——在PHP中true会被当作整数1,这就是你看到的非预期整数返回值。
另外,file_exists判断和require执行之间存在竞态条件:文件存在不代表内容已经完全写入,这也是触发问题的核心因素。
内容的提问来源于stack exchange,提问作者user3982143
相关产品推荐
相关产品推荐

