<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                [TOC] * * * * * ## 1 應用調度源代碼(thinkphp/library/think/App::run()) ~~~ switch (self::$dispatch['type']) { case 'redirect': header('Location: ' . self::$dispatch['url'], true, self::$dispatch['status']); break; case 'module': $data = self::module(self::$dispatch['module'], $config); break; case 'controller': $data = Loader::action(self::$dispatch['controller'], self::$dispatch['params']); break; case 'method': $data = self::invokeMethod(self::$dispatch['method'], self::$dispatch['params']); break; case 'function': $data = self::invokeFunction(self::$dispatch['function'], self::$dispatch['params']); break; default: throw new Exception('dispatch type not support', 10008); } ~~~ ## 2 應用調度分析 ### 1 路由解析 ~~~ switch (self::$dispatch['type']) {} ~~~ $dispatch['type']是App::run()中 經過self::route(),self::dispatch()后得到 * * * * * ~~~ if (empty(self::$dispatch['type'])) { self::route($config); } ~~~ >[info] 解析url,生成$dispatch 檢查self::$dispatch['type'], 調用self::route()解析url,生成$dispatch。 * * * * * ~~~ public static function route(array $config) { self::parsePathinfo($config); if (empty($_SERVER['PATH_INFO'])) { $_SERVER['PATH_INFO'] = ''; define('__INFO__', ''); define('__EXT__', ''); } else { $_SERVER['PATH_INFO'] = trim($_SERVER['PATH_INFO'], '/'); define('__INFO__', $_SERVER['PATH_INFO']); define('__EXT__', strtolower(pathinfo($_SERVER['PATH_INFO'], PATHINFO_EXTENSION))); if ($config['url_deny_suffix'] && preg_match('/\.(' . $config['url_deny_suffix'] . ')$/i', __INFO__)) { throw new Exception('url suffix deny'); } $_SERVER['PATH_INFO'] = preg_replace($config['url_html_suffix'] ? '/\.(' . trim($config['url_html_suffix'], '.') . ')$/i' : '/\.' . __EXT__ . '$/i', '', __INFO__); } $depr = $config['pathinfo_depr']; $result = false; if (APP_ROUTE_ON && !empty($config['url_route_on'])) { if (!empty($config['route'])) { Route::register($config['route']); } $result = Route::check($_SERVER['PATH_INFO'], $depr, !IS_CLI ? $config['url_domain_deploy'] : false); if (APP_ROUTE_MUST && false === $result && $config['url_route_must']) { throw new Exception('route not define '); } } if (false === $result) { $result = Route::parseUrl($_SERVER['PATH_INFO'], $depr); } self::dispatch($result); } ~~~ self::route()中,根據配置參數,解析url。 最后調用self::dispatch(),設置$disptach 。 具體分析見[附:應用啟動文件](http://www.hmoore.net/zmwtp/tp5/119429) * * * * * ~~~ public static function dispatch($dispatch) { self::$dispatch = $dispatch; } ~~~ 在self::route中調用,設置調度類型$dispatch * * * * * ### 2 五種調度類型 >[info] Redirect類型調度 ~~~ case 'redirect': header('Location: ' . self::$dispatch['url'], true, self::$dispatch['status']); break; ~~~ $dispatch['type']為**redirect**時的應用調度 直接跳轉到**self::$dispatch['url']** >[info] Module調度類型 ~~~ case 'module': $data = self::module(self::$dispatch['module'], $config); break; ~~~ $dispatch['type']為**module**時的應用調度 調用**self::module()** >[info] Controller調度類型 ~~~ case 'controller': $data = Loader::action(self::$dispatch['controller'], self::$dispatch['params']); break; ~~~ $dispatch['type']為**controller**時的調度 調用自動加載器**Loader::action()** >[info] Method調度類型 ~~~ case 'method': $data = self::invokeMethod(self::$dispatch['method'], self::$dispatch['params']); break; ~~~ $dispatch['type']為**method**時的調度 調用**self::invokeMethod()** >[info] Function調度類型 ~~~ case 'function': $data = self::invokeFunction(self::$dispatch['function'], self::$dispatch['params']); break; ~~~ $dispatch['type']為**function**時的調度 調用**self::invokeFunction()** ~~~ default: throw new Exception('dispatch type not support', 10008); ~~~ 超出以上調度類型的直接拋出異常報錯 * * * * * ## 3 調度方法實現 上面的五種調度類型中 除了redirect,controller調度類型外的其余三種調度類型 都是調用的App內的靜態方法 moudle調度類型的self::module() method調度類型的self::invokeMethod() function調度類型的self::invokeFunction() 三個靜態方法的實現原理基本相同, 依次為調用參數分析,反射回調相應方法, 關于反射原理見基本原理的[php的反射](http://www.hmoore.net/zmwtp/tp5/119469) 下面按照源代碼順序依次分析這三個靜態方法: ### 1 self::invokeFunction() ~~~ public static function invokeFunction($function, $vars = []) { $reflect = new \ReflectionFunction($function); $args = self::bindParams($reflect, $vars); APP_DEBUG && Log::record('[ RUN ] ' . $reflect->getFileName() . '[ ' . var_export($vars, true) . ' ]', 'info'); return $reflect->invokeArgs($args); } ~~~ > $function 調用的函數名 > $vars 調用函數的參數 `$reflect = new \ReflectionFunction($function);` 創建$function的反射函數類 `$args = self::bindParams($reflect, $vars);` 創建反射函數的參數 `APP_DEBUG && Log::record('[ RUN ] ' . $reflect->getFileName() . '[ ' . var_export($vars, true) . ' ]', 'info');` 日志記錄調度運行 `return $reflect->invokeArgs($args);` 使用反射函數類調用函數,并返回結果保存到App::run()中的$data~~~ * * * * * ### 2 self::invokeMethod() ~~~ public static function invokeMethod($method, $vars = []) { if (empty($vars)) { switch (REQUEST_METHOD) { case 'POST': $vars = array_merge($_GET, $_POST); break; case 'PUT': parse_str(file_get_contents('php://input'), $vars); break; default: $vars = $_GET; } } if (is_array($method)) { $class = is_object($method[0]) ? $method[0] : new $method[0]; $reflect = new \ReflectionMethod($class, $method[1]); } else { $reflect = new \ReflectionMethod($method); } $args = self::bindParams($reflect, $vars); APP_DEBUG && Log::record('[ RUN ] ' . $reflect->getFileName() . '[ ' . var_export($args, true) . ' ]', 'info'); return $reflect->invokeArgs(isset($class) ? $class : null, $args); } ~~~ > $method 調用的方法 > $vars 調用的方法的參數 ~~~ if (empty($vars)) { switch (REQUEST_METHOD) { case 'POST': $vars = array_merge($_GET, $_POST); break; case 'PUT': parse_str(file_get_contents('php://input'), $vars); break; default: $vars = $_GET; } } ~~~ 合并$_POST $_GET $_input等參數到$vars ~~~ if (is_array($method)) { $class = is_object($method[0]) ? $method[0] : new $method[0]; $reflect = new \ReflectionMethod($class, $method[1]); } else { $reflect = new \ReflectionMethod($method); } ~~~ 檢查$method 如果為數組則是調用對象的方法 如果不是數組則是調用靜態方法 創建$method反射方法類 `$args = self::bindParams($reflect, $vars);` 同上創建參數 `APP_DEBUG && Log::record('[ RUN ] ' . $reflect->getFileName() . '[ ' . var_export($args, true) . ' ]', 'info');` 同上記錄調度運行日志 `return $reflect->invokeArgs(isset($class) ? $class : null, $args);` 同上獲取調用返回值, * * * * * ### 3 self::module() ~~~ private static function module($result, $config) { if (APP_MULTI_MODULE) { $module = strtolower($result[0] ?: $config['default_module']); if ($maps = $config['url_module_map']) { if (isset($maps[$module])) { define('MODULE_ALIAS', $module); $module = $maps[MODULE_ALIAS]; } elseif (array_search($module, $maps)) { $module = ''; } } define('MODULE_NAME', strip_tags($module)); if (MODULE_NAME && !in_array(MODULE_NAME, $config['deny_module_list']) && is_dir(APP_PATH . MODULE_NAME)) { define('MODULE_PATH', APP_PATH . MODULE_NAME . DS); define('VIEW_PATH', MODULE_PATH . VIEW_LAYER . DS); self::initModule(MODULE_NAME, $config); } else { throw new Exception('module [ ' . MODULE_NAME . ' ] not exists ', 10005); } } else { define('MODULE_NAME', ''); define('MODULE_PATH', APP_PATH); define('VIEW_PATH', MODULE_PATH . VIEW_LAYER . DS); } $controllerName = strip_tags($result[1] ?: Config::get('default_controller')); define('CONTROLLER_NAME', Config::get('url_controller_convert') ? strtolower($controllerName) : $controllerName); $actionName = strip_tags($result[2] ?: Config::get('default_action')); define('ACTION_NAME', Config::get('url_action_convert') ? strtolower($actionName) : $actionName); if (!preg_match('/^[A-Za-z](\/|\.|\w)*$/', CONTROLLER_NAME)) { throw new Exception('illegal controller name:' . CONTROLLER_NAME, 10000); } $instance = Loader::controller(CONTROLLER_NAME, '', Config::get('empty_controller')); $action = ACTION_NAME . Config::get('action_suffix'); try { $call = [$instance, $action]; APP_HOOK && Hook::listen('action_begin', $call); if (!preg_match('/^[A-Za-z](\w)*$/', $action)) { throw new Exception('illegal action name :' . ACTION_NAME, 10001); } $data = self::invokeMethod($call); } catch (\ReflectionException $e) { if (method_exists($instance, '_empty')) { $method = new \ReflectionMethod($instance, '_empty'); $data = $method->invokeArgs($instance, [$action, '']); APP_DEBUG && Log::record('[ RUN ] ' . $method->getFileName(), 'info'); } else { throw new Exception('method [ ' . (new \ReflectionClass($instance))->getName() . '->' . $action . ' ] not exists ', 10002); } } return $data; } ~~~ > $result 調用的模塊信息 > $config 調用相關的配置信息 >[info] 1 模塊參數處理 `if (APP_MULTI_MODULE) {}` 根據全局變量APP_MULTI_MODULE分為多模塊部署和單模塊部署 >[info] 1-1多模塊部署 `$module = strtolower($result[0] ?: $config['default_module']);` 將調用的模塊名稱轉換為小寫 ~~~ if ($maps = $config['url_module_map']) { if (isset($maps[$module])) { define('MODULE_ALIAS', $module); $module = $maps[MODULE_ALIAS]; } elseif (array_search($module, $maps)) { $module = ''; } ~~~ 檢查全局配置是否有別名配置 `define('MODULE_NAME', strip_tags($module));` 定義全局變量MODULE_NAME, ~~~ if (MODULE_NAME && !in_array(MODULE_NAME, $config['deny_module_list']) && is_dir(APP_PATH . MODULE_NAME)) { define('MODULE_PATH', APP_PATH . MODULE_NAME . DS); define('VIEW_PATH', MODULE_PATH . VIEW_LAYER . DS); self::initModule(MODULE_NAME, $config); } else { throw new Exception('module [ ' . MODULE_NAME . ' ] not exists ', 10005); } ~~~ 檢查模塊是否禁用$config['deny_module_list'] 模塊對應目錄是否存在APP_PATH.MODULE_NAME 定義全局變量MODULE_PATH 模塊控制器文件路徑 定義全局變量VIEW_PATH 模塊視圖文件路徑 `self::initModule(MODULE_NAME, $config);` 初始化相應模塊信息 >[info] 1-2 單一模塊部署 ~~~ define('MODULE_NAME', ''); define('MODULE_PATH', APP_PATH); define('VIEW_PATH', MODULE_PATH . VIEW_LAYER . DS); ~~~ 定義全局變量MODULE_NAME,MODULE_PATH,VIEW_PATH。 * * * * * >[info] 2 控制器參數處理 ` $controllerName = strip_tags($result[1] ?: Config::get('default_controller'));` 獲取控制器名稱 ` define('CONTROLLER_NAME', Config::get('url_controller_convert') ? strtolower($controllerName) : $controllerName);` 定義全局變量CONTROLLER_NAME 默認為小寫的控制器名字 * * * * * >[info] 3 操作參數處理 `$actionName = strip_tags($result[2] ?: Config::get('default_action'));` 獲取操作名稱 `define('ACTION_NAME', Config::get('url_action_convert') ? strtolower($actionName) : $actionName);` 定義全局變量ACTION_NAME 默認為小寫的操作名字 ~~~ if (!preg_match('/^[A-Za-z](\/|\.|\w)*$/', CONTROLLER_NAME)) { throw new Exception('illegal controller name:' . CONTROLLER_NAME, 10000); } ~~~ 檢查控制器名稱的合法性 `$instance = Loader::controller(CONTROLLER_NAME, '', Config::get('empty_controller'));` 加載控制器文件并創建控制器實例 `$action = ACTION_NAME . Config::get('action_suffix');` 獲取回調控制器的操作 * * * * * >[info] 4 應用調度運行 * * * * * >[info] try部分 `$call = [$instance, $action];` 合并控制器對象 方法為數組參數 `APP_HOOK && Hook::listen('action_begin', $call);` 運行方法開始的監聽回調 ~~~ if (!preg_match('/^[A-Za-z](\w)*$/', $action)) { throw new Exception('illegal action name :' . ACTION_NAME, 10001); } ~~~ 檢查方法名稱的合法性 `$data = self::invokeMethod($call);` 使用反射調用相應對象的方法 >[info] catch部分 ~~~ if (method_exists($instance, '_empty')) { $method = new \ReflectionMethod($instance, '_empty'); $data = $method->invokeArgs($instance, [$action, '']); APP_DEBUG && Log::record('[ RUN ] ' . $method->getFileName(), 'info'); } else { throw new Exception('method [ ' . (new \ReflectionClass($instance))->getName() . '->' . $action . ' ] not exists ', 10002); } ~~~ 對異常的處理 如果操作不存在 檢查_empty方法是否定義 并調用_empty方法 或者返回方法不存在異常 `return $data;` 返回調用的值 * * * * * ### 4 self::bindParams() ~~~ private static function bindParams($reflect, $vars) { $args = []; $keys = array_keys($vars); $type = array_keys($keys) === $keys ? 1 : 0; if ($reflect->getNumberOfParameters() > 0) { $params = $reflect->getParameters(); foreach ($params as $param) { $name = $param->getName(); if (1 == $type && !empty($vars)) { $args[] = array_shift($vars); } elseif (0 == $type && isset($vars[$name])) { $args[] = $vars[$name]; } elseif ($param->isDefaultValueAvailable()) { $args[] = $param->getDefaultValue(); } else { throw new Exception('method param miss:' . $name, 10004); } } array_walk_recursive($args, 'think\\Input::filterExp'); } return $args; } ~~~ > $reflect 反射類 > $vars 調用參數 ~~~ $keys = array_keys($vars); $type = array_keys($keys) === $keys ? 1 : 0; ~~~ 參數的數組類型轉換, ~~~ if ($reflect->getNumberOfParameters() > 0) { $params = $reflect->getParameters(); foreach ($params as $param) { $name = $param->getName(); if (1 == $type && !empty($vars)) { $args[] = array_shift($vars); } elseif (0 == $type && isset($vars[$name])) { $args[] = $vars[$name]; } elseif ($param->isDefaultValueAvailable()) { $args[] = $param->getDefaultValue(); } else { throw new Exception('method param miss:' . $name, 10004); } } array_walk_recursive($args, 'think\\Input::filterExp'); } ~~~ 將參數$args添加到回調方法的參數$args中 `return $args;` 返回合成的參數 * * * * * ## 4 總結 應用調度總的思路是根據調度類型,通過不同的調度處理,返回調度處理的結果到App::run(),然后調用Response::send()返回到客戶端。 **這里的調度是從框架底層到應用業務的跳轉核心,需要認真分析。**
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看