$controller
$controller : string
控制器名
Controller Dispatcher
init(\think\App $app)
\think\App | $app |
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
declare (strict_types = 1);
namespace think\route\dispatch;
use ReflectionClass;
use ReflectionException;
use ReflectionMethod;
use think\App;
use think\exception\ClassNotFoundException;
use think\exception\HttpException;
use think\helper\Str;
use think\route\Dispatch;
/**
* Controller Dispatcher
*/
class Controller extends Dispatch
{
/**
* 控制器名
* @var string
*/
protected $controller;
/**
* 操作名
* @var string
*/
protected $actionName;
public function init(App $app)
{
parent::init($app);
$result = $this->dispatch;
if (is_string($result)) {
$result = explode('/', $result);
}
// 获取控制器名
$controller = strip_tags($result[0] ?: $this->rule->config('default_controller'));
if (strpos($controller, '.')) {
$pos = strrpos($controller, '.');
$this->controller = substr($controller, 0, $pos) . '.' . Str::studly(substr($controller, $pos + 1));
} else {
$this->controller = Str::studly($controller);
}
// 获取操作名
$this->actionName = strip_tags($result[1] ?: $this->rule->config('default_action'));
// 设置当前请求的控制器、操作
$this->request
->setController($this->controller)
->setAction($this->actionName);
}
public function exec()
{
try {
// 实例化控制器
$instance = $this->controller($this->controller);
} catch (ClassNotFoundException $e) {
throw new HttpException(404, 'controller not exists:' . $e->getClass());
}
// 注册控制器中间件
$this->registerControllerMiddleware($instance);
return $this->app->middleware->pipeline('controller')
->send($this->request)
->then(function () use ($instance) {
// 获取当前操作名
$suffix = $this->rule->config('action_suffix');
$action = $this->actionName . $suffix;
if (is_callable([$instance, $action])) {
$vars = $this->request->param();
try {
$reflect = new ReflectionMethod($instance, $action);
// 严格获取当前操作方法名
$actionName = $reflect->getName();
if ($suffix) {
$actionName = substr($actionName, 0, -strlen($suffix));
}
$this->request->setAction($actionName);
} catch (ReflectionException $e) {
$reflect = new ReflectionMethod($instance, '__call');
$vars = [$action, $vars];
$this->request->setAction($action);
}
} else {
// 操作不存在
throw new HttpException(404, 'method not exists:' . get_class($instance) . '->' . $action . '()');
}
$data = $this->app->invokeReflectMethod($instance, $reflect, $vars);
return $this->autoResponse($data);
});
}
/**
* 使用反射机制注册控制器中间件
* @access public
* @param object $controller 控制器实例
* @return void
*/
protected function registerControllerMiddleware($controller): void
{
$class = new ReflectionClass($controller);
if ($class->hasProperty('middleware')) {
$reflectionProperty = $class->getProperty('middleware');
$reflectionProperty->setAccessible(true);
$middlewares = $reflectionProperty->getValue($controller);
foreach ($middlewares as $key => $val) {
if (!is_int($key)) {
if (isset($val['only']) && !in_array($this->request->action(true), array_map(function ($item) {
return strtolower($item);
}, is_string($val['only']) ? explode(",", $val['only']) : $val['only']))) {
continue;
} elseif (isset($val['except']) && in_array($this->request->action(true), array_map(function ($item) {
return strtolower($item);
}, is_string($val['except']) ? explode(',', $val['except']) : $val['except']))) {
continue;
} else {
$val = $key;
}
}
if (is_string($val) && strpos($val, ':')) {
$val = explode(':', $val);
if (count($val) > 1) {
$val = [$val[0], array_slice($val, 1)];
}
}
$this->app->middleware->controller($val);
}
}
}
/**
* 实例化访问控制器
* @access public
* @param string $name 资源地址
* @return object
* @throws ClassNotFoundException
*/
public function controller(string $name)
{
$suffix = $this->rule->config('controller_suffix') ? 'Controller' : '';
$controllerLayer = $this->rule->config('controller_layer') ?: 'controller';
$emptyController = $this->rule->config('empty_controller') ?: 'Error';
$class = $this->app->parseClass($controllerLayer, $name . $suffix);
if (class_exists($class)) {
return $this->app->make($class, [], true);
} elseif ($emptyController && class_exists($emptyClass = $this->app->parseClass($controllerLayer, $emptyController . $suffix))) {
return $this->app->make($emptyClass, [], true);
}
throw new ClassNotFoundException('class not exists:' . $class, $class);
}
}