当前位置: 首页 > 后端技术 > PHP

分析ThinkPHP5框架从入口到输出界面的加载过程

时间:2023-03-29 18:05:39 PHP

InstallingThinkPHP的安装方法,我安装的版本是5.0.24试运行下载安装后,如果工程是工程根目录下的下载目录你本地服务器的目录,可以直接在浏览器中输入地址http://localhost/thinkphp5/public/,就可以进入ThinkPHP5默认的欢迎页面,如下图,说明ThinkPHP5已经安装成功。除了上述方法中的地址操作,我们还可以通过Apache或者Nginx配置虚拟主机来实现项目访问。有兴趣的可以上网查看具体教程,然后配置虚拟主机进行访问。现在进入正题,我们一步步分析ThinkPHP5的执行过程……入口文件(publicindex.php)打开public\index.php文件后,我们可以看到入口文件的原代码是如下//[应用入口文件]//定义应用目录define('APP_PATH',__DIR__.'/../application/');//加载框架启动文件require__DIR__.'/../thinkphp/start.php';入口文件代码很简单,就两行代码,函数是define('APP_PATH',__DIR__.'/../application/');定义常量APP_PATHrequire__DIR__。应用程序目录的'/../thinkphp/start.php';加载除上述之外的框架引导文件除了这两个函数外,我们还可以在入口文件中定义自己的常量,例如添加一行代码define('PUBLIC_PATH',__DIR__.'/../public');定义public目录的常量和一些presets处理和加载框架引导文件(thinkphpstart.php)同理,进入thinkphp\start.php文件后,我们可以知道代码没有太多namespacethink;//ThinkPHP引导文件//1.加载基本文件require__DIR__.'/base.php';//2.执行应用App::run()->send();从这短短的两行代码中,我们可以看出左右有两个require__DIR__。'/base.php';加载基础文件App::run()->send();执行应用程序的以下两个主要点,并将详细介绍这两个左右做了什么。载入基础文件(thinkphpbase.php)我们继续打开thinkphp\base.php文件,发现这个文件不再像前两个文件,只有两行代码...define('THINK_VERSION','5.0.24');define('THINK_START_TIME',microtime(true));define('THINK_START_MEM',memory_get_usage());define('EXT','.php');define('DS',DIRECTORY_SEPARATOR);define('THINK_PATH')ordefine('THINK_PATH',__DIR__.DS);define('LIB_PATH',THINK_PATH.'library'.DS);define('CORE_PATH',LIB_PATH.'think'.DS);define('TRAIT_PATH',LIB_PATH.'traits'.DS);defined('APP_PATH')ordefine('APP_PATH',dirname($_SERVER['SCRIPT_FILENAME']).DS);defined('ROOT_PATH')或define('ROOT_PATH',dirname(realpath(APP_PATH)).DS);defined('EXTEND_PATH')或define('EXTEND_PATH',ROOT_PATH.'extend'.DS);defined('VENDOR_PATH')或define('VENDOR_PATH',ROOT_PATH.'vendor'.DS);defined('RUNTIME_PATH')或define('RUNTIME_PATH',ROOT_PATH.'runtime'.DS);defined('LOG_PATH')或define('LOG_PATH',RUNTIME_PATH.'log'.DS);defined('CACHE_PATH')或define('CACHE_PATH',RUNTIME_PATH.'cache'.DS);defined('TEMP_PATH')或define('TEMP_PATH',RUNTIME_PATH.'temp'.DS);defined('CONF_PATH')或define('CONF_PATH',APP_PATH);//配置文件目录defined('CONF_EXT')ordefine('CONF_EXT',EXT);//配置文件后缀defined('ENV_PREFIX')ordefine('ENV_PREFIX','PHP_');//环境变量配置前缀//环境常量define('IS_CLI',PHP_SAPI=='cli'?true:false);define('IS_WIN',strpos(PHP_OS,'WIN')!==false);//加载Loader类需要CORE_PATH。'Loader.php';//加载环境变量配置文件if(is_file(ROOT_PATH.'.env')){$env=parse_ini_file(ROOT_PATH.'.env',true);foreach($envas$key=>$val){$name=ENV_PREFIX.strtoupper($键);if(is_array($val)){foreach($valas$k=>$v){$item=$name.'_'。strtoupper($k);putenv("$item=$v");}}else{putenv("$name=$val");}}}//注册自动加载\think\Loader::register();//注册错误和异常处理机制\think\Error::register();//加载约定配置文件\think\Config::set(includeTHINK_PATH.'convention'.EXT);仔细一看,发现虽然代码有60多行,但是代码的作用是显而易见的。主要作用有以下六点。使用define('','')函数定义了很多系统常量,加上两个环境常量导入加载器类(thinkphplibrarythinkloader.php),供后续加载环境变量配置文件(环境变量配置文件名为.php)使用。env,这个文件不一定是真实存在的实际开发过程中,根据需要添加)调用\think\Loader::register()注册自动加载机制注册系统自动加载Composer自动加载支持注册命名空间定义加载类库映射文件,存在于运行时缓存目录类图。php自动加载extend目录调用\think\Error::register()注册异常和错误处理机制加载约定配置文件(thinkphpconvention.php)执行应用程序(thinkphplibrarythinkApp.php)下的run方法为了方便,虽然这个run方法的代码有点长,不过我还是选择贴出整个方法,不要打我/***Executeapplication*@accesspublic*@paramRequest$request请求对象*@returnResponse*@throws异常*/publicstaticfunctionrun(Request$request=null){$request=is_null($request)?请求::实例():$请求;尝试{$config=self::initCommon();//模块/控制器绑定if(defined('BIND_MODULE')){BIND_MODULE&&Route::bind(BIND_MODULE);}elseif($config['auto_bind_module']){//条目自动绑定$name=pathinfo($request->baseFile(),PATHINFO_FILENAME);如果($name&&'index'!=$name&&is_dir(APP_PATH.$name)){Route::bind($name);}}$要求uest->filter($config['default_filter']);//默认语言Lang::range($config['default_lang']);//启用多语言机制来检测当前语言$config['lang_switch_on']&&Lang::detect();$request->langset(Lang::range());//加载系统语言包Lang::load([THINK_PATH.'lang'.DS.$request->langset().EXT,APP_PATH.'lang'.DS.$request->langset().EXT,]);//监听app_dispatchHook::listen('app_dispatch',self::$dispatch);//获取应用调度信息$dispatch=self::$dispatch;//URL路由检查是否没有设置调度信息if(empty($dispatch)){$dispatch=self::routeCheck($request,$config);}//记录当前调度信息$request->dispatch($dispatch);//记录路由和请求信息if(self::$debug){Log::r??ecord('[ROUTE]'.var_export($dispatch,true),'info');日志::record('[HEADER]'.var_export($request->header(),true),'info');Log::r??ecord('[PARAM]'.var_export($request->param(),true),'info');}//监听app_beginHook::listen('app_begin',$dispatch);//请求缓存检查$request->cache($config['request_cache'],$config['request_cache_expire'],$config['request_cache_except']);$data=self::exec($dispatch,$config);}catch(HttpResponseException$exception){$data=$exception->getResponse();}//清除类Loader::clearInstance()的实例;//向客户端输出数据if($datainstanceofResponse){$response=$data;}elseif(!is_null($data)){//默认自动识别响应输出类型$type=$request->isAjax()?Config::get('default_ajax_return'):Config::get('default_return_type');$response=Response::create($data,$type);}else{$response=Response::create();}//监听app_endHook::listen('app_end',$response);返回$响应se;}这大约90行代码,它到底做了什么?结合评论分析,主要有以下几个步骤。第一步:处理变量$request,保证它是合法有用的,不为null。()调用当前controller中的initCommon()方法,负责初始化应用,并返回配置信息Loader::addNamespace(self::$namespace,APP_PATH);注册命名空间self::init()调用init()方法初始化应用,加载各种配置文件,加载行为扩展文件,加载公共文件,加载语言包,应用调试模式相关处理,加载附加文件,加载通过配置项extra_file_list的值关联文件date_default_timezone_set($config['default_timezone']);设置系统时区调用Hook::listen('app_init');监听app_init标签的行为第三步:判断是绑定模块还是控制器第四步:系统语言设置和加载第五步:self::routeCheck($request,$config)加载当前的routeCheck()方法controllerforroutedetection首先进行路由地址配置检测,先读取缓存的路由,没有路由配置则导入路由文件配置,直接解析module/controller/operation返回module模块信息(模块名,controller名,operation方法名)Step6:debug模式下,log记录路由和请求信息Step7:Self::exec($dispatch,$config)调用controllerexec()方法根据用户请求的类型执行调用分配流通加工。这是模块模块类型。调用self::module()执行模块,进行模块部署和初始化,获取和设置当前控制器名称和操作名称。第八步:清除类的实例化,将相应格式的数据输出到客户端,即用户看到的输出界面。小结本文大致分析了ThinkPHP5的基本执行流程。我不会弥补,它太瘦了;但如果说错了,请指出,我一定会改正的??,就这么直白,如果觉得对你有帮助,请点赞离开。感激的!