预加载 PHP 脚本时“未知类型依赖项”是啥意思?
Posted
技术标签:
【中文标题】预加载 PHP 脚本时“未知类型依赖项”是啥意思?【英文标题】:What does "Unknown type dependencies" mean when preloading PHP scripts?预加载 PHP 脚本时“未知类型依赖项”是什么意思? 【发布时间】:2020-04-18 14:11:46 【问题描述】:我正在尝试使用自 php 7.4 起可用的新 preloading feature。
我运行composer install --no-dev --optimize-autoloader
来生成项目中所有可用类的列表,并使用以下preload.php
脚本预加载它们:
$files = require 'vendor/composer/autoload_classmap.php';
foreach (array_unique($files) as $file)
opcache_compile_file($file);
并在我的opcache.ini
文件中配置了这个预加载脚本:
opcache.preload=/path/to/preload.php
然后重新启动php-fpm
。现在systemctl status php-fpm.service
报告以下警告:
PHP 警告:无法预加载未链接的类 Brick\Money\Context\CashContext:第 16 行...中的未知类型依赖关系 PHP 警告:无法预加载未链接的类 Brick\Money\Context\AutoContext:第 17 行中的未知类型依赖项 PHP 警告:无法预加载未链接的类 Brick\Math\BigRational:第 17 行中的未知类型依赖项 PHP 警告:无法预加载未链接的类 Brick\Math\BigInteger:第 20 行...中的未知类型依赖关系 PHP 警告:无法预加载未链接的类 Brick\Math\BigDecimal:第 15 行中的未知类型依赖项
“未知类型依赖”是什么意思?如何预加载这些类?
注意:我是有问题的库 Brick\Math 和 Brick\Money 的维护者,所以如果这些库需要修改以使其可预加载,我会全力以赴! p>
【问题讨论】:
RFC 提到这一点:只有没有未解析父级、接口、特征和常量值的类才能被预加载。 这意味着存在包含类型(类、接口、特征)的文件您必须在错误消息中提到的之前预加载。 它是什么操作系统? . @Kubo2 我不确定它们是否必须在 before 之前预加载:循环依赖呢?我希望他们以任何顺序工作,但我可能错了。无论如何,我还有其他与预加载脚本中未包含的类相关的警告,但这些警告不同,当类尝试扩展非预加载类时,它们会说“未知父级”。这个说“未知类型依赖”,我试图找出这意味着什么。 @revo 这是 CentOS 7.7,有什么不同吗? @NikiC 我以某种方式期望 PHP 文件在执行预加载脚本期间编译为操作码,并且链接要在之后完成 脚本已结束,所有必要的类都已预加载;这将防止任何依赖问题。不是这样吗?顺序重要吗? 【参考方案1】:这意味着 PHP 在运行时无法在预加载的文件中找到类。 This only happens when there might be methods that are incompatible:
预加载:放宽已知类型限制 检查是否存在同名的父/接口/特征方法,然后才需要知道类型。这大大减少了这种情况在实践中触发的情况。
预加载的文件不使用 Composer 自动加载器,因此未预加载的类将不存在。
Symfony 由 creating a Preloader
class 修复了这个问题,它可以加载它的依赖项。这是how to use it 预加载LoaderInterface
和AnnotationClassLoder
:
<?php
// preload.php
$classes[] = 'Symfony\Component\Config\Loader\LoaderInterface';
$classes[] = 'Symfony\Component\Routing\Loader\AnnotationClassLoader';
Preloader::preload($classes);
在有更好的方法之前,您可以复制该类或预加载库所依赖的所有类。
如果您可以让预加载失败成为硬错误,请使用answer from NikiC:
为避免依赖性问题,您可以使用
require
代替opcache_compile_file()
进行预加载。这将很好地处理循环依赖关系,但如果预加载失败(而不仅仅是警告)则会出现硬错误。
【讨论】:
感谢您的回答。不过,我仍然无法弄清楚这些违规课程出了什么问题。以CashContext.php on line 16 为例,它只是一个实现接口的类在同一个包中。 @Benjamin 错误可能会更好,但我认为BigNumber
是那里的问题。 PHP 仍然不太擅长处理预加载文件中的协变和逆变。
所以您的意思是任何在其任何方法中接受或返回BigNumber
的类都可能无法预加载?
@Benjamin 是的。有时,PHP 可以通过比较完整的类名字符串来找出答案,但这里并没有这样做。这可能是因为 BigNumber
是 abstract
或其他地方存在另一个过载。预加载仍然是新的,所以它应该会变得更好。
@Rain 是的,当您使用require
时,预加载可能会导致硬错误。但这应该意味着存在实际错误。 NikiC 在preloading pull request 上帮了很多忙,所以他知道自己在说什么。以上是关于预加载 PHP 脚本时“未知类型依赖项”是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章