答案是composer link仅适用于已安装包的临时验证,无法支撑拆包迭代,因其不更新autoload、不改lock、会静默被覆盖;而path仓库配合dev-main可实现修改即生效。

必须用 path 仓库 + dev-main 版本约束,不能依赖 composer link;后者只适用于已安装包的临时验证,无法支撑拆包过程中的持续迭代。
为什么 composer link 在拆包中基本不可用
拆单体应用时,你要反复调整接口、重构类、移动命名空间——这些操作要求本地修改能「立即生效」,且不破坏自动加载和类型检查。composer link 的本质是给已安装包打补丁,它不改 composer.lock,也不重生成 autoload,更不会同步你刚删掉的旧类文件。
- 执行
composer link vendor/name前,该包必须已通过composer require安装过(即已写入composer.lock) - 一旦后续运行
composer update或 CI 环境执行composer install,软链接会被 silently 覆盖回 dist 复制模式 - Windows 上若未启用开发者模式,
composer link会静默失败,vendor 目录变成普通副本,但命令不报错 - 它无法解决「主项目还混着旧代码调用未抽离方法」的问题——这不是链接问题,是契约断裂
path 仓库配置的三个硬性条件
只有同时满足这三点,path 才会真正创建符号链接,并让修改实时可见:
-
url必须是相对于主项目composer.json的相对路径,比如"../packages/my-core";绝对路径或~/会直接失效 - 本地包根目录下必须有合法
composer.json,且其中name字段(如"myorg/core")要与主项目require中的包名完全一致 - 主项目
require中的版本必须用分支名,如"myorg/core": "dev-main";写成"1.0.0"会导致 Composer 忽略本地改动,只认包内硬编码的 version
怎么确认软链接真生效了
别信 composer install 输出的 “Installing myorg/core (dev-main)”,那只是流程日志。真实状态得靠系统命令验证:
- Linux/macOS:运行
ls -la vendor/myorg/core,输出里必须含->符号,例如vendor/myorg/core -> /absolute/path/to/packages/my-core - Windows:用
dir vendor\myorg\core查看,若显示<symlinkd></symlinkd>且目标路径可访问才算成功 - 改一行本地包里的代码,立刻在主项目中
php -r "echo (new MyOrg\Core\Service())->run();"测试——不重启、不重装、不清缓存,结果必须变 - 如果
composer show --path myorg/core返回的是vendor/myorg/core,这什么也说明不了;它永远返回这个路径,不管底下是 symlink 还是 copy
拆包过渡期最容易被忽略的陷阱
软链接只是载体,真正的平滑在于契约收敛。你可能已经配对了 path,但一跑就 Class not found 或 Interface not implemented:
- 本地包的
autoload段没配 PSR-4 映射,或者映射路径写错了(比如指向了src/但实际代码在lib/) - 主项目里还有老代码直接
use App\Services\OldService,而新包里是MyOrg\Core\Service——链接再准也没用,这是耦合没解干净 - Docker 或 WSL 中,
url指向的路径在容器内根本不存在,ls -la显示<symlink></symlink>但readlink -f失败,运行时必然报错 - CI 环境中未同步
../packages/my-core目录,Composer 会 fallback 到 Packagist 并安装空包或旧版,且不警告


















