很简单的问题,但我实际上无法确定。PHP 如何处理已经被 APC 缓存的文件的 requires/includes 行为?我的理解是,这个缓存主要保存 PHP 编译已经缓存的文件,但我不清楚它是否也保存了查找/获取文件所需的磁盘命中;所以,是吗?或者 PHP 是否会命中磁盘,即使操作码已经被缓存,唯一的区别是它不会再次执行编译过程?
我想认为 requires/includes 神奇地知道文件已缓存,因此由于 APC 直接从内存中获取它,但我刚刚意识到我没有理由假设这是这种情况,因此我问。
我认为你关于这个主题的问题在 APC 手册中有解释,但它有点隐藏。您必须阅读配置部分才能找到它。尤其是查看apc.stat配置选项,它说明了这一点:
...这默认为打开,强制 APC 统计(检查)每个请求的脚本以确定它是否已被修改。如果它已被修改,它将重新编译并缓存新版本。如果此设置关闭,APC 将不会检查
...
对于包含/必需的文件,此选项也适用,但请注意,对于相对路径包含(在 Unix 上任何不以 / 开头的路径)APC 必须按顺序检查唯一标识文件。如果您使用绝对路径包括 APC 可以跳过统计信息并使用该绝对路径作为文件的唯一标识符。
因此,如果您通过文件的绝对路径包含/要求,那么看起来 APC 正在以与原始脚本大致相同的方式缓存所需/包含的文件。如果您使用的是相对路径(很多人都这样做),则需要磁盘命中才能找到完整的文件名。
实际上,APC为 *once 变体(include_once、require_once)执行 OPEN 系统调用。您可以使用 strace 轻松检查这一点。
这是因为 *once 的代码略有不同,在调用 compile_filename 之前调用 zend_stream_open (被 apc 覆盖):
https://github.com/php/php-src/blob/master/Zend/zend_execute.h
错误跟踪器中也有一个未解决的问题: https ://bugs.php.net/bug.php?id=59372
APC 覆盖 Zend 引擎中的 zend_compile_file 函数,它负责定位和打开实际文件;多亏了这一点,如果文件已经被缓存,它能够在磁盘命中发生之前“劫持”它们。
因此,是的,如果缓存了文件,则从内存中提供文件。
来源:APC Technotes和 Zend Engine 源代码,特别是zend_language_scanner.c