别从头手写composer.json,应优先用composer init交互生成;它自动确保JSON合规、字段完整、autoload正确,并避免全角引号、BOM、尾逗号等90%的语法错误。

别从头手写 composer.json,90% 的错误都源于“以为自己在写配置”,其实是在向 Composer 描述项目事实。
用 composer init 而不是手敲第一行
新建项目时,composer init 会交互式问你 name、description、require 哪些包、autoload 怎么配——它生成的结构天然合规,不会漏 autoload 字段、不会错用单引号、不会在末项加逗号。手写容易卡在 JSON 格式上:比如复制粘贴时带了全角引号、保存成 UTF-8 with BOM、最后一行多了个逗号,结果 composer install 直接报 JSON decode error: Syntax error,但错误位置不提示,只能盲猜。
实操建议:
- 执行
composer init,按提示填,不确定就直接回车跳过(多数字段可后续补) - 如果已有代码结构,让它自动探测
src/和命名空间,比自己凭空写"App": "src/"更可靠 - 生成后立刻跑
composer validate,它比人眼快十倍发现格式或逻辑问题
require 和 require-dev 的分界线是「是否参与运行时执行」
不是“本地用还是线上用”,而是“PHP 执行业务逻辑时会不会 new 它、use 它、调它的方法”。把 phpunit/phpunit 放进 require,生产环境白装几十 MB;把 guzzlehttp/guzzle 放进 require-dev,上线后所有 HTTP 请求全挂。
常见错误现象:
-
Class not found在 CI 报,本地却正常 → 检查require-dev里有没有本该在require的运行时依赖 -
composer install --no-dev后 vendor 体积没变小 → 说明有 dev 包被误塞进require - CI 构建失败,报某个 dev 工具版本冲突 → 因为
require-dev里的包间接拉入了和require冲突的子依赖
判断口诀:打开你的代码,搜 use 或 new,出现在 src/ 或 app/ 里的,进 require;只在 tests/、bin/ 或 .github/workflows/ 里出现的,进 require-dev。
autoload 配完不 dump-autoload = 白配
Composer 不会在每次请求时动态读取 composer.json 里的 autoload 配置。它只在 install、update 或显式执行 dump-autoload 时,把规则编译进 vendor/autoload.php。所以改完 psr-4 映射,不跑这步,Class not found 绝对不报错原因,只甩个异常。
关键细节:
-
psr-4的 namespace 必须以反斜杠结尾:"App": "src/"✅,"App"❌(Windows 下写成双反斜杠"App\": "src/") -
files列表里的文件,每次请求都会include_once,别往里塞初始化重的逻辑(比如连接数据库) - 混用
psr-4和classmap时,classmap优先级更高——同名类若同时存在于两个路径,加载的是classmap指向的那个
验证方式:改完立即执行 composer dump-autoload -o(-o 表示优化),然后在终端里 php -a,输入 new AppSomeClass(); 看是否报错。
别碰 composer format 之前先确认版本
Composer 2.5.0+ 内置 composer format,能安全重排缩进、修复尾随逗号、统一引号,且保留注释和字段顺序。但低于这个版本执行会报 Command "format" is not defined,有人就转头去用 jq 或 python -m json.tool,结果把 scripts 压成一行、删掉人工加的空行注释、重排 config 字段顺序——这些工具不理解 composer.json 的语义约束。
实操步骤:
- 先跑
composer --version,低于 2.5.0 就composer self-update - 格式化前加
--dry-run预览改动:composer format --dry-run - CI 中可加校验步骤:
composer format --dry-run && echo "OK" || (echo "Format error!" && exit 1)
真正难处理的从来不是语法,是那些没人检查的隐性约定:比如 name 字段缺失导致某些插件无法识别项目类型,或者 type 写错让 Laravel 的 service provider 自动注册失效——这些不会报错,只会让你花半天时间怀疑人生。


















