答案是:symlink参数必须写在本地包自己的composer.json顶层,与name、version同级,值为true;主项目中配置无效。缺此配置,Windows必fallback到copy,Linux/macOS也易静默降级,导致改代码不生效。

symlink参数必须写在本地包自己的composer.json里
绝大多数人配不成功,是因为把 "options": {"symlink": true} 错误地加在了主项目的 composer.json 的 repositories 里。实际生效位置是**本地包根目录下的 composer.json**——不是主项目,也不是全局 config。
这个配置告诉 Composer:“当我被作为 path 仓库引入时,请强制用符号链接,别复制。” 缺了它,Windows 默认 fallback 到 copy,Linux/macOS 虽可能成功建链,但一旦权限或路径稍有异常,也会静默降级,你改代码根本不会反映到 vendor/ 中。
- 本地包
composer.json必须存在且语法合法(无尾逗号、全双引号) -
"options"是顶层字段,和"name"、"version"同级,不是嵌套在"autoload"或"require"里 - 值必须是布尔
true,写成"1"、"yes"或省略引号都会失效
为什么 composer update vendor/name 才能触发 symlink 创建
composer install 不会重建已有链接;它只按 composer.lock 拉取,而 lock 文件里若记录的是 source.type: "dist" 或旧的 "copy" 状态,就不会重试 symlink。
只有 composer update vendor/name(精确到包名)才会重新解析仓库类型、读取本地包的 options 字段,并尝试创建符号链接。如果失败,它也不会报错,而是默默 fallback 到复制——所以你得手动验证。
- 执行后立刻检查:
ls -la vendor/vendor/name(Linux/macOS)或dir vendor\vendor\name(Windows) - 看到
-> /abs/path/to/local-pkg或JUNCTION才算成功 - 若显示为普通文件夹,说明 fallback 了,优先排查本地包
composer.json是否漏了"options"
Windows 和 Docker 下 symlink 的硬性前提
即使配置全对,Windows 和 Docker 也常因权限或内核能力缺失导致 symlink 失败,且无明确错误提示。
Windows 用户必须以管理员身份运行终端(CMD/PowerShell/WSL 均需),否则 mklink 被拒,Composer 静默降级。Docker 容器默认无 SYS_ADMIN 权限,无法创建符号链接,挂载宿主机路径后依然 fallback 到 copy。
- Windows:启用“开发者模式”或组策略中开启“创建符号链接”权限
- Docker:启动容器时加
--cap-add=SYS_ADMIN,并确认挂载方式支持 symlink(如-v $(pwd)/../my-pkg:/mnt/pkg:shared) - 路径避免含空格或中文,某些 PHP 版本在 Windows 下解析会截断
验证 symlink 是否真正生效的三个关键点
光看命令没报错没用。真正生效要同时满足:锁文件记录、文件系统链接、类加载路径一致。
缺一不可。最容易忽略的是 autoload 映射——即使链接建成了,如果本地包的 autoload 段没配好,或者主项目没执行 composer dump-autoload -o,new XxxClass() 还是会报 class not found。
- 检查
composer.lock中该包的source.type是否为"path",且source.url指向正确路径 - 用
ls -la或dir确认vendor/vendor/name是链接而非文件夹 - 修改本地包源码后,在主项目中运行
composer dump-autoload -o,确保 PSR-4/PSR-0 映射刷新
options 声明、以及每次变更后的 composer update vendor/name + dump-autoload 组合操作,这三者不全满足,就不可能实现真正的热更新。


















