我有以下代码,它将一些php代码保存到文件中,然后加载它,再次运行,有时require方法返回int,为什么会发生这种情况?
<?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)) {
// Sometime the following line returns int,why?
$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
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号
如果脚本始终只有一个执行者,则此问题无法重现。
如果您正在谈论并行运行此脚本,那么问题在于以独占模式写入文件并不能保护您稍后在写入过程中读取文件。
进程可能正在写入文件(并拥有锁),但
require不遵守该锁(文件系统锁是建议性的,而不是强制执行的)。所以正确的解决方案是:
<?php $f = function() use($a){ $cachePath = '/tmp/t.php'; /* Open the file for writing only. If the file does not exist, it is created. If it exists, it is neither truncated (as opposed to 'w'), nor the call to this function fails (as is the case with 'x'). The file pointer is positioned on the beginning of the file. This may be useful if it's desired to get an advisory lock (see flock()) before attempting to modify the file, as using 'w' could truncate the file before the lock was obtained (if truncation is desired, ftruncate() can be used after the lock is requested). */ $fp = fopen($cachePath, "c"); $code = '<?php'; $code .= "\n\n"; $code .= 'return ' . var_export([], true) . ';'; // acquire exclusive lock, waits until lock is acquired flock($fp, LOCK_EX); // clear the file ftruncate($fp, 0); // write the contents fwrite($fp, $code); //wrong (see my answer as to why) //file_put_contents($cachePath, $code, LOCK_EX); //not needed //if (file_exists($cachePath)) { // Lock is held during require $result = require($cachePath); if (!is_array($result)) { var_dump($result, $cachePath, file_get_contents($cachePath)); exit("ok"); } var_dump($result); //} // closing the file implicitly releases the lock fclose($fp); }; for($i=0;$i<1000000;$i++) { $f(); }请注意,写入后不会释放并重新获取锁,因为另一个进程可能正在等待覆盖该文件。
不发布它是为了确保编写的同一段代码也是
required。然而,这整件事从一开始就值得怀疑。
为什么需要写入一个文件以便稍后
require将其返回?