1) { $method = array_pop($pathInfo); } else { $method = self::METHOD_DEFAULT; } $controller = $prefix . '\\' . implode('\\', $pathInfo); // 加入一次出错重试的机会 for ($i = 0; $i < 2; $i++) { try { // 判断是否是公开方法 $reflection = new \ReflectionMethod($controller, $method); if ($reflection->isPublic() == false) { throw new \Exception($controller . "::$method is not public"); } $controller = new $controller(); $controller->$method(); break; } catch (\Exception $ex) { Logger::emerg($ex, 'dispatcher.run'); $controller = $prefix . '\\' . self::CONTROLLER_ERROR; $method = self::METHOD_DEFAULT; } } } /** * 分发请求 * @param string $customPrefix * @param string $pathInfo */ public static function dispatch($customPrefix, $pathInfo = '') { header("HTTP/1.1 200"); header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE"); header("Access-Control-Allow-Headers: *"); // 获取前缀 $prefix = '\Heanup\\App\\' . self::convertToClassName($customPrefix) . "\\Controller"; if (!$pathInfo) { $pathInfo = self::getPathInfo(); } $pathInfo = self::convertToClassName($pathInfo); try { $path = explode('\\', $pathInfo); $id = array_pop($path); if (is_numeric($id)) { $_GET['id'] = $id; $pathInfo = implode('\\', $path); } $controller = $prefix . '\\' . $pathInfo; // 如果类不存在则使用默认的错误类 if (!class_exists($controller)) { //类不存在则尝试通过自定义路由解析 $url = $_SERVER["REQUEST_URI"]; // 去除 ?后面的部分 $request = parse_url($url); $url = $request['path']; $route = Route::getData($customPrefix); foreach ($route as $val) { $pattern = $val["pattern"]; $params = self::checkUrl(strtolower($url), strtolower($pattern)); if ($params != null) { $controller = $val["action"]; $count = count($params); for ($i = 0; $i < $count; $i++) { $_GET['args_' . $i] = $params[$i]; } break;// 寻找到第一个匹配的路由即执行,然后返回 } } if (!class_exists($controller)) { Logger::error($controller, 'dispatcher.controller_not_exist'); throw new \Exception($controller . ' not exist'); } } // 判断主方法 if (!method_exists($controller, 'run')) { throw new \Exception($controller . ' has no method called "run"'); } $controller = new $controller(); $controller->run(); } catch (\Exception $ex) { $method = strtolower($_SERVER['REQUEST_METHOD']); if ($method == 'options') { header("HTTP/1.1 200"); header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE"); header("Access-Control-Allow-Headers: lang,token,content-type"); die(); } Response::sendResponse(404, [], $ex->getMessage()); Logger::emerg($ex, 'dispatcher.dispatch'); } } /** * 正则匹配检查,并提取出参数 * @param $str * @param $pattern * @return array|null */ private static function checkUrl($str, $pattern) { $ma = array(); $pattern = ltrim(rtrim($pattern, "/")); $pattern = "/" . str_replace("/", "\/", $pattern) . "\/?$/"; $pattern = str_replace(":s", "([^\/]+)", $pattern); if (preg_match($pattern, $str, $ma) > 0) { array_shift($ma); return $ma; } return null; } /** * 获取pathInfo, 兼容Apache, Nginx * 如果使用Apache的话可以直接使用 $_SERVER['PATH_INFO']的 * @return string */ protected static function getPathInfo() { //去掉uri中的PHP_SELF 信息 $length = strlen($_SERVER['PHP_SELF']); if (substr($_SERVER['REQUEST_URI'], 0, $length) == $_SERVER['PHP_SELF']) { $request = substr($_SERVER['REQUEST_URI'], $length); } else { $request = $_SERVER['REQUEST_URI']; } // 去除 ?后面的部分 $request = parse_url($request); $request = $request['path']; $request = urldecode($request); $request = trim($request, '/_ '); // 去掉 '.' 后缀 if (strpos($request, '.') !== false) { $request = explode('.', $request); $request = array_shift($request); } if (empty($request)) { $request = self::CONTROLLER_DEFAULT; } return $request; } /** * 将字符串转成带命名空间的类名 * @param $string * @return string */ public static function convertToClassName($string) { $string = trim($string, '\\/_ '); $string = strtolower($string); $string = str_replace('/', '\\', $string); $string = str_replace(' ', '\\', ucwords(str_replace('\\', ' ', $string))); $string = str_replace(' ', '', ucwords(str_replace('_', ' ', $string))); return $string; } }