start_time = microtime(true); // $this->loadAnnotationClasses(); $this->req_mapping[0] = [ 'id' => 0, 'pid' => -1, 'name' => '/', ]; } /** * 注册各个模块类的注解和模块level的排序 * @throws ReflectionException * @throws ConfigException */ public function parseAll() { foreach ($this->path_list as $path) { logger()->debug('parsing annotation in ' . $path[0] . ':' . $path[1]); $all_class = FileSystem::getClassesPsr4($path[0], $path[1]); $conf = ZMConfig::get('global.runtime.annotation_reader_ignore'); if (isset($conf['name']) && is_array($conf['name'])) { foreach ($conf['name'] as $v) { AnnotationReader::addGlobalIgnoredName($v); } } if (isset($conf['namespace']) && is_array($conf['namespace'])) { foreach ($conf['namespace'] as $v) { AnnotationReader::addGlobalIgnoredNamespace($v); } } AnnotationReader::addGlobalIgnoredName('mixin'); $this->reader = new DualReader(new AnnotationReader(), new AttributeReader()); foreach ($all_class as $v) { logger()->debug('正在检索 ' . $v); $reflection_class = new ReflectionClass($v); $methods = $reflection_class->getMethods(ReflectionMethod::IS_PUBLIC); $class_annotations = $this->reader->getClassAnnotations($reflection_class); // 这段为新加的:start // 这里将每个类里面所有的类注解、方法注解通通加到一颗大树上,后期解析 /* $annotation_map: { Module\Example\Hello: { class_annotations: [ 注解对象1, 注解对象2, ... ], methods: [ ReflectionMethod, ReflectionMethod, ... ], methods_annotations: { foo: [ 注解对象1, 注解对象2, ... ], bar: [ 注解对象1, 注解对象2, ... ], } } } */ // 生成主树 $this->annotation_map[$v]['class_annotations'] = $class_annotations; $this->annotation_map[$v]['methods'] = $methods; foreach ($methods as $method) { $this->annotation_map[$v]['methods_annotations'][$method->getName()] = $this->reader->getMethodAnnotations($method); } foreach ($this->annotation_map[$v]['class_annotations'] as $vs) { $vs->class = $v; // 预处理1:将适用于每一个函数的注解到类注解重新注解到每个函数下面 if (($vs instanceof ErgodicAnnotation) && ($vs instanceof AnnotationBase)) { foreach (($this->annotation_map[$v]['methods'] ?? []) as $method) { $copy = clone $vs; $copy->method = $method->getName(); $this->annotation_map[$v]['methods_annotations'][$method->getName()][] = $copy; } } // 预处理2:处理 class 下面的注解 if ($vs instanceof Closed) { unset($this->annotation_map[$v]); continue 2; } if ($vs instanceof MiddlewareClass) { // 注册中间件本身的类,标记到 middlewares 属性中 logger()->debug('正在注册中间件 ' . $reflection_class->getName()); $rs = $this->registerMiddleware($vs, $reflection_class); $this->middlewares[$rs['name']] = $rs; } } $inserted = []; // 预处理3:处理每个函数上面的特殊注解,就是需要操作一些东西的 foreach (($this->annotation_map[$v]['methods_annotations'] ?? []) as $method_name => $methods_annotations) { foreach ($methods_annotations as $method_anno) { /* @var AnnotationBase $method_anno */ $method_anno->class = $v; $method_anno->method = $method_name; if (!($method_anno instanceof Middleware) && ($middlewares = ZMConfig::get('global.global_middleware_binding')[get_class($method_anno)] ?? []) !== []) { if (!isset($inserted[$v][$method_name])) { // 在这里在其他中间件前插入插入全局的中间件 foreach ($middlewares as $middleware) { $mid_class = new Middleware($middleware); $mid_class->class = $v; $mid_class->method = $method_name; $this->middleware_map[$v][$method_name][] = $mid_class; } $inserted[$v][$method_name] = true; } } elseif ($method_anno instanceof Route) { $this->addRouteAnnotation($method_anno, $method_name, $v, $methods_annotations); } elseif ($method_anno instanceof Middleware) { $this->middleware_map[$method_anno->class][$method_anno->method][] = $method_anno; } else { AnnotationMap::$_map[$method_anno->class][$method_anno->method][] = $method_anno; } } } } } logger()->debug('解析注解完毕!'); } public function generateAnnotationEvents(): array { $o = []; foreach ($this->annotation_map as $obj) { // 这里的ErgodicAnnotation是为了解决类上的注解可穿透到方法上的问题 foreach (($obj['class_annotations'] ?? []) as $class_annotation) { if ($class_annotation instanceof ErgodicAnnotation) { continue; } $o[get_class($class_annotation)][] = $class_annotation; } foreach (($obj['methods_annotations'] ?? []) as $methods_annotations) { foreach ($methods_annotations as $annotation) { $o[get_class($annotation)][] = $annotation; } } } foreach ($o as $k => $v) { $this->sortByLevel($o, $k); } return $o; } public function getMiddlewares(): array { return $this->middlewares; } public function getMiddlewareMap(): array { return $this->middleware_map; } public function getReqMapping(): array { return $this->req_mapping; } /** * @param string $path 注册解析注解的路径 * @param string $indoor_name 起始命名空间的名称 */ public function addRegisterPath(string $path, string $indoor_name) { logger()->debug('Add register path: ' . $path . ' => ' . $indoor_name); $this->path_list[] = [$path, $indoor_name]; } /** * @param array $events 需要排序的 * @param string $class_name 排序的类名 * @param string $prefix 前缀 * @internal 用于 level 排序 */ public function sortByLevel(array &$events, string $class_name, string $prefix = '') { if (is_a($class_name, Level::class, true)) { $class_name .= $prefix; usort($events[$class_name], function ($a, $b) { $left = $a->level; $right = $b->level; return $left > $right ? -1 : ($left == $right ? 0 : 1); }); } } public function getUsedTime() { return microtime(true) - $this->start_time; } // private function below private function registerMiddleware(MiddlewareClass $vs, ReflectionClass $reflection_class): array { $result = [ 'class' => '\\' . $reflection_class->getName(), 'name' => $vs->name, ]; foreach ($reflection_class->getMethods() as $vss) { $method_annotations = $this->reader->getMethodAnnotations($vss); foreach ($method_annotations as $vsss) { if ($vsss instanceof HandleBefore) { $result['before'] = $vss->getName(); } if ($vsss instanceof HandleAfter) { $result['after'] = $vss->getName(); } if ($vsss instanceof HandleException) { $result['exceptions'][$vsss->class_name] = $vss->getName(); } } } return $result; } private function addRouteAnnotation(Route $vss, $method, $class, $methods_annotations) { if (InternalGlobals::$routes === null) { InternalGlobals::$routes = new RouteCollection(); } // 拿到所属方法的类上面有没有控制器的注解 $prefix = ''; foreach ($methods_annotations as $annotation) { if ($annotation instanceof Controller) { $prefix = $annotation->prefix; break; } } $tail = trim($vss->route, '/'); $route_name = $prefix . ($tail === '' ? '' : '/') . $tail; logger()->debug('添加路由:' . $route_name); $route = new \Symfony\Component\Routing\Route($route_name, ['_class' => $class, '_method' => $method]); $route->setMethods($vss->request_method); InternalGlobals::$routes->add(md5($route_name), $route); } }