composer.json 的 name 字段必须为 "vendor/name" 格式(全小写、斜杠分隔),否则依赖安装、autoload 等会静默失败;psr-4 路径须真实存在且末尾带斜杠;版本约束应明确边界,scripts 中 PHP 命令需显式加 php 前缀;composer.lock 必须随修改提交并用于 CI 安装。

composer.json 里 name 字段必须填,且格式要严格
不填 name 或格式错(比如写成 "my-project" 却漏了 vendor 名),composer install 不报错,但后续所有依赖安装、autoload 生成、甚至 composer dump-autoload 都可能静默失败或行为异常——尤其在用 psr-4 自动加载时,类找不到根本不会提示“name 缺失”,只会报 Class not found。
正确写法是 "vendor/name",两个单词用斜杠分隔,全小写,不能含空格或大写字母。例如:"acme/blog-api",不是 "AcmeBlogApi",也不是 "blog-api"。
- vendor 名建议和 GitHub 组织/用户名一致,方便 Packagist 同步
- 本地开发没打算发包?也得填,否则
require本地路径包时会解析失败 - 如果项目只是脚本工具,没有发布计划,可用占位名如
"local/scripts",但别留空或只写"scripts"
autoload 的 psr-4 路径必须真实存在,且末尾带斜杠
psr-4 映射的目录路径如果不存在,Composer 不校验也不报错;但运行时 class_exists() 或自动加载就会失败。更隐蔽的是:路径末尾漏掉斜杠(比如写成 "App\": "src/App"),PHP 自动加载器会拼出 src/AppSomeClass.php,而不是预期的 src/App/SomeClass.php,直接 404。
示例错误配置:"App\": "src/App" → 正确应为 "App\": "src/App/"(注意末尾斜杠)。
- 路径是相对于
composer.json所在目录的相对路径,不要用./开头 - 多个命名空间可共用一个目录,但别让子命名空间覆盖父命名空间(如同时定义
"App\"和"App\Http\"指向不同目录,容易冲突) - 开发中改了
autoload,必须手动运行composer dump-autoload,install或update不会自动触发
require 和 require-dev 的版本约束别盲目用 ^ 或 ~
写 "monolog/monolog": "^2.0" 看似稳妥,但实际会装到 2.10.0 甚至 2.99.9 ——只要主版本号是 2 就算兼容。而某些次要版本可能引入破坏性变更(比如移除一个方法),导致你的代码在 CI 上突然挂掉。
真正可控的做法是:明确最小可用版本 + 锁定最大兼容边界。例如用 "^2.8.0" 表示允许 2.8.0 到 2.999.999,但前提是确认过 2.8.0 确实能跑通你的全部逻辑。
- 新项目起步阶段,优先用具体版本如
"2.8.0",等稳定后再放宽 -
require-dev里的包(如phpunit/phpunit)版本可以比require更激进,但别用*或dev-main,CI 构建会不可靠 - 如果依赖某个包的特定 commit,用
"dev-main#abc123"格式,但仅限临时调试,别提交到主分支
scripts 里执行 PHP 命令必须显式调用 php
在 scripts 里写 "test": "phpunit" 看起来干净,但很多环境(尤其是 Docker 或某些 macOS Homebrew 安装)下,phpunit 是 PHAR 文件,没加可执行权限或没设 shebang,直接执行会报 command not found 或 Permission denied。Composer 不会帮你补 php 前缀。
正确写法永远是 "test": "php vendor/bin/phpunit"(路径写死)或 "test": "php -d memory_limit=-1 vendor/bin/phpunit"(顺便控制内存)。
- 所有
vendor/bin/xxx工具都必须加php前缀,包括phpcs、phpstan、phinx - scripts 中的命令不继承 shell 的 alias 或函数,
php必须是系统 PATH 下的真实二进制 - 想跨平台兼容?避免用
&&连接多条命令,改用composer run-script分拆,或写成独立脚本文件再调用
最常被跳过的其实是 composer.lock 提交和更新时机:本地改了 composer.json,跑完 composer update 后,composer.lock 必须一起提交;CI 构建时则必须用 composer install --no-dev,而不是 update —— 否则 lock 文件失效,版本漂移就藏不住了。


















