当 PHP 中不可能时 require 方法返回 int
P粉883223328
P粉883223328 2023-09-02 09:55:14
[PHP讨论组]

我有以下代码,它将一些php代码保存到文件中,然后加载它,再次运行,有时require方法返回int,为什么会发生这种情况?

演示.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)) {
        // 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

P粉883223328
P粉883223328

全部回复(1)
P粉550323338

如果脚本始终只有一个执行者,则此问题无法重现。

如果您正在谈论并行运行此脚本,那么问题在于以独占模式写入文件并不能保护您稍后在写入过程中读取文件。

进程可能正在写入文件(并拥有锁),但 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将其返回?

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号