ThinkPHP中的跨控制器调用与框架执行流程
2016-06-17 10:05
537 查看
一、跨控制器调用
UserController.class.php<?php namespace Home/Controller use Think/Controller class UserController extends Controller{ public function show(){ //TODO } }
IndexController.class.php(方法一)
<?php namespace Home/Controller use Think/Controller class IndexController extends Controller{ public function count(){ //通过快捷函数来实例化一个控制器 //User为控制器名 $user = A('User'); $user-> show(); } }
IndexController.class.php(方法二)
<?php namespace Home/Controller use Think/Controller class IndexController extends Controller{ public function count(){ //User为控制器名,show为其方法 R('User/show'); } }
二、ThinkPHP执行流程
当一个客户端发起一个请求的时候先去访问应用入口文件<?php // 应用入口文件 // 检测PHP环境 if(version_compare(PHP_VERSION,'5.3.0','<')) die('require PHP > 5.3.0 !'); // 开启调试模式 建议开发阶段开启 部署阶段注释或者设为false define('APP_DEBUG',True); // 引入ThinkPHP入口文件 require '../../ThinkPHP/ThinkPHP.php';
在应用入口文件中引入TinkPHP框架的入口文件,然后执行该文件中的代码。
在TinkPHP.php中做了一些初始化操作,比如定义了大量的全局常量,运行环境检测等
ThinkPHP.php
<?php // 记录开始运行时间 $GLOBALS['_beginTime'] = microtime(TRUE); // 记录内存初始使用 define('MEMORY_LIMIT_ON',function_exists('memory_get_usage')); if(MEMORY_LIMIT_ON) $GLOBALS['_startUseMems'] = memory_get_usage(); // 版本信息 const THINK_VERSION = '3.2.3'; // URL 模式定义 const URL_COMMON = 0; //普通模式 const URL_PATHINFO = 1; //PATHINFO模式 const URL_REWRITE = 2; //REWRITE模式 const URL_COMPAT = 3; // 兼容模式 // 类文件后缀 const EXT = '.class.php'; // 系统常量定义 defined('THINK_PATH') or define('THINK_PATH', __DIR__.'/'); defined('APP_PATH') or define('APP_PATH', dirname($_SERVER['SCRIPT_FILENAME']).'/'); defined('APP_STATUS') or define('APP_STATUS', ''); // 应用状态 加载对应的配置文件 defined('APP_DEBUG') or define('APP_DEBUG', false); // 是否调试模式 if(function_exists('saeAutoLoader')){// 自动识别SAE环境 defined('APP_MODE') or define('APP_MODE', 'sae'); defined('STORAGE_TYPE') or define('STORAGE_TYPE', 'Sae'); }else{ defined('APP_MODE') or define('APP_MODE', 'common'); // 应用模式 默认为普通模式 defined('STORAGE_TYPE') or define('STORAGE_TYPE', 'File'); // 存储类型 默认为File } defined('RUNTIME_PATH') or define('RUNTIME_PATH', APP_PATH.'Runtime/'); // 系统运行时目录 defined('LIB_PATH') or define('LIB_PATH', realpath(THINK_PATH.'Library').'/'); // 系统核心类库目录 defined('CORE_PATH') or define('CORE_PATH', LIB_PATH.'Think/'); // Think类库目录 defined('BEHAVIOR_PATH')or define('BEHAVIOR_PATH', LIB_PATH.'Behavior/'); // 行为类库目录 defined('MODE_PATH') or define('MODE_PATH', THINK_PATH.'Mode/'); // 系统应用模式目录 defined('VENDOR_PATH') or define('VENDOR_PATH', LIB_PATH.'Vendor/'); // 第三方类库目录 defined('COMMON_PATH') or define('COMMON_PATH', APP_PATH.'Common/'); // 应用公共目录 defined('CONF_PATH') or define('CONF_PATH', COMMON_PATH.'Conf/'); // 应用配置目录 defined('LANG_PATH') or define('LANG_PATH', COMMON_PATH.'Lang/'); // 应用语言目录 defined('HTML_PATH') or define('HTML_PATH', APP_PATH.'Html/'); // 应用静态目录 defined('LOG_PATH') or define('LOG_PATH', RUNTIME_PATH.'Logs/'); // 应用日志目录 defined('TEMP_PATH') or define('TEMP_PATH', RUNTIME_PATH.'Temp/'); // 应用缓存目录 defined('DATA_PATH') or define('DATA_PATH', RUNTIME_PATH.'Data/'); // 应用数据目录 defined('CACHE_PATH') or define('CACHE_PATH', RUNTIME_PATH.'Cache/'); // 应用模板缓存目录 defined('CONF_EXT') or define('CONF_EXT', '.php'); // 配置文件后缀 defined('CONF_PARSE') or define('CONF_PARSE', ''); // 配置文件解析方法 defined('ADDON_PATH') or define('ADDON_PATH', APP_PATH.'Addon'); // 系统信息 if(version_compare(PHP_VERSION,'5.4.0','<')) { ini_set('magic_quotes_runtime',0); define('MAGIC_QUOTES_GPC',get_magic_quotes_gpc()? true : false); }else{ define('MAGIC_QUOTES_GPC',false); } define('IS_CGI',(0 === strpos(PHP_SAPI,'cgi') || false !== strpos(PHP_SAPI,'fcgi')) ? 1 : 0 ); define('IS_WIN',strstr(PHP_OS, 'WIN') ? 1 : 0 ); define('IS_CLI',PHP_SAPI=='cli'? 1 : 0); if(!IS_CLI) { // 当前文件名 if(!defined('_PHP_FILE_')) { if(IS_CGI) { //CGI/FASTCGI模式下 $_temp = explode('.php',$_SERVER['PHP_SELF']); define('_PHP_FILE_', rtrim(str_replace($_SERVER['HTTP_HOST'],'',$_temp[0].'.php'),'/')); }else { define('_PHP_FILE_', rtrim($_SERVER['SCRIPT_NAME'],'/')); } } if(!defined('__ROOT__')) { $_root = rtrim(dirname(_PHP_FILE_),'/'); define('__ROOT__', (($_root=='/' || $_root=='\\')?'':$_root)); } } // 加载核心Think类 ThinkPHP/Library/Think/Think.class.php require CORE_PATH.'Think'.EXT; // 应用初始化,调用Think类的静态方法start() Think\Think::start();
Think.class.php
<?php // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- // | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st <liu21st@gmail.com> // +---------------------------------------------------------------------- namespace Think; /** * ThinkPHP 应用程序类 执行应用过程管理 */ class App { /** * 应用程序初始化 * @access public * @return void */ static public function init() { // 加载动态应用公共文件和配置 load_ext_file(COMMON_PATH); // 日志目录转换为绝对路径 默认情况下存储到公共模块下面 C('LOG_PATH', realpath(LOG_PATH).'/Common/'); // 定义当前请求的系统常量 define('NOW_TIME', $_SERVER['REQUEST_TIME']); define('REQUEST_METHOD',$_SERVER['REQUEST_METHOD']); define('IS_GET', REQUEST_METHOD =='GET' ? true : false); define('IS_POST', REQUEST_METHOD =='POST' ? true : false); define('IS_PUT', REQUEST_METHOD =='PUT' ? true : false); define('IS_DELETE', REQUEST_METHOD =='DELETE' ? true : false); // URL调度, 把模块、控制器、方法赋予常量 // MOUDLE_NAME = 模块名 // CONTROLLER_NAME // ACTION_NAME Dispatcher::dispatch(); if(C('REQUEST_VARS_FILTER')){ // 全局安全过滤 array_walk_recursive($_GET, 'think_filter'); array_walk_recursive($_POST, 'think_filter'); array_walk_recursive($_REQUEST, 'think_filter'); } // URL调度结束标签 Hook::listen('url_dispatch'); define('IS_AJAX', ((isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') || !empty($_POST[C('VAR_AJAX_SUBMIT')]) || !empty($_GET[C('VAR_AJAX_SUBMIT')])) ? true : false); // TMPL_EXCEPTION_FILE 改为绝对地址 C('TMPL_EXCEPTION_FILE',realpath(C('TMPL_EXCEPTION_FILE'))); return ; } /** * 执行应用程序 * @access public * @return void */ static public function exec() { if(!preg_match('/^[A-Za-z](\/|\w)*$/',CONTROLLER_NAME)){ // 安全检测 $module = false; }elseif(C('ACTION_BIND_CLASS')){ // 操作绑定到类:模块\Controller\控制器\操作 $layer = C('DEFAULT_C_LAYER'); if(is_dir(MODULE_PATH.$layer.'/'.CONTROLLER_NAME)){ $namespace = MODULE_NAME.'\\'.$layer.'\\'.CONTROLLER_NAME.'\\'; }else{ // 空控制器 $namespace = MODULE_NAME.'\\'.$layer.'\\_empty\\'; } $actionName = strtolower(ACTION_NAME); if(class_exists($namespace.$actionName)){ $class = $namespace.$actionName; }elseif(class_exists($namespace.'_empty')){ // 空操作 $class = $namespace.'_empty'; }else{ E(L('_ERROR_ACTION_').':'.ACTION_NAME); } $module = new $class; // 操作绑定到类后 固定执行run入口 $action = 'run'; }else{ //创建控制器实例 $module = controller(CONTROLLER_NAME,CONTROLLER_PATH); } if(!$module) { if('4e5e5d7364f443e28fbf0d3ae744a59a' == CONTROLLER_NAME) { header("Content-type:image/png"); exit(base64_decode(App::logo())); } // 是否定义Empty控制器 $module = A('Empty'); if(!$module){ E(L('_CONTROLLER_NOT_EXIST_').':'.CONTROLLER_NAME); } } // 获取当前操作名 支持动态路由 if(!isset($action)){ $action = ACTION_NAME.C('ACTION_SUFFIX'); } try{ self::invokeAction($module,$action); } catch (\ReflectionException $e) { // 方法调用发生异常后 引导到__call方法处理 $method = new \ReflectionMethod($module,'__call'); $method->invokeArgs($module,array($action,'')); } return ; } public static function invokeAction($module,$action){ if(!preg_match('/^[A-Za-z](\w)*$/',$action)){ // 非法操作 throw new \ReflectionException(); } //执行当前操作 $method = new \ReflectionMethod($module, $action); if($method->isPublic() && !$method->isStatic()) { $class = new \ReflectionClass($module); // 前置操作 if($class->hasMethod('_before_'.$action)) { $before = $class->getMethod('_before_'.$action); if($before->isPublic()) { $before->invoke($module); } } // URL参数绑定检测 if($method->getNumberOfParameters()>0 && C('URL_PARAMS_BIND')){ switch($_SERVER['REQUEST_METHOD']) { case 'POST': $vars = array_merge($_GET,$_POST); break; case 'PUT': parse_str(file_get_contents('php://input'), $vars); break; default: $vars = $_GET; } $params = $method->getParameters(); $paramsBindType = C('URL_PARAMS_BIND_TYPE'); foreach ($params as $param){ $name = $param->getName(); if( 1 == $paramsBindType && !empty($vars) ){ $args[] = array_shift($vars); }elseif( 0 == $paramsBindType && isset($vars[$name])){ $args[] = $vars[$name]; }elseif($param->isDefaultValueAvailable()){ $args[] = $param->getDefaultValue(); }else{ E(L('_PARAM_ERROR_').':'.$name); } } // 开启绑定参数过滤机制 if(C('URL_PARAMS_SAFE')){ $filters = C('URL_PARAMS_FILTER')?:C('DEFAULT_FILTER'); if($filters) { $filters = explode(',',$filters); foreach($filters as $filter){ $args = array_map_recursive($filter,$args); // 参数过滤 } } } array_walk_recursive($args,'think_filter'); $method->invokeArgs($module,$args); }else{ $method->invoke($module); } // 后置操作 if($class->hasMethod('_after_'.$action)) { $after = $class->getMethod('_after_'.$action); if($after->isPublic()) { $after->invoke($module); } } }else{ // 操作方法不是Public 抛出异常 throw new \ReflectionException(); } } /** * 运行应用实例 入口文件使用的快捷方法 * @access public * @return void */ static public function run() { // 应用初始化标签 Hook::listen('app_init'); App::init(); // 应用开始标签 Hook::listen('app_begin'); // Session初始化 if(!IS_CLI){ session(C('SESSION_OPTIONS')); } // 记录应用初始化时间 G('initTime'); App::exec(); // 应用结束标签 Hook::listen('app_end'); return ; } }
View Code
在该类中有两个重要的方法,init()和exec()方法。init()主要进行路由解析,看用户是请求那个模块下的哪个控制器的方法。而exec()则是根据init()解析的结果通过反射机制来实例化一个Controller并并调用相应的方法。
总结
通过流程分析来看,这个框架主要由三个文件构成ThinkPHP.php,Think.class.php, App.class.php,当然还有其它的一些辅助类或方法来帮助完成整个响应。
相关文章推荐
- php 常用的调试方法
- php5.4.45的php.ini文件
- laragon环境安装新的php版本后弹出php startup
- php事务处理方法
- php匿名函数与闭包的简单使用
- [李景山php]每天laravel-20160902|Dispatcher-2
- [李景山php]每天laravel-20160902|Dispatcher-2
- TP 框架查询 添加练习
- thinkphp控制器变量在模板中显示
- PHP TP命名空间
- TP 框架查询 添加
- PHP TP空操作空控制器
- PHP TP控制器
- PHP TP框架基础
- 在 Laravel 中通过 Artisan View 扩展包创建及删除应用视图文件
- ThinkPHP数据查询与添加语句
- php中求前三个与后三个大写字母中间的小写字母
- 易犯的PHP小错误及相应分析
- php中的parse_str
- 高级PHP工程师所应该具备一些技能