require 是硬依赖,必须安装否则报错;suggest 仅为提示,不触发任何安装行为,运行时需手动检测类、扩展等存在性。

require 是装了才能跑,不装直接报错
Composer 安装时,require 里的包是硬依赖:PHP 自动加载、类存在性、函数调用全靠它撑着。漏一个,composer install 直接失败,或者运行时报 Class not found、Call to undefined function。
常见错误现象:composer update 后本地能跑,CI 环境报错——大概率是某人把本该写在 require 的包,误塞进了 suggest。
-
require包会下载、自动加载、参与 autoloader 生成 - 生产环境和开发环境都必须一致安装
- 如果只是“偶尔用到的扩展能力”,别放这儿,那是
suggest的位置
suggest 是“你可能需要,但不装也不影响主流程”
suggest 纯属提示字段,Composer 完全不处理它:不下载、不检查版本、不报错、不写进 vendor/autoload.php。它只出现在 composer show 输出里,或 composer install --verbose 的末尾提示中。
使用场景典型有三类:
- 可选驱动:比如
monolog/monolog在suggest里写"ext-amqp": "Required for AMQP handler support" - 配套工具:如
phpunit/phpunit被建议用于测试,但业务代码本身不依赖它 - 生态联动:如
laravel/frameworksuggestlaravel/tinker,方便开发者发现周边工具
注意:suggest 的值只是字符串描述,不是包名列表;它不校验语法,写错也不会报错——所以常有人填成 "foo/bar": "use it if u like",但实际想表达的是“推荐装 foo/bar”,得自己心里有数。
require-dev 和 suggest 容易混淆,但角色完全不同
require-dev 是开发期硬依赖:测试、构建、代码分析工具,比如 phpunit/phpunit、phpstan/phpstan。它和 require 一样会被 Composer 下载(除非加 --no-dev),只是不参与生产 autoload。
而 suggest 连“是否下载”都不管——它不触发任何安装行为,也不分 dev 还是 prod。
- 要让 CI 跑测试?必须放
require-dev,不能指望suggest - 想告诉用户“装了这个能支持 Redis 缓存”?写进
suggest,但得在文档或初始化逻辑里做运行时检测(比如extension_loaded('redis')) -
suggest里写的包,如果真要装,得手动composer require foo/bar,Composer 不会替你点确认
发布包时写 suggest 的几个实际坑
很多人以为 suggest 是“软依赖声明”,结果上线后发现功能抽风——因为没做运行时兜底。
- 写了
"ext-redis": "For Redis cache support",但代码里直接 new Redis(),没判断扩展是否存在 → 生产环境报错 - 建议了
"guzzlehttp/guzzle": "HTTP client for webhooks",却没在对应逻辑里做class_exists('GuzzleHttp\Client')检查 → 类未加载就 fatal error -
suggest值用了模糊描述,比如"some-package": "better experience",别人根本不知道这是功能增强还是 UI 优化
真正靠谱的做法:suggest 只负责“告知”,运行时逻辑必须自己判断扩展、类、函数是否存在,再决定走哪条路径。这一步绕不开,也没法靠 Composer 替你做。










