Composer的path依赖不参与repositories顺序优先级,仅当require包名与本地composer.json中name字段完全一致时才触发直连;它绕过所有仓库匹配流程,是独立开发通道。

Composer 的 path 依赖不参与“优先级竞争”,它只在 require 明确命中时才触发,且完全绕过所有其他仓库(包括 packagist 和镜像)——不是“优先”,而是“专属通道”。
为什么 repositories 数组顺序对 path 无效
path 类型仓库不走常规的“按序匹配 → 下载 → 安装”流程。它被设计为一种开发期直连机制:只要 require 中的包名与本地 composer.json 中的 name 字段逐字一致,Composer 就会跳过网络查找,直接解析本地路径。
-
type: "vcs"或type: "composer"仓库才依赖repositories数组顺序,第一个匹配即终止 -
type: "path"是独立通道,哪怕你把它放在数组末尾,只要require写对了,它就生效;放前面也并不会让它“抢”其他包的安装权 - 常见误操作:把
path和镜像源混写在同一repositories里,结果发现私有包没走本地、反而去连了镜像——那是因为name拼错了,根本没命中path规则
path 依赖生效的三个硬性条件
缺一不可,任一失败都静默跳过,无错误提示。
-
url必须是相对路径,且以./或../开头,例如"../my-utils"✅;"my-utils"❌,"/home/user/my-utils"❌,"../my-utils/"(末尾斜杠)❌ - 该路径下必须存在合法的
composer.json,其中name字段(如"acme/utils")必须和你在composer require里写的**完全一致**:大小写、短横线、vendor 名全部敏感 - 执行
composer require acme/utils:dev-main时,本地包目录必须是 Git 仓库(git init && git add . && git commit -m "init"),且当前分支为main(或你指定的分支名);不能写acme/utils:1.0.0,除非你打了 tag
如何确认 path 真正在用,而不是 fallback 到复制或网络
别信 composer install 输出里的 “Installing”,要看底层行为和运行时效果。
- 加
-vvv运行:composer require acme/utils:dev-main -vvv,日志中必须出现Symlinking from ../my-utils或Copying from ../my-utils—— 前者才是预期行为 - 检查
vendor/acme/utils是否为符号链接:ls -la vendor/acme/utils(Linux/macOS)看到->,Windows 上用dir vendorcmeutils看到JUNCTION才算成功;若只是普通文件夹,说明 symlink 失败并 fallback 到 copy - 改一行本地包代码,然后在主项目里调用它,看是否立刻生效 —— 如果没变,大概率是 symlink 没建起来,或你没运行
composer update acme/utils(install不刷新已有链接)
autoload 不更新?90% 是忘了这一步
path 让包“存在”,但类能不能 new 或 use,取决于自动加载映射是否包含它的真实路径。这个映射不会随 symlink 自动刷新。
- 确保本地包自己的
composer.json中声明了正确的autoload,例如:"psr-4": {"Acme\Utils\": "src/"}—— 注意末尾双反斜杠和路径拼写 - 主项目中执行
composer dump-autoload(开发阶段不用-o),否则新映射不会写入vendor/composer/autoload_static.php - 如果测试类在
tests/下,且用了autoload-dev,请确认其映射末尾带反斜杠:"Acme\Tests\": "tests/",少一个就断掉 - 验证是否真生成了映射:打开
vendor/composer/autoload_classmap.php,搜索你的类名,看路径是否指向../my-utils/src/...而不是vendor/acme/utils/src/...
最常被忽略的是:symlink 生效与否,取决于本地包自己的 composer.json 里有没有 "options": {"symlink": true},而不是主项目的配置;Windows 用户必须管理员权限运行终端,否则连失败提示都没有。











