PHP的require()函数是否在PHP 5.6中缓存其结果?

时间:2018-02-19 00:42:30

标签: php linux filesystems require

在一个旨在处理通用共享LAMP托管的PHP脚本中,我使用require()作为函数从文件中读取数据。数据文件如下所示:

<?php
# storage.php

return [
    // Rotating secrets
    'last_rand' => '532e89355b78aafdb85f5f01f0eed20440d6bd9e0a2d6ae1bd17be4e1d7d21c7bb7a822a2077e3f4',
];

我这样读了:

$data = require($root . '/storage.php');
$lastRand = $data['last_rand'];

在我的脚本中,我将使用此方法从配置文件中读取信息。在某些情况下,操作将重新编写新的配置文件(使用file_put_contents()),然后再次使用require()重新读取它。

到目前为止,这已经在各种LAMP主机上运行良好,但今天我发现了一个网络主机require()似乎没有注意到文件中的变化。这个主机使用PHP 5.6,而我测试的所有其他主机都使用7 +。

奇怪的是require()获取文件的旧内容,即使file_get_contents()可以看到新版本,就像require()正在进行自己的内部缓存一样。

修复尝试失败

我甚至试图等待require()赶上,以防某些底层缓存需要时间到期:

$ok = true;
$t = microtime(true);
while ($oldRandom != $this->getFileService()->requirePhp($this->getStoragePath())['last_rand'])
{
    $elapsedTime = microtime(true) - $t;
    if ($elapsedTime > 4) // Wait 4 seconds
    {
        $ok = false;
        break;
    }
    usleep(1000);
}

这也不起作用(超时刚过期而require()带来的结果没有变化)。

但是,在下一次运行PHP脚本时,require()会突然看到新文件内容。

我还尝试在重新阅读之前删除storage.php文件,这也没有效果!我真的希望能帮到你。

未来行动

所以,我根本不明白这种行为。为了解决这个问题,我可以:

  • 而不是修改新配置,将其保存到文件然后从文件重新加载,我可以重构我的代码,以便将新配置保存到内存中,从而避免重新加载它
  • 重构,以便我使用file_get_contents()而不是require()(因为相当沉闷的原因,它不那么方便,但我会更喜欢可靠的工作)。

然而,这些都觉得我忽略了一个错误,我应该调查原因。我碰巧也知道这个主机(一个免费的)几乎总是在CPU负载很重的情况下。它是一个64位服务器,在相当旧的2.6内核上运行Linux,而phpinfo()表示CGI / FastCGI服务器API已生效。

以前有没有人遇到过这个问题,可以做些什么来缓解它?

更多尝试

一些有用的评论者认为这个问题可能与opcaching有关,这似乎符合require()的一般目的。我在重写配置的file_put_contents()之后添加了这段代码:

    $reset = opcache_reset(); // Returns true
    $invalid = opcache_invalidate($this->getStoragePath()); // Returns false

然而,它没有任何区别 - require()顽固地读取相同的值。我通过在文件写入之前和之后执行require()以及file_get_contents()来确认这一点,以获取真实内容。

1 个答案:

答案 0 :(得分:1)

当我最初遇到这个错误时,我对于解决这个问题犹豫不决,因为它感觉就像一个不容忽视的关键错误。但是,现在罪魁祸首很可能是opcaching(因此与require()具体相关),我认为通过将值保存在内存中来解决它并不是一个糟糕的解决方案。我必须记住,require()仅适用于每个HTTP请求的一次调用,即使对于所有PHP安装都不适用。

我也意识到,如果我确实试图解决这个问题,我将不得不面对一些opcache失效机制,这比我所熟悉的更复杂。