Class not found 时软链接存在但失效,需验证 readlink -f 目标路径是否可达、权限是否正常、大小写及挂载是否正确,并执行 composer dump-autoload -o 和清理 OPCache。

ls -la 看到 -> 却报 Class not found 怎么办
软链接存在 ≠ 目标路径可访问。Composer 创建 symlink 后,运行时 PHP 加载类失败,90% 是因为 readlink -f vendor/vendor/name 返回空或报错,说明目标路径在当前环境不可达。
常见表现:
-
ls -la vendor/monolog/monolog显示monolog/monolog -> /home/user/my-project/packages/monolog - 但
readlink -f vendor/monolog/monolog输出为空,或提示No such file or directory - 执行
php -r "require 'vendor/autoload.php';"报Class not found
必须立刻验证三件事:
- 手动
ls -la /home/user/my-project/packages/monolog/composer.json—— 文件是否存在?权限是否为-rw-r--r--? - 检查路径是否含大小写错误(Linux/macOS 下
Packages/monolog≠packages/monolog) - 若在 Docker 或 WSL 中,确认该路径是否挂载进容器:宿主机能访问 ≠ 容器内能
readlink到
CI/CD 里 symlink 显示正常但运行时报错
CI 环境(GitHub Actions、GitLab CI)默认不启用符号链接支持,且 repositories.path 指向的本地目录往往根本不存在——Composer 不报错,而是静默 fallback 到 dist 安装(如果包有 dist 配置),或直接失败。
典型翻车点:
-
composer install日志里出现Installing monolog/monolog (dev-main): Downloading (100%)—— 这说明它没走 symlink,而是下了 zip 包 -
ls -la vendor/monolog/monolog看起来像软链,但readlink -f失败,或cat vendor/monolog/monolog/composer.json | grep name返回的是 dist 包里的内容,不是你本地源的
解决方案只有两个:
- CI 脚本中显式禁用 symlink:
composer config --global path.repo false,然后改用git clone+composer install组合 - 或确保 CI job 的工作目录里真实存在
repositories.path所指的目录,并通过cp -r或rsync提前复制进去(不能靠挂载)
Windows 上 symlink 显示为普通文件夹怎么办
Windows 默认禁止非管理员创建符号链接,Composer 检测失败后会自动降级为复制(copy),且不提示。你看到 vendor/vendor/name 是个普通文件夹,不是因为配置错了,而是系统权限拦住了。
验证方式:
- 打开 PowerShell,运行
Get-ChildItem -Path vendorendor ame -Force—— 如果输出里没有Mode列显示l(link),就是复制模式 - 检查是否启用了开发者模式:设置 → 更新与安全 → 针对开发人员 → 开启“开发者模式”
- 确认 Composer 是否以管理员身份运行(通常不需要,但某些策略组策略会强制要求)
注意:composer show --path vendor/name 永远只返回 vendor/vendor/name 这个路径,它不告诉你底下是 symlink 还是 copy —— 别被这个命令骗了。
修改本地源代码后项目没反应
这是判断 symlink 是否真正生效的黄金测试:改一行本地源码(比如在 packages/my-pkg/src/Helper.php 里加个 echo 'live';),然后直接运行项目入口脚本(如 php index.php)。如果没输出,说明不是 symlink 生效了,而是 dist 复制、OPCache 缓存、或 autoload 没刷新。
排查顺序必须是:
- 先确认
readlink -f vendor/vendor/name输出的是你刚改代码的那个绝对路径 - 再运行
composer dump-autoload(不是install,也不是update) - 如果部署在线上,
opcache_reset()或重启 PHP-FPM —— OPCache 会缓存旧的 classmap,改了源码也不生效 - 最后检查 PSR-4 映射:
"MyPackage\": "src/"和实际文件路径src/Helper.php、命名空间MyPackageHelper是否完全一致(大小写、反斜杠、路径分隔符)
最常被忽略的一点:symlink 目标路径里如果有中文、空格或特殊符号(比如 my pkg),Windows 和部分 CI 工具链会直接拒绝解析,且无明确报错 —— 改成纯英文下划线命名再试。











