微服务必须各自独立维护composer.lock文件,禁止共享或统一管理;不同服务对同一sdk版本需求可能冲突,共享lock会导致ci构建失败;每个服务的lock文件须提交至对应仓库主分支,确保可重现构建。

微服务不能共用 composer.lock,必须各自锁定
直接把所有服务的 composer.lock 文件统一管理是行不通的。不同服务对同一 SDK 的版本诉求可能冲突:比如订单服务依赖 acme/user-sdk ^2.3,而通知服务已升级到 ^3.0,强行共享 lock 会导致 Your lock file does not contain a compatible set of packages 报错,CI 构建失败。
每个微服务必须维护自己独立的 composer.json 和 composer.lock,且 composer.lock 必须提交到对应 Git 仓库主分支。这是可重现构建的前提,不是“多此一举”。
- 禁止在多个仓库间复制粘贴
composer.lock - 禁止通过脚本批量重写所有服务的 lock 文件来“对齐”
-
composer update只能在本地开发时谨慎使用,CI 中一律禁用
SDK 必须发布为独立语义化版本包
想让多个服务用相同版本的 SDK,核心不是约束 lock,而是约束源——把 SDK 打包成独立 Composer 包,打正式 tag(如 v2.3.1),再由各服务显式 require。
例如,acme/user-sdk 发布 v2.3.1 后,所有服务都写:"acme/user-sdk": "2.3.1"(不用 ^2.3),避免 Composer 自行解析出不同 minor 版本。
- SDK 仓库的
composer.json中设"minimum-stability": "stable"和"prefer-stable": true,防止子依赖引入 dev 包 - 禁止在服务中直接
require acme/user-sdk:dev-main—— CI 构建时会因无源仓库路径失败 - 本地开发可用
"repositories"+"type": "path"临时调试,但上线前必须切回私有 Packagist 或 Satis 地址
所有服务统一镜像源与 platform 配置
镜像源和 PHP 运行环境配置不统一,会导致不同服务生成的 composer.lock 解析结果不一致,哪怕 require 写得一模一样。
必须在每个服务的 composer.json 中显式声明:
"repositories": {
"packagist.org": {"type": "composer", "url": "https://mirrors.aliyun.com/composer/"}
},
"config": {
"platform": {"php": "8.1.0"},
"preferred-install": "dist"
}
-
"packagist.org"键名不能写成"packagist"或"default",否则 Composer 2.9+ 会忽略 -
"platform": {"php": "8.1.0"}比"^8.1"更安全,避免 patch 版本差异影响依赖树 - 若某服务需
ext-gd,其他服务不需要,不要在 platform 里硬加"ext-gd": "true"—— 这掩盖真实环境缺陷
OpenAPI 客户端必须抽离为独立包
用 openapi-generator-cli 为用户服务生成 PHP 客户端后,不能直接塞进订单服务的 src/ 目录或靠 autoload 映射加载 —— 这破坏服务边界,且无法版本控制。
正确做法是:生成后删掉 vendor/ 和 composer.lock,只保留源码 + 精简的 composer.json(含 "require": {"php": "^8.1"}),然后打 tag v1.2.0 并发布到私有仓库。
- 各服务通过
"acme/user-api-client": "^1.2"引入,版本受控、可审计 - 禁止在服务中
require openapitools/openapi-generator-cli—— 它是构建期工具,不是运行时依赖 - CI 流水线里调用 generator 会因 Node.js 缺失或权限失败,且生成代码易因 CLI 版本不一致而漂移
真正难的不是怎么装包,而是怎么让每个服务在独立 lock 的前提下,仍能复用同一份 SDK 行为。这要求你把“版本契约”从 lock 文件里抽出来,写进包名、tag、require 字符串和 CI 校验逻辑里——漏掉任何一环,都会在灰度发布时突然报 Class not found。











