ls -la 是唯一可信验证方式:若 vendor/vendor/name 输出含 -> 才表示软链接生效,否则为复制模式;Docker/WSL 中 readlink -f 失败或 Windows 未启开发者模式均会导致静默 fallback。

ls -la 是唯一可信的验证方式
Composer 对 path 类型仓库是否真正创建了软链接,不看日志、不看 composer install 输出,只看 ls -la vendor/vendor/name 的实际输出。出现 -> 符号才代表链接生效;否则就是 fallback 到复制模式,哪怕 composer show --path 返回的路径看起来“很合理”。
常见错误现象:
-
ls -la显示普通目录结构,但你改了本地源码,项目里却没变化 - 在 Docker 或 WSL 中
ls -la显示<symlink></symlink>,但readlink -f vendor/vendor/name报错或返回空——说明宿主机挂载路径不一致,链接目标不可达 - Windows 上未启用开发者模式,
mkdir和symlink权限被拒,Composer 静默走复制,不报错也不提示
路径权限和系统支持决定 symlink 是否可用
软链接不是“写了就一定有”,它依赖三个硬性条件同时满足:系统支持(Linux/macOS 默认支持;Windows 需开启开发者模式)、Composer 未禁用(symlink: false 在 repositories 或全局 config 中显式设置会关闭)、包类型不是 dist(即不能带 "dist": {...} 块)。
实操建议:
- 检查
composer.json中该path仓库定义,确认没有"symlink": false - Windows 用户运行
Get-ComputerInfo | Select-Object WindowsBuildLabEx,确认系统版本 ≥ 1703 且已开启“开发者模式”(设置 → 更新与安全 → 针对开发人员) - Linux/macOS 用户检查当前用户对目标源路径是否有读+执行权限(
read+execute才能chdir进入,这是 symlink 生效前提)
CI/CD 和容器环境里 symlink 几乎必然失效
CI 环境中 repositories.path 指向的目录往往根本不存在,Composer 不校验链接有效性,只按 composer.lock 记录重建路径。结果就是:本地是软链,CI 里变成 dist 复制,甚至直接失败。
关键判断点:
- 删掉
vendor/和composer.lock,在 CI 环境中跑composer install --verbose,观察日志里是否出现Reading /path/to/my-pkg/composer.json - 若日志里只有
Downloading https://...zip或直接跳过该包,说明path配置未生效,Composer 已 fallback 到 dist 或忽略 - 不要依赖
composer show --path结果做自动化判断——它永远返回vendor/...,跟底层是 symlink 还是 copy 完全无关
修改本地源码后项目不生效?先排除 OPCache 和 autoload 缓存
即使 ls -la 确认是软链,也存在“改了代码但没效果”的情况。这不是链接问题,而是 PHP 层缓存干扰。
排查顺序:
- 确认
opcache.enable=0(开发环境必须关,否则 symlink 目录下的文件变更不会触发重编译) - 运行
composer dump-autoload --optimize后再试(尤其当包用了自定义 autoload 或 classmap) - 如果用了 Swoole、RoadRunner 等常驻进程框架,重启服务进程——它们会缓存已加载的类路径,不随 symlink 内容变化自动更新
真正卡住人的从来不是“怎么配 symlink”,而是“为什么它看起来配好了却不工作”。每一步都要用终端命令交叉验证,而不是相信配置文件写对了、install 没报错、或者 IDE 显示能跳转。软链接的脆弱性在跨环境时会被放大,而 Composer 自身几乎不提供运行时校验能力。


















