Composer中软链接是否启用由环境与配置共同决定:默认尝试创建symlink,但仅当系统支持、未禁用、非dist包且路径可达时生效,否则静默回退为复制。

软链接在 Composer 中是否启用,不由你决定,而由环境和配置共同决定
Composer 对 path 类型仓库默认尝试创建符号链接(symlink),但仅当满足全部条件时才真正生效:系统支持(Linux/macOS 默认支持,Windows 需开发者模式)、未显式禁用、包未标记为 "dist"、且源路径可读可访问。不满足任一条件,Composer 会静默 fallback 到复制模式——你根本不会收到任何提示。
这意味着,你以为的“软链开发流”在生产环境很可能早已退化为“复制副本”,而你却还依赖着“改源码即生效”的错觉。
生产环境使用 symlink 的三大风险点
- CI/CD 流水线中
repositories.path指向的本地目录通常不存在,Composer 直接跳过 symlink 尝试,转而安装 dist 包(如果有的话)或报错失败 - Windows 生产服务器若未启用开发者模式,
symlink调用被系统拒绝,Composer 不报错但走复制逻辑,导致vendor/下代码与源码不同步,热更新失效 - Docker 或 WSL 场景下,宿主机挂载路径与容器内路径不一致时,
ls -la可能显示->,但readlink -f vendor/vendor/name返回空或错误——运行时加载类失败、找不到文件,错误信息里完全不提“链接失效”
如何验证 symlink 是否真正在起作用
别信 composer install 输出,也别信 composer show --path ——它只返回 vendor/ 下的路径,不反映底层是链接还是复制。
必须人工验证:
- Linux/macOS:
ls -la vendor/vendor/name,看到-> /absolute/path/to/src才算有效 - 再执行
readlink -f vendor/vendor/name,确保输出是真实可访问的绝对路径 - 改一行本地源码,立刻在项目中调用对应类或函数,确认行为已更新(这是唯一运行时验证方式)
- Windows:用
dir vendor\vendor\name看是否有标识,并确认 PowerShell 中Get-Item vendor\vendor\name | % Target有输出
生产环境建议:默认关闭 symlink,除非你全程掌控路径与权限
在 repositories 的单个 path 条目里明确写入:
{
"type": "path",
"url": "../my-package",
"options": {
"symlink": false
}
}
这个 "symlink": false 必须放在 options 下,且属于该 path 仓库定义内部——写在全局 config 或顶层 options 里完全无效。
关闭后,Composer 始终复制文件,行为确定、可审计、无跨环境歧义。对于 CI 构建、Docker 镜像打包、多实例部署等场景,确定性比“省一次拷贝”重要得多。
真正需要热联动的环节(如本地开发联调),应通过 IDE 文件监听 + rsync / inotify + 容器卷挂载等方式实现,而不是把部署机制和开发便利性混在一起。











