发现thinkphp5.1.5在处理鸵峰命名的类时提示找不到控制器。
创建了一个api模块,controller文件夹中创建AdminUser.php类:
<?php
namespace app\api\controller;
use think\Controller;
class AdminUser extends Controller
{
public function adminUserInfo($id){
return $id;
}
}

访问http://oa.com/index.php/api/adminuser/adminUserInfo/id/2时出现如下错误:

我的控制器明明是AdminUser,它提示的却是Adminuser,鸵峰命名的类被它转成只有首字母大写的风格了,自己找不着我的AdminUser类了。
不知道有没有人遇到过类似的问题,请注意我用的是从官方git仓库拉取的最新版本。
自己折腾中... ...
有解决办法的小伙伴麻烦跟贴YY一下
======================================
== 从代码中去找自己踩中的坑 ===
======================================
下面这部分是我从错误提示中排查和解决的经历,这个问题把我困扰了一个下午。希望下面的内容可以帮助那些和我一样遇到这种问题的小白:
首先从我的问题根源追究起:
http://oa.com/index.php/api/adminuser/adminUserInfo/id/1
报错如上面的图片所示。
先不去管别的,我们从下面错误的提示Call Stack中看第一个出错的文件提示:
Call Stack
in Module.php line 100
at Module->run() in Url.php line 26
at Url->run() in App.php line 362
at App->run() in index.php line 20
把鼠标放到Module.php上,会有这个文件的路径提示,找到Module.php文件:
thinkphp/library/route/dispatch/Moudel.php
第一百行代码:(因为它提示的错误就是第100行):
throw new HttpException(404, 'controller not exists:' . $e->getClass());
这就是提示控制器不存在的代码,$e->getClass()是获取到的模块名(类名)如果我们从getClass()这个方法去追溯错误根源,可能有点麻烦,因为这个进去是错误处理的一些东西,跟我们想要的不在一个点上。
那接着看它的第二个提醒 :
at Module->run() in Url.php line 26
还是在这个文件里,但是是第26行的问题:
if (is_string($result)) {
$result = explode('/', $result);
}
26行是 if (is_string($result)),输出一下$result是个什么东西。dump($result):array(3) {
[0] => string(3) "api"
[1] => string(9) "adminuser"
[2] => string(13) "adminUserInfo"
}
发现$result就是我们把我们请求的模块,控制器和方法解析成一个数组。这里它解析出来的,还是跟我请求的URL中的字符是一样的:http://oa.com/index.php/api/adminuser/adminUserInfo/id/1
为什么要说这个呢,因为我注意到它错误提示不存在的控制是Adminuser,实际上我创建的是class AdminUser,说好的鸵峰呢?
那问题是不是出在请求的路由上?是分大小写的?输入的请求是AdminUser和adminuser,它提示不存在的控制都是Adminuser,
那就是就是框架内部把AdminUser转换了。那就从Moudel.php的第 26行往下看吧,因为不管输入的是AdminUser还是全小写的adminuser,26行前面的接收的
$result跟我们输入的大小写是完全吻合的,说明这里还没有对解析的请求字符做大小写转换。
你细心的话,往下就应该发现,好多初始化实例的操作都在这里来完成了。
有初始化模块,获取控制器名,获取操作名... ...
什么?获取控制器名?你不是提示我控制器不存在吗?这里获取,那获取出来的是一个什么鬼?明明在的说不存在。
看代码:
// 是否自动转换控制器和操作名
$convert = is_bool($this->convert) ? $this->convert : $this->app->config('app.url_convert');
// 获取控制器名
$controller = strip_tags($result[1] ?: $this->app->config('app.default_controller'));
$controller = $convert ? strtolower($controller) : $controller;
这里把$controller输出来看看:adminuser
果不其然!不管你在URL中用大写还是小写,这里全部被转换成了小写。那问题就来了,是谁来决定转换成小写这个操作呢?就这个代码 :
$convert = is_bool($this->convert) ? $this->convert : $this->app->config('app.url_convert');
通过$this->app->config('app.url_convert')可以知道它在读取url_convert配置项来决定要不要转换成大小写。去配置文件中看一下:
// 是否自动转换URL中的控制器和操作名
'url_convert' => true,
这里配置是默认开启自动转换的。那它Adminuser这个没有鸵峰风格的控制器是怎么来的?
亲,到这一步就差不多了。框架默认是把所有请求的控制器名都转为小写的,那像AdminUser这样的风格就不是在这里处理。
我突然想到先看一下手册吧
找到控制器定义:
控制器类文件的实际位置是
application\index\controller\HelloWorld.php,
访问URL地址是(假设没有定义路由的情况下)
http://localhost/index.php/index/HelloWorld
原来这才是症结所在!没有定义路由的情况下,对于鸵峰命名的控制器名的访问不是相同的控制器本身,而是要用开线分开!
http://oa.com/index.php/api/admin_user/adminUserInfo/id/1
http://oa.com/index.php/api/Admin_User/adminUserInfo/id/1
这个时候就是你不管大小写,都正确无误了。
其实写了这么多,你会发现这很好笑。因为废话了半天,问题的答案却跟你追溯了半天的努力不相关。
我想说的是,当你遇到问题的时候,不妨学会自己去思考一下,先不要急于向别人求证或者放弃。
等你一步一步去独立去把问题解决掉之后,你才会在这种反复的折腾中进步。
求人不如求已。
最佳答案
