如何在Composer中为开发(Dev)和生产(Prod)环境加载不同的配置?

12次阅读

composer 通过 autoload-dev 实现开发与生产配置分离:autoload 下的配置始终生效,autoload-dev 中的路径仅在启用 dev 模式(未加 –no-dev)时加载;生产环境执行 composer install –no-dev 后,dev 类不会被自动加载,因此必须由应用层根据环境变量动态实例化对应配置类,且开发专用依赖须严格置于 require-dev 中。

如何在Composer中为开发(Dev)和生产(Prod)环境加载不同的配置?

composer.jsonautoload-dev 区分开发与生产配置加载

Composer 本身不提供“环境感知”的自动加载机制,但可以通过 autoload-dev 配置让开发专用文件(如调试配置、Mock类)只在 composer install --dev 或本地运行时加载,而不会进入生产部署包。

关键在于:生产环境执行 composer install --no-dev 后,autoload-dev 中定义的路径和 PSR-4 映射将被完全忽略,对应文件不会写入 vendor/autoload.php,也不会被自动加载器识别。

  • autoload 下的配置始终生效(适用于所有环境)
  • autoload-dev 下的配置仅在启用了 dev 模式时生效(即未加 --no-dev
  • 不要把生产必需的配置文件放在 autoload-dev 里,否则上线后会报 class not found
{     "autoload": {         "psr-4": {             "app\": "src/"         }     },     "autoload-dev": {         "psr-4": {             "App\Config\Dev\": "config/dev/",             "App\Config\Prod\": "config/prod/"         }     } }

在代码中按环境动态加载配置类

不能依赖 Composer 自动加载“切换配置”,必须由应用层控制——比如在启动时根据 $_ENV['APP_ENV']环境变量决定实例化哪个配置类。

常见错误是直接 new DevConfig() 而不检查环境,导致生产环境因类未加载(或不应加载)而崩溃。

  • 确保 DevConfig 类只出现在 autoload-dev 映射中,且不在生产 composer install --no-dev 的产物里
  • 用工厂模式或简单条件判断加载:比如 if ($_ENV['APP_ENV'] === 'dev') { new DevConfig(); } else { new ProdConfig(); }
  • 避免在全局作用域中无条件 new 开发类,否则即使没调用也会触发 autoload 失败

require-dev 管理仅开发环境需要的包

有些配置依赖外部工具(如 phpunit/phpunitsymfony/var-dumper),它们不该出现在生产环境中。这些应严格放在 require-dev 里。

如果误写进 require,即使你没在生产代码中 use 它们,Composer 仍会安装并可能引发安全扫描告警或兼容性问题。

  • require-dev 中的包在 composer install --no-dev 时完全不安装
  • 若某包既被开发使用、又被生产配置逻辑间接依赖(例如日志格式化器),它就不是纯 dev 依赖,得移回 require
  • 运行 composer show --dev 可确认当前是否加载了 dev 包

注意 composer dump-autoload 的环境一致性

执行 composer dump-autoload 时,默认包含 dev 加载规则。如果你在 CI/CD 流水线中先运行了该命令再执行 --no-dev 安装,生成的 autoloader 可能残留 dev 映射,导致生产环境意外加载开发类。

  • CI 中推荐统一用 composer install --no-dev --optimize-autoloader,跳过手动 dump 步骤
  • 本地开发可保留 composer dump-autoload -o 提升性能,但别把它提交到部署脚本里
  • 检查 vendor/composer/autoload_psr4.php 文件内容,确认生产构建后不含 Dev\ 相关路径

最易被忽略的是:以为只要不 new 就安全,其实只要类名出现在任何已加载文件的 useclass_exists() 中,就会触发 autoload —— 而这个 autoload 表是否含 dev 类,取决于当初怎么 install 的。

text=ZqhQzanResources