composer show --locked才是ThinkPHP项目可复现、可部署的真实依赖快照,因它强制从composer.lock读取精确版本、source.type、commit hash及私有源地址,而默认composer show仅反映当前vendor状态,易与lock不一致导致Class not found或版本漂移。

直接用 composer show --locked 导出的清单,才是 ThinkPHP 项目可复现、可部署的真实依赖快照;仅靠 composer show 或扫 composer.json 会漏掉嵌套版本、私有源包和实际安装路径,迁移后大概率报 Class not found 或 Cannot redeclare function。
为什么 tp 项目必须用 --locked 而不是默认 show
ThinkPHP 项目常混用原生 require_once、自定义 autoload 和 Composer 自动加载,composer show 默认读的是 vendor/composer/installed.json,它反映的是“当前 vendor 目录里有什么”,但不保证和 composer.lock 一致——比如你本地 composer update 过,但没提交 lock 文件,CI 环境 composer install 就会按 composer.json 重新解析,装出不同版本的 topthink/framework 或 monolog/monolog。
-
composer show --locked强制从composer.lock解析,输出字段含version(精确到2.0.12而非^2.0)、source.type(git还是dist)、source.reference(commit hash),这才是 tp 部署时真正装进去的 - tp6 常用的
topthink/think-orm若来自私有 GitLab 仓库,show可能只显示包名,而--locked会保留"source": {"url": "https://gitlab.example.com/tp/orm.git", "type": "git", "reference": "a1b2c3..."} - 若项目删过
vendor/但 lock 文件还在,composer show会直接报错Could not find package information for,而composer show --locked仍可执行
导出生产环境专用清单(不含 require-dev)
tp 项目上线前要剔除 phpunit/phpunit、friendsofphp/php-cs-fixer 等开发依赖,否则可能暴露测试入口或引发 autoloader 冲突。关键不是过滤显示,而是确保生成的清单对应真实部署行为。
- 运行
composer show --locked --no-dev --format=short > deps-prod.txt,每行格式为topthink/framework 6.1.8,适合粘贴进运维文档或 CI 检查脚本 - 更稳妥的做法是先生成精简 lock 文件:
composer export --without-dev --format=lock > composer-prod.lock,再用jq -r '.packages[] | "\(.name) \(.version)"' composer-prod.lock提取,它会递归剔除 dev 包及其所有子依赖(如phpunit带进来的sebastian/exporter) - 别用
composer show --no-dev --tree—— 它只隐藏顶层 dev 包,但像topthink/framework依赖的psr/log如果被phpunit间接拉入,仍会出现在树里,造成误判
tp 项目迁移时怎么验证依赖是否完整
tp 的 app 目录下常有无命名空间的老代码(如 app/model/User.php),它们不走 Composer autoload,但又依赖 topthink/think-helper 等包。导出清单只是第一步,必须确认这些类在新环境真能加载。
- 检查
composer.json的autoload.classmap是否覆盖了 tp 的传统目录:"classmap": ["app/", "extend/", "public/static/"],然后必须运行composer dump-autoload -o生成优化映射 - 入口文件
public/index.php第一行必须是require __DIR__ . '/../vendor/autoload.php';,且不能有任何require_once 'app/model/User.php'出现在它之前,否则旧逻辑会抢先加载,导致class_exists('User')返回 true,但实例化时报Cannot redeclare class - 运行
composer depends topthink/framework确认没有其他包在间接引用它——tp6 有时会被topthink/think-swoole或topthink/think-queue覆盖,版本冲突会导致Facade加载失败
最容易被忽略的是:tp 项目里 config/app.php 中的 'default_module' 或 'app_debug' 设置,和依赖清单无关,但若迁移时漏改,会直接让路由 404 或日志写不进 runtime/log;导出依赖只是还原技术栈,业务配置得另做检查。











