[李景山php]每天TP5-20161214|App.php
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace think;// 放到同一个大包 下面
use thinkConfig;// 使用 配置类
use thinkEnv;// 使用环境类
use thinkException;// 使用异常包
use thinkexceptionHttpException;// 使用异常包 http包
use thinkexceptionHttpResponseException;// 使用异常包 http response 包
use thinkHook;// 使用 钩子 类
use thinkLang;// 使用 语言 类
use thinkLoader;// 使用 加载 类
use thinkLog;// 使用 日志 类
use thinkRequest;// 使用 请求 类
use thinkResponse;// 使用 返回 类
use thinkRoute;// 使用 路由 类
// 这个类应算是 皇上类了 可以调度基本上 全部的资源
/**
* App 应用管理
* @author liu21st <liu21st@gmail.com>
*/
class App
{
/**
* @var bool 是否初始化过
*/
protected static $init = false;// 初始化 标志位
/**
* @var string 当前模块路径
*/
public static $modulePath;// 初始化 当前 模块 路径
/**
* @var bool 应用调试模式
*/
public static $debug = true;// 应用调试 模式
/**
* @var string 应用类库命名空间
*/
public static $namespace = "app";// 应用 类库 命名空间
/**
* @var bool 应用类库后缀
*/
public static $suffix = false;// 应用 类库 后缀
/**
* @var bool 应用路由检测
*/
protected static $routeCheck;// 应用 路由 检测
/**
* @var bool 严格路由检测
*/
protected static $routeMust; // 严格 路由检测
protected static $dispatch;// 路由调度
protected static $file = []; // 文件加载
/**
* 执行应用程序
* @access public
* @param Request $request Request对象
* @return Response
* @throws Exception
*/
public static function run(Request $request = null)
{// thinkphp经过了 自动加载、错误接管、配置文件预设,终于开始执行了。
// 第一步:获取请求参数
is_null($request) && $request = Request::instance();
// self::$instance = new static($options); 执行了 这个 instance
// 默认 没有传入任何数值,is_null 所以执行 后面 $request = Request::instance();
// 这个写法 真的 很经典,我喜欢你,老刘,哈哈
// 最终获取了 一个 request 对象
$config = self::initCommon();// 加载 初始化 配置 文件 选项
// 2016-10-09
if (defined("BIND_MODULE")) {// 默认此处是没有定义的
// 模块/控制器绑定
BIND_MODULE && Route::bind(BIND_MODULE);//self::$bind = ["type" => $type, $type => $bind];
// 对 Route 的 $
} elseif ($config["auto_bind_module"]) {// 默认这里也是没有定义的
// 入口自动绑定
$name = pathinfo($request->baseFile(), PATHINFO_FILENAME);
if ($name && "index" != $name && is_dir(APP_PATH . $name)) {
Route::bind($name);
}
}
$request->filter($config["default_filter"]);// 指定 过滤 参数 为空 直接 返回
try {
// 开启多语言机制
if ($config["lang_switch_on"]) {
// 获取当前语言
$request->langset(Lang::detect());
// 加载系统语言包
Lang::load(THINK_PATH . "lang" . DS . $request->langset() . EXT);// 加载 系统 配置的语言包
if (!$config["app_multi_module"]) {// 如果没有 多模块配置
Lang::load(APP_PATH . "lang" . DS . $request->langset() . EXT);
}
}
// 获取应用调度信息
$dispatch = self::$dispatch;// 默认 为空
if (empty($dispatch)) {
// 进行URL路由检测
$dispatch = self::routeCheck($request, $config);// 获取调度信息
// 分别 通过 请求 跟 配置 文件
}
// 记录当前调度信息
$request->dispatch($dispatch);// 配置调度 信息
// 记录路由和请求信息
if (self::$debug) {
Log::record("[ ROUTE ] " . var_export($dispatch, true), "info");
Log::record("[ HEADER ] " . var_export($request->header(), true), "info");
Log::record("[ PARAM ] " . var_export($request->param(), true), "info");
}// 存入 信息 到数据,
// 监听app_begin
Hook::listen("app_begin", $dispatch);// 这个基本上 什么事情 都没干啊
switch ($dispatch["type"]) {
case "redirect":
// 执行重定向跳转
$data = Response::create($dispatch["url"], "redirect")->code($dispatch["status"]);
break;
case "module":
// 模块/控制器/操作
$data = self::module($dispatch["module"], $config, isset($dispatch["convert"]) ? $dispatch["convert"] : null);
break;
case "controller":
// 执行控制器操作
$data = Loader::action($dispatch["controller"]);
break;
case "method":
// 执行回调方法
$data = self::invokeMethod($dispatch["method"]);
break;
case "function":
// 执行闭包
$data = self::invokeFunction($dispatch["function"]);
break;
case "response":
$data = $dispatch["response"];
break;
default:
throw new InvalidArgumentException("dispatch type not support");
}
} catch (HttpResponseException $exception) {
$data = $exception->getResponse();
}
// 清空类的实例化
Loader::clearInstance();// 清空实例化
// 输出数据到客户端
if ($data instanceof Response) {
$response = $data;
} elseif (!is_null($data)) {
// 默认自动识别响应输出类型
$isAjax = $request->isAjax();
$type = $isAjax ? Config::get("default_ajax_return") : Config::get("default_return_type");
$response = Response::create($data, $type);
} else {
$response = Response::create();
}
// 监听app_end
Hook::listen("app_end", $response);// 监听 结尾,
return $response;// 此处返回 一个默认的类
}
/**
* 设置当前请求的调度信息
* @access public
* @param array|string $dispatch 调度信息
* @param string $type 调度类型
* @return void
*/
public static function dispatch($dispatch, $type = "module")
{// 赋值 当前资源
self::$dispatch = ["type" => $type, $type => $dispatch];
}
/**
* 执行函数或者闭包方法 支持参数调用
* @access public
* @param string|array|Closure $function 函数或者闭包
* @param array $vars 变量
* @return mixed
*/
public static function invokeFunction($function, $vars = [])
{
$reflect = new ReflectionFunction($function);
$args = self::bindParams($reflect, $vars);
// 记录执行信息
self::$debug && Log::record("[ RUN ] " . $reflect->__toString(), "info");
return $reflect->invokeArgs($args);
}
/**
* 调用反射执行类的方法 支持参数绑定
* @access public
* @param string|array $method 方法
* @param array $vars 变量
* @return mixed
*/
public static function invokeMethod($method, $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);
}
$args = self::bindParams($reflect, $vars);
// 记录执行信息
self::$debug && Log::record("[ RUN ] " . $reflect->__toString(), "info");
return $reflect->invokeArgs(isset($class) ? $class : null, $args);
}
/**
* 绑定参数
* @access public
* @param ReflectionMethod|ReflectionFunction $reflect 反射类
* @param array $vars 变量
* @return array
*/
private static function bindParams($reflect, $vars = [])
{
if (empty($vars)) {
// 自动获取请求变量
if (Config::get("url_param_type")) {
$vars = Request::instance()->route();
} else {
$vars = Request::instance()->param();
}
}
$args = [];
// 判断数组类型 数字数组时按顺序绑定参数
reset($vars);
$type = key($vars) === 0 ? 1 : 0;
if ($reflect->getNumberOfParameters() > 0) {
$params = $reflect->getParameters();
foreach ($params as $param) {
$name = $param->getName();
$class = $param->getClass();
if ($class) {
$className = $class->getName();
if (isset($vars[$name]) && $vars[$name] instanceof $className) {
$args[] = $vars[$name];
unset($vars[$name]);
} else {
$args[] = method_exists($className, "instance") ? $className::instance() : new $className();
}
} elseif (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 InvalidArgumentException("method param miss:" . $name);
}
}
// 全局过滤
array_walk_recursive($args, [Request::instance(), "filterExp"]);
}
return $args;
}
/**
* 执行模块
* @access public
* @param array $result 模块/控制器/操作
* @param array $config 配置参数
* @param bool $convert 是否自动转换控制器和操作名
* @return mixed
*/
public static function module($result, $config, $convert = null)
{// 其实就对 模型 路径的一个解析
if (is_string($result)) {
$result = explode("/", $result);
}
$request = Request::instance();
if ($config["app_multi_module"]) {
// 多模块部署
$module = strip_tags(strtolower($result[0] ?: $config["default_module"]));
$bind = Route::getBind("module");
$available = false;
if ($bind) {
// 绑定模块
list($bindModule) = explode("/", $bind);
if (empty($result[0])) {
$module = $bindModule;
$available = true;
} elseif ($module == $bindModule) {
$available = true;
}
} elseif (!in_array($module, $config["deny_module_list"]) && is_dir(APP_PATH . $module)) {
$available = true;
}
// 模块初始化
if ($module && $available) {
// 初始化模块
$request->module($module);
$config = self::init($module);
} else {
throw new HttpException(404, "module not exists:" . $module);
}
} else {
// 单一模块部署
$module = "";
$request->module($module);
}
// 当前模块路径
App::$modulePath = APP_PATH . ($module ? $module . DS : "");
// 是否自动转换控制器和操作名
$convert = is_bool($convert) ? $convert : $config["url_convert"];
// 获取控制器名
$controller = strip_tags($result[1] ?: $config["default_controller"]);
$controller = $convert ? strtolower($controller) : $controller;
// 获取操作名
$actionName = strip_tags($result[2] ?: $config["default_action"]);
$actionName = $convert ? strtolower($actionName) : $actionName;
// 设置当前请求的控制器、操作
$request->controller(Loader::parseName($controller, 1))->action($actionName);
// 监听module_init
Hook::listen("module_init", $request);
try {
$instance = Loader::controller($controller, $config["url_controller_layer"], $config["controller_suffix"], $config["empty_controller"]);
if (is_null($instance)) {
throw new HttpException(404, "controller not exists:" . Loader::parseName($controller, 1));
}
// 获取当前操作名
$action = $actionName . $config["action_suffix"];
if (!preg_match("/^[A-Za-z](w)*$/", $action)) {
// 非法操作
throw new ReflectionException("illegal action name:" . $actionName);
}
// 执行操作方法
$call = [$instance, $action];
Hook::listen("action_begin", $call);
$data = self::invokeMethod($call);
} catch (ReflectionException $e) {
// 操作不存在
if (method_exists($instance, "_empty")) {
$reflect = new ReflectionMethod($instance, "_empty");
$data = $reflect->invokeArgs($instance, [$action]);
self::$debug && Log::record("[ RUN ] " . $reflect->__toString(), "info");
} else {
throw new HttpException(404, "method not exists:" . (new ReflectionClass($instance))->getName() . "->" . $action);
}
}
return $data;
}
/**
* 初始化应用
*/
public static function initCommon()
{
if (empty(self::$init)) {// 初始化 配置 选项
// 初始化应用
$config = self::init();
self::$suffix = $config["class_suffix"];// 此处 默认是 false 方式。
// 应用调试模式
self::$debug = Env::get("app_debug", Config::get("app_debug"));
if (!self::$debug) {// 如果 非 系统 显示
ini_set("display_errors", "Off");//
} elseif (!IS_CLI) {// 非命令行 模式
//重新申请一块比较大的buffer
if (ob_get_level() > 0) {
$output = ob_get_clean();
}
ob_start();// 默认开始 缓存输出
if (!empty($output)) {
echo $output;
}
}
// 注册应用命名空间
self::$namespace = $config["app_namespace"];
Loader::addNamespace($config["app_namespace"], APP_PATH);
if (!empty($config["root_namespace"])) {// 默认为空
Loader::addNamespace($config["root_namespace"]);
}
// 加载额外文件
if (!empty($config["extra_file_list"])) {// 加载帮助文件
//"extra_file_list" => [THINK_PATH . "helper" . EXT],
foreach ($config["extra_file_list"] as $file) {
$file = strpos($file, ".") ? $file : APP_PATH . $file . EXT;
if (is_file($file) && !isset(self::$file[$file])) {
include $file;
self::$file[$file] = true;// 并且 提示文件已经 加载完成了
}
}
}
// 设置系统时区
date_default_timezone_set($config["default_timezone"]);
// 监听app_init
Hook::listen("app_init");
self::$init = $config;
}
return self::$init;// 返回 他【它】
}
/**
* 初始化应用或模块
* @access public
* @param string $module 模块名
* @return array
*/
private static function init($module = "")
{
// 定位模块目录
$module = $module ? $module . DS : "";// 默认为空
// 加载初始化文件
if (is_file(APP_PATH . $module . "init" . EXT)) {// 如果存在 模块 初始化 文件
include APP_PATH . $module . "init" . EXT;
} elseif (is_file(RUNTIME_PATH . $module . "init" . EXT)) {// 如果存在 运行编译后的,初始化模块
include RUNTIME_PATH . $module . "init" . EXT;
} else {// 进行默认 项目的加载
$path = APP_PATH . $module;
// 加载模块配置
$config = Config::load(CONF_PATH . $module . "config" . CONF_EXT);// 默认加载 application/config.php 文件
// 读取扩展配置文件
if ($config["extra_config_list"]) {
// 默认配置为 "extra_config_list" => ["database", "validate"],
foreach ($config["extra_config_list"] as $name => $file) {
$filename = CONF_PATH . $module . $file . CONF_EXT;
Config::load($filename, is_string($name) ? $name : pathinfo($filename, PATHINFO_FILENAME));
}
}
// 加载应用状态配置
if ($config["app_status"]) {
$config = Config::load(CONF_PATH . $module . $config["app_status"] . CONF_EXT);
}
// 加载行为扩展文件
if (is_file(CONF_PATH . $module . "tags" . EXT)) {
Hook::import(include CONF_PATH . $module . "tags" . EXT);
}
// 加载公共文件
if (is_file($path . "common" . EXT)) {
include $path . "common" . EXT;
}
// 加载当前模块语言包
if ($config["lang_switch_on"] && $module) {
Lang::load($path . "lang" . DS . Request::instance()->langset() . EXT);
}// 语言包 加载 默认为空
}
return Config::get();// 返回 Config::$config["_sys_"]// 内容,
// 以及对应的 普通 文件包含
}
/**
* URL路由检测(根据PATH_INFO)
* @access public
* @param hinkRequest $request
* @param array $config
* @return array
* @throws hinkException
*/
public static function routeCheck($request, array $config)
{
$path = $request->path();
$depr = $config["pathinfo_depr"];
$result = false;
// 路由检测
$check = !is_null(self::$routeCheck) ? self::$routeCheck : $config["url_route_on"];
if ($check) {
// 开启路由
if (is_file(RUNTIME_PATH . "route.php")) {
// 读取路由缓存
$rules = include RUNTIME_PATH . "route.php";
if (is_array($rules)) {
Route::rules($rules);
}
} else {
$files = $config["route_config_file"];
foreach ($files as $file) {
if (is_file(CONF_PATH . $file . CONF_EXT)) {
// 导入路由配置
$rules = include CONF_PATH . $file . CONF_EXT;
if (is_array($rules)) {
Route::import($rules);
}
}
}
}
// 路由检测(根据路由定义返回不同的URL调度)
$result = Route::check($request, $path, $depr, $config["url_domain_deploy"]);
$must = !is_null(self::$routeMust) ? self::$routeMust : $config["url_route_must"];
if ($must && false === $result) {
// 路由无效
throw new HttpException(404, "Route Not Found");
}
}
if (false === $result) {
// 路由无效 解析模块/控制器/操作/参数... 支持控制器自动搜索
$result = Route::parseUrl($path, $depr, $config["controller_auto_search"]);
}
return $result;
}
/**
* 设置应用的路由检测机制
* @access public
* @param bool $route 是否需要检测路由
* @param bool $must 是否强制检测路由
* @return void
*/
public static function route($route, $must = false)
{
self::$routeCheck = $route;
self::$routeMust = $must;
}
}
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。
- 上一篇: 三十一、利用微信搜索抓取公众号文章
- 下一篇: java 判断是否中文字符