(相关文件链接在我的问题底部。)
我让 Composer 运行一些
post-install-cmd
和 post-update-cmd
脚本。在我的脚本中,我想使用 readlink()
中的
symfony/filesystem
函数。在我的项目 /vendor
文件夹中,有 3.4
版本的文件系统包,很好。
我
use Symfony\Component\Filesystem\Filesystem;
位于我的文件顶部。
但是每当我跑步时:
$fs = new Filesystem();
$path = '/path/to/some/symlink';
if ($fs->readlink($path)) {
// code
}
我收到以下错误,告诉我我正在调用未定义的方法:
PHP 致命错误:未捕获错误:调用未定义的方法 Symfony\Component\Filesystem\Filesystem::readlink() 中 /Users/leymannx/Sites/blog/scripts/composer/ScriptHandler.php:160
好的,所以我仔细检查了项目的
/vendor
文件夹中的类。这个方法是有的。我的 IDE 指向我那里。但当我跑步时:
$fs = new Filesystem();
get_class_methods($fs);
此方法未列出。
好的,所以我尝试检查它从哪个文件加载此类:
$fs = new Filesystem();
$a = new \ReflectionClass($fs);
echo $a->getFileName();
这让我回想起
phar:///usr/local/Cellar/composer/1.7.2/bin/composer/vendor/symfony/filesystem/Filesystem.php
– 但为什么呢?为什么它从我的 Mac 的地窖中取出包裹?这很奇怪。
但是好吧,所以我认为这是一个 Homebrew 问题,并卸载了 Homebrew Composer
$ brew uninstall --force composer
并再次将其安装为 PHAR,如 https://getcomposer.org/doc/00-intro.md#globally 上记录的那样。
但现在还是一样。
$fs = new Filesystem();
$a = new \ReflectionClass($fs);
echo $a->getFileName();
归还我
phar:///usr/local/bin/composer/vendor/symfony/filesystem/Filesystem.php
。
但是为什么呢?为什么它从我的全局 Composer 安装中获取(过时的)包?如何强制我的脚本使用项目的本地类,而不是全局 Composer 安装中的类?
最初我的
$PATH
包含/Users/leymannx/.composer/vendor/bin /usr/local/bin /usr/bin /bin /usr/sbin /sbin
。我删除了 /Users/leymannx/.composer/vendor/bin
只返回 /usr/local/bin /usr/bin /bin /usr/sbin /sbin
。还是一样。
我还尝试在我的
composer.json
中设置以下内容。还是一样:
"optimize-autoloader": true,
"classmap-authoritative": true,
"vendor-dir": "vendor/",
我终于在 GitHub 上创建了一个问题:https://github.com/composer/composer/issues/7708
这与代码运行的上下文有关。如果您直接在
post-install-cmd
中执行某个方法,它将在 Composer 进程内部执行。这意味着它将共享 composer.phar
内捆绑的所有代码。由于两个类不能具有相同的 FQN,因此在此上下文中不能包含另一个 Symfony\Component\Filesystem\Filesystem
。
您可以通过在单独的进程中运行脚本来绕过此问题。您可以创建
post-install-cmd.php
文件,在其中执行所有引导(如 require vendor/autoload.php
)并调用这些方法。然后在你的 post-install-cmd
钩子中运行这个文件:
"scripts": {
"post-install-cmd": [
"php post-install-cmd.php"
]
},
最终通过在我的脚本顶部要求
require_once __DIR__.'/../vendor/autoload.php'
并保持其他所有内容不变来修复它。