生产环境依赖必须放 require,开发测试依赖放 require-dev;部署时必须用 --no-dev 避免注入调试工具;symfony/flex 通常放 require-dev;升级 symfony 大版本需删 lock 文件并强制重装 recipes。

composer.json 里该用 require 还是 require-dev?
Symfony 项目里,依赖分两类:运行时必需的(比如 doctrine/orm),和只在开发/测试时需要的(比如 phpunit/phpunit 或 symfony/debug-bundle)。
错放会直接导致生产环境出问题:把调试工具塞进 require,上线后可能暴露敏感信息;反过来,把 symfony/console 放进 require-dev,bin/console 就直接报错。
- 生产必须的包(如
symfony/framework-bundle、twig/twig)一律进require - 只用于本地开发、CI 测试或调试的(如
symfony/maker-bundle、doctrine/doctrine-fixtures-bundle)进require-dev - 注意
symfony/flex是个例外:它本身不参与运行,但影响安装流程,所以放在require-dev更安全(除非你明确要它在 CI 中介入自动配置)
为什么 composer install --no-dev 在部署时不能省?
很多团队在 CI/CD 里漏掉这个参数,结果把 phpunit、debug-bundle 全打进生产镜像。这不只是浪费磁盘空间——更严重的是:
debug-bundle启用后可能泄露堆栈、环境变量甚至源码maker-bundle的命令类被自动注册,万一路由没关严,/_profiler类接口可能意外暴露某些 dev-only 包含
autoload-dev规则,混入生产后可能干扰自动加载顺序部署脚本里必须显式加
--no-dev,哪怕COMPOSER_ENV=prod也不顶用Dockerfile 中建议写成:
composer install --no-interaction --optimize-autoloader --no-dev--optimize-autoloader能把 PSR-4 映射转成静态数组,启动快 10%–20%,别漏
symfony/flex 的 recipes 怎么关又怎么开?
Flex 是 Symfony 的“依赖自动化管家”,它通过 recipes 自动往项目里扔配置、复制文件、改 composer.json。好处是快,坏处是黑盒——你不一定知道它悄悄改了啥。
常见翻车点:
升级
symfony/console时,Flex 自动覆盖bin/console,把你加的自定义启动逻辑冲掉某些 bundle 的 recipe 会强制启用监听器(比如
doctrine/doctrine-bundle默认开 SQL 日志),线上性能直降关 recipe:在
composer.json加"extra": {"symfony": {"allow-contrib": false}}开单个 recipe:用
composer sync-recipes <code>vendor/package--force查当前生效的 recipe:
composer recipes,注意看状态列是install还是sync
升级 Symfony 主版本时,composer update 为什么总卡住?
比如从 Symfony 5.4 升 6.4,composer update "symfony/*" 经常失败,不是版本冲突,而是 Flex 的 recipe 机制和旧 lock 文件互相锁死。
根本原因是:Flex 会读 composer.lock 里的旧版本号来决定应用哪个 recipe,而 lock 文件又依赖当前 composer.json 的约束——死循环。
- 先跑
composer update --dry-run "symfony/*"看哪些包真要动 - 再手动删掉
composer.lock和vendor/(别怕,composer.json是唯一真相) - 然后
composer update "symfony/*" --with-all-dependencies,加上--with-all-dependencies才能连带更新doctrine、twig等强耦合包 - 最后立刻跑
composer recipes:install --force -v,让 Flex 重刷一遍配置,别跳过
Flex 的 recipe 行为高度依赖 lock 文件快照,一旦版本跨度过大,就别指望它自己理清依赖链。手动清场比硬扛报错快得多。










