php think service:discover 显式生成 vendor/services.php,扫描扩展包 composer.json 中 extra.think.providers 声明的服务提供者并写入纯 php 数组,该文件为框架初始化时 include 的零依赖输入源,非 json/yaml,不可手动修改,且必须执行后才能注册自定义服务。

php think service:discover 是触发入口
vendor/services.php 不是 Composer 自动生成的,也不是框架启动时动态写的——它由 ThinkPHP 自定义命令 php think service:discover 显式生成。这条命令扫描所有已安装扩展包的 composer.json,提取 extra.think.providers 字段声明的服务提供者类,然后写入一个 PHP 数组文件到 vendor/services.php。
常见错误现象:php think service:discover 运行后无输出、vendor/services.php 不存在、或内容为空数组 []。
- 确认扩展包的
composer.json中有合法的"extra": {"think": {"providers": ["Vendor\Package\ServiceProvider"]}}声明 - 执行命令前确保当前目录是 ThinkPHP 项目根目录(含
think可执行文件) - 若扩展包刚
composer require安装,但没运行过service:discover,服务提供者不会被注册 - Windows 下注意路径大小写和反斜杠转义问题,可能导致扫描失败
services.php 内容是纯 PHP 数组,不是 JSON
vendor/services.php 是一个可直接 include 的 PHP 文件,内容形如:
return [
hinkservicePaginatorService::class,
hinkserviceValidateService::class,
VendorPackageServiceProvider::class,
];它不包含任何逻辑,只负责把服务类名列表“导出”给框架初始化流程使用。
为什么不用 JSON 或 YAML?因为 ThinkPHP 在 App 初始化早期就 include 它,要求零依赖、零解析开销、绝对可靠。
- 手动修改这个文件无效:下次执行
service:discover会被覆盖 - 不要在该文件里写条件判断或 require 其他文件——它只应返回数组
- 如果
include报错(如 Parse error),大概率是某扩展包的composer.json里 providers 数组格式非法(比如多了一个逗号、引号不闭合)
runtime/service.php 和 vendor/services.php 不是一回事
别混淆这两个文件:vendor/services.php 是服务发现的**中间产物**,而真正被框架加载的是 runtime/service.php(或类似路径,取决于 config/app.php 中 'service_file' 配置)。后者由 RegisterService 在初始化阶段读取前者内容,再合并内置服务后生成,且带缓存逻辑(如存在则跳过重写)。
也就是说:vendor/services.php 是输入源,runtime/service.php 是运行时实际加载的最终配置。
- 开发期改了扩展包的 providers 声明,必须重新运行
service:discover才能更新vendor/services.php - 但即使
vendor/services.php更新了,若runtime/service.php没刷新(比如 runtime 目录权限不足),新服务仍不会生效 - 线上环境建议禁用
service:discover,改用 config/app.php 的'providers'数组硬编码,避免 runtime 目录不可写导致服务丢失
不执行 service:discover 就无法加载自定义服务提供者
ThinkPHP 不会自动监听 composer.json 变化,也不会在每次请求时重新扫描 vendor。一旦跳过 service:discover,哪怕扩展包已正确安装、autoload 没问题、extra.think.providers 也写对了,vendor/services.php 就是空的,后续整个服务注册链就断了。
最常被忽略的一点:这个机制和 Composer 的 autoload 完全解耦。autoloader 能找到类,不代表服务提供者会被注册;类能 new 出来,不代表它已被绑定进容器。
- 报错
Class not found时先查 autoload;报错Cannot resolve ... from container或服务方法未执行,优先检查service:discover是否运行成功 - CI/CD 流程中,务必在
composer install后追加php think service:discover - 本地开发时,可 alias 一条命令,比如
alias tpup='composer update && php think service:discover'
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











