从easyswoole2.X源码解读-事件注册EventRegister我们知道,onRequest事件会通过Dispatcher分发到http的控制器
1. \easyswoole\vendor\easyswoole\easyswoole\src\Core\Http\Dispatcher.php
其实开启不同的服务,会调用对应服务的Dispatcher类;
例如socket服务easyswoole\vendor\easyswoole\easyswoole\src\Core\Socket\Dispatcher.php
我们先讨论http服务的Dispatcher类;
2. 在默认注册事件中,
$dispatcher = new Dispatcher($controllerNameSpace);
$request_psr,$response_psr 分别对应easyswoole的request对象和response对象
$dispatcher->dispatch($request_psr,$response_psr);
3.dispatch方法
如果有自定义路由,优先使用自定义的
public function dispatch(Request $request,Response $response):void
{
if($this->router === null){
$router = $this->checkRouter();
if($router){
$this->routerMethodNotAllowCallBack = $router->getMethodNotAllowCallBack();
$this->router = new GroupCountBased($router->getRouteCollector()->getData());
}else{
$this->router = false;
}
}
if(!$response->isEndResponse()){
$this->router($request,$response);
};
if(!$response->isEndResponse()){
$this->controllerHandler($request,$response);
};
}
4.Router自定义路由,
先判断 App\HttpController命名空间下是否有Router类,有则返回这个实例;
若需要在EasySwoole使用自定义路由拦截功能,请在应用目录的Http控制器目录下(默认为HttpController)下,建立Router类, 井继承\EasySwoole\Core\Http\AbstractInterface\Router实现register方法
private function checkRouter():?Router
{
$class = $this->controllerNameSpacePrefix.'\\Router';
if(class_exists($class)){
$router = new $class;
if($router instanceof Router){
return $router;
}else{
return null;
}
}else{
return null;
}
}
5. 执行对应controller
最终(new $finalClass($actionName,$request,$response)); 通过类的构造方法来执行对应的action;
private function controllerHandler(Request $request,Response $response)
{
$pathInfo = ltrim(UrlParser::pathInfo($request->getUri()->getPath()),"/");
$list = explode("/",$pathInfo);
$actionName = null;
$finalClass = null;
$controlMaxDepth = Di::getInstance()->get(SysConst::HTTP_CONTROLLER_MAX_DEPTH);
$currentDepth = count($list);
$maxDepth = $currentDepth < $controlMaxDepth ? $currentDepth : $controlMaxDepth;
while ($maxDepth >= 0){
$className = '';
for ($i=0 ;$i<$maxDepth;$i++){
$className = $className."\\".ucfirst($list[$i] ?: 'Index');//为一级控制器Index服务
}
if(class_exists($this->controllerNameSpacePrefix.$className)){
//尝试获取该class后的actionName
$actionName = empty($list[$i]) ? 'index' : $list[$i];
$finalClass = $this->controllerNameSpacePrefix.$className;
break;
}else{
//尝试搜搜index控制器
$temp = $className."\\Index";
if(class_exists($this->controllerNameSpacePrefix.$temp)){
$finalClass = $this->controllerNameSpacePrefix.$temp;
//尝试获取该class后的actionName
$actionName = empty($list[$i]) ? 'index' : $list[$i];
break;
}
}
$maxDepth--;
}
if(!empty($finalClass)){
(new $finalClass($actionName,$request,$response));
}else{
if(in_array($request->getUri()->getPath(),['/','/index.html'])){
$content = file_get_contents(__DIR__.'/../../Resource/welcome.html');
}else{
$response->withStatus(Status::CODE_NOT_FOUND);
$content = file_get_contents(__DIR__.'/../../Resource/404.html');
}
$response->write($content);
}
}
5.1 可以看下controller构造方法
public function __construct(string $actionName,Request $request,Response $response)
{
$this->request = $request;
$this->response = $response;
$this->actionName = $actionName;
if($actionName == '__construct'){
$this->response()->withStatus(Status::CODE_BAD_REQUEST);
}else{
$this->__hook( $actionName);
}
}
5.2 所有可以在控制器类添加onRequest($actionName)方法,通过返回bool来限制这个方法是否能够调用
protected function __hook(?string $actionName):void
{
if($this->onRequest($actionName) !== false){
//支持在子类控制器中以private,protected来修饰某个方法不可见
try{
$ref = new \ReflectionClass(static::class);
if($ref->hasMethod($actionName) && $ref->getMethod( $actionName)->isPublic()){
$this->$actionName();
}else{
$this->actionNotFound($actionName);
}
}catch (\Throwable $throwable){
$this->onException($throwable,$actionName);
}
//afterAction 始终都会被执行
try{
$this->afterAction($actionName);
}catch (\Throwable $throwable){
$this->onException($throwable,$actionName);
}
}
}