require字段不支持路径,必须用vendor/name:version格式;路径须在repositories中以type:"path"声明,且name、路径、Git分支名(如dev-main)须严格匹配。

require字段里直接写路径会彻底失效
这是最常踩的坑:require 字段只认 vendor/name:version 格式,不接受任何本地路径。写成 "myorg/utils": "./packages/my-utils" 看似直观,但 Composer 会完全忽略它,仍去 Packagist 查找,报错 Could not find a matching version of package myorg/utils。
必须把路径声明挪到 repositories 数组里,且类型明确为 "type": "path"。require 仅负责“要什么”,repositories 才决定“去哪找”。
-
repositories必须写在主项目根目录的composer.json中,不能放在本地包自己的composer.json里 -
url值是相对于主项目composer.json的路径,不是当前 shell 工作目录 - 路径末尾不能加
/,"../my-pkg/"会被静默跳过
name字段大小写和分隔符必须逐字一致
Composer 对 name 字段严格区分大小写、空格和分隔符。本地包 composer.json 里写的是 "acme/utils",而 require 写成 "Acme/utils" 或 "acme_utils",就会匹配失败,报 Could not find package,且 composer show --all 里根本不会列出该包。
常见错误包括:用下划线代替短横线、首字母大写、混用中文标点、路径含空格或中文(尤其 Windows 下某些 PHP 版本解析失败)。
- 验证方式:用
cat ../my-pkg/composer.json | grep name和grep require composer.json对比输出,确保字符串完全相同 - 本地包
composer.json必须语法合法——无尾逗号、全双引号、JSON 有效 - name 中不能出现大写字母,只能用小写字母 + 短横线
-
改了代码没生效,大概率是 symlink 没真正启用
默认行为在 Linux/macOS 是尝试创建符号链接,但失败时会静默 fallback 到复制(copy),结果你改了 ../my-pkg/src/Helper.php,vendor/acme/utils/src/Helper.php 还是旧文件——这个 bug 极隐蔽,因为没有任何报错提示。
关键不在主项目配置 "symlink": true,而在于**本地包自己的 composer.json 是否包含 "options": {"symlink": true}**。缺这句,Windows 下即使管理员权限运行,也会 fallback;Docker 容器挂载时也常因权限丢失 symlink 能力。
- 验证是否真用了 symlink:
ls -la vendor/acme/utils(Linux/macOS)看到->箭头;Windows 用dir vendor\acme\utils看是否为“JUNCTION”或“快捷方式” - 执行
composer update acme/utils才会重建链接,composer dump-autoload不影响 symlink - Windows 用户必须以管理员身份运行终端,否则 symlink 创建失败且无提示
版本约束写 * 或 ^1.0 就会找不到包
path 类型仓库下,Composer 忽略本地包 composer.json 中的 version 字段,只按 Git 分支名解析。如果你本地包没打 tag,又没初始化 Git,或者 require 写成 "acme/utils": "*",就会报错 Could not find a matching version。
正确做法是显式使用 dev- 开头的分支名,比如 "acme/utils": "dev-main"。前提是本地包目录已运行 git init 并至少有一个 commit。
- 若本地包默认分支是
develop,则 require 必须写"dev-develop" - 不建议用
"*"或"^1.0",它们只对远程 VCS 或 dist 包有效 - 执行
composer update acme/utils而非全量update,避免意外刷新其他依赖
实际调试时最容易被忽略的是:**本地包目录是否真的有 Git 仓库且 HEAD 在可识别分支上**。没有 git init,哪怕 composer.json 全对、路径全对、symlink 全开,也会静默失败。











