vendor/services.php 文件因 php think service:discover 命令在 Workerman 等扩展安装后,因 installed.json 格式变更导致遍历逻辑失效而被清空;需手动从 installed.json 提取 extra.think.services 字段内容,写入 services.php 并确保格式为 return ['class1', 'class2'];,无 BOM、无空行、无输出。

vendor/services.php 文件为什么突然没了
它不是被误删的,而是 php think service:discover 命令在某些扩展(比如 Workerman)安装后执行时,因 vendor/composer/installed.json 格式变更,导致遍历逻辑失效,最终生成空数组并覆盖了原有内容。现象是:控制器报错 控制器不存在: appcontrollerAdmin,但 app/controller/Admin.php 明明存在——根本原因是服务注册表清空,框架连路由解析器、控制器绑定器这些基础服务都没加载进来。
怎么快速恢复 services.php 内容
别重跑 service:discover,它大概率还会写空。直接从源头补:
- 打开
vendor/composer/installed.json - 搜索所有
"extra": {"think": {"services": [片段,提取里面每个字符串值,例如"think\service\RouteService" - 新建或编辑
vendor/services.php,内容格式为:return [ 'think\service\RouteService', 'think\service\AppService', // ……把你从 installed.json 里拷出来的全部粘贴到这里 ]; - 确保文件以
return [开头,无 BOM、无空行、无 echo/var_dump
如何防止下次再丢
临时修复只是救急,真正要堵住漏洞得改扫描逻辑:
- 定位到
vendor/topthink/framework/src/think/console/command/ServiceDiscover.php - 找到第 33–37 行左右的循环体(含
foreach($packages as $package)) - 把原逻辑替换为更健壮的写法:
foreach ($packages as $package) { $servicesList = $package['extra']['think']['services'] ?? []; if (is_array($servicesList)) { $services = array_merge($services, $servicesList); } elseif (is_string($servicesList)) { $services[] = $servicesList; } }
这个改动能兼容新旧版 installed.json 中 services 字段可能为字符串或数组的两种情况,避免再次清空。
验证是否真正生效
光有 services.php 文件还不够,得确认它被读进去了:
- 清空
runtime/下所有缓存(runtime/cache/、runtime/log/、runtime/container/全删) - 访问任意页面,看是否还报控制器不存在;如果仍报错,用
var_dump(class_exists('think\service\RouteService'));在入口加一行测试 - 若返回
false,说明services.php没被加载——检查是否漏了return,或文件权限为只读(Linux 下常见)
最易被忽略的是:services.php 必须是纯 PHP 返回数组,任何前置输出(哪怕一个空格)都会让 require 失败,而框架不会报错,只会静默跳过。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











