根本原因是Windows宿主机生成的符号链接在Linux容器中解析为Windows路径(如C:projectendor),而容器内无C:盘;应使用composer install --prefer-dist或COMPOSER_PREFER_DIST=1避免软链接,且vendor必须在容器内安装而非挂载覆盖。

为什么Docker里vendor/bin脚本执行报错“File not found”
根本不是脚本写错了,而是vendor/下符号链接指向的路径在容器内根本不存在——尤其当你把项目目录挂载自 Windows(比如/mnt/c/project)时,NTFS 上创建的 symlink 在 Linux 容器里会被解释成 Windows 风格路径(如C:projectendorsome-package),而容器里根本没有C:盘。
- 现象:运行
vendor/bin/phpunit提示No such file or directory,但ls -l vendor/bin/phpunit显示链接存在 - 本质:symlink 目标路径跨系统失效,不是权限问题,也不是 PHP 版本问题
- 验证方式:
readlink -f vendor/bin/phpunit,如果输出含C:或/mnt/c/,就坐实了这个问题
怎么让composer install不生成软链接
别等报错再折腾,直接绕过 symlink 机制。Composer 官方支持--prefer-dist模式,它下载 zip 包并解压,完全不依赖 symlink。
-
composer install --prefer-dist:单次生效,适合 CI 或临时修复 -
COMPOSER_PREFER_DIST=1 composer install:Linux/macOS 临时环境变量启用 -
composer config -g prefer-dist true:全局生效,一劳永逸(推荐 WSL2/Docker 用户长期启用) - 注意:
composer.json里若写了"preferred-install": "source",会覆盖该设置,要删掉或改成"dist"
Docker volume挂载时vendor目录被覆盖怎么办
你用docker run -v $(pwd):/app挂载代码目录,然后在容器外执行了composer install——结果容器启动时,/app/vendor被宿主机目录覆盖,里面根本没有 Composer 在容器内生成的正确 symlink 或 dist 文件结构。
- 正确做法:所有
composer install必须在容器内部执行,且vendor/不能被宿主机卷直接覆盖 - 开发中推荐方案:
docker run -v $(pwd):/app -v app-vendor:/app/vendor image composer install,用命名卷托管vendor - CI 场景下,直接在
ubuntu-latestrunner 上跑composer install --prefer-dist,别用 Windows runner + setup-php - 如果必须挂载
vendor,确保挂载前已在容器内完成composer install,否则挂载动作会清空容器内已生成的内容
autoload.php加载失败还查不到类?先看vendor/composer/autoload_psr4.php
符号链接失效常连带导致 PSR-4 映射错乱——因为 Composer 自动生成的autoload_psr4.php里大量用__DIR__拼路径,而 symlink 路径解析错误会让__DIR__指向一个不存在的父目录,最终整个映射表为空或错位。
- 打开
vendor/composer/autoload_psr4.php,搜索你的命名空间(如"App\"),如果找不到,说明 autoload 没生效 - 不要只跑
composer dump-autoload,先确认vendor/是否完整:运行composer show,看依赖是否真被安装 - 检查
composer.json中autoload路径是否真实存在,且不能是软链接(某些挂载方式会让app/目录在容器内不可见) - Linux 容器里大小写敏感,
src/Http/Controller和src/Http/controller是两个不同路径,映射会直接跳过后者
vendor/目录里残留的旧 symlink 和 autoload 文件还在,它们不会自动刷新。动手前先rm -rf vendor,再用--prefer-dist重装,才能真正从头开始。


















