Maison >cadre php >PensezPHP >Analyser le processus de chargement du framework TP5 depuis l'entrée jusqu'à l'interface de sortie

Analyser le processus de chargement du framework TP5 depuis l'entrée jusqu'à l'interface de sortie

藏色散人
藏色散人avant
2021-09-16 15:12:282851parcourir

framework thinkphpLa colonne du didacticiel présentera et analysera le processus de chargement du framework ThinkPHP5 depuis l'entrée jusqu'à l'interface de sortie. J'espère que cela sera utile aux amis dans le besoin !

Installation de ThinkPHP

Je n'entrerai pas dans les détails sur la façon de l'installer Le document officiel - Installation de ThinkPHP est très complet. Vous pouvez utiliser Composer, Git ou directement Accédez au site officiel de ThinkPHP pour télécharger le package zip. La version que j'ai installée est la 5.0.24

Test run

Après le téléchargement et l'installation, si le répertoire de téléchargement du projet se trouve dans le répertoire racine du projet. votre serveur local, vous pouvez saisir directement l'adresse dans le navigateur http://localhost/thinkphp5/public/, vous pouvez accéder à la page d'accueil par défaut de ThinkPHP5, comme le montre la figure ci-dessous, ce qui signifie que ThinkPHP5 a été installé avec succèshttp://localhost/thinkphp5/public/,就可以进入到ThinkPHP5的默认欢迎页,如下图所示,这就说明ThinkPHP5已经安装成功

除了上面的这个方式的地址运行,我们也可以通过Apache或者Nginx配置虚拟主机实现项目的访问,有兴趣的可以网上查看具体教程,然后配置虚拟主机进行访问。

下面进入正题,我们来逐步分析ThinkPHP5的执行流程……

入口文件(publicindex.php)

打开publicindex.php文件后,我们可以看到,入口文件原始代码如下

// [ 应用入口文件 ]

// 定义应用目录
define('APP_PATH', __DIR__ . '/../application/');
// 加载框架引导文件
require __DIR__ . '/../thinkphp/start.php';

入口文件代码很简洁,就两行代码,作用分别为

  1. define('APP_PATH', __DIR__ . '/../application/');定义应用目录的常量APP_PATH
  2. require __DIR__ . '/../thinkphp/start.php';加载框架引导文件

除了上面的这两个作用外,我们还可以额外在入口文件中,定义我们自己的常量,例如添加一行代码define('PUBLIC_PATH', __DIR__ .'/../public');定义public目录的常量以及一些预处理等

加载框架引导文件(thinkphpstart.php)

同样的,进入thinkphpstart.php文件后,我们可以知道,代码并不多

namespace think;

// ThinkPHP 引导文件
// 1. 加载基础文件
require __DIR__ . '/base.php';

// 2. 执行应用
App::run()->send();

从这简短的两行代码,我们可以看到,主要左右有两个

  1. require __DIR__ . '/base.php';加载基础文件
  2. App::run()->send();执行应用

下面两个大点,将具体介绍这两个左右都做了什么

加载基础文件(thinkphpbase.php)

我们继续打开thinkphpbase.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);
defined('THINK_PATH') or define('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') or define('APP_PATH', dirname($_SERVER['SCRIPT_FILENAME']) . DS);
defined('ROOT_PATH') or define('ROOT_PATH', dirname(realpath(APP_PATH)) . DS);
defined('EXTEND_PATH') or define('EXTEND_PATH', ROOT_PATH . 'extend' . DS);
defined('VENDOR_PATH') or define('VENDOR_PATH', ROOT_PATH . 'vendor' . DS);
defined('RUNTIME_PATH') or define('RUNTIME_PATH', ROOT_PATH . 'runtime' . DS);
defined('LOG_PATH') or define('LOG_PATH', RUNTIME_PATH . 'log' . DS);
defined('CACHE_PATH') or define('CACHE_PATH', RUNTIME_PATH . 'cache' . DS);
defined('TEMP_PATH') or define('TEMP_PATH', RUNTIME_PATH . 'temp' . DS);
defined('CONF_PATH') or define('CONF_PATH', APP_PATH); // 配置文件目录
defined('CONF_EXT') or define('CONF_EXT', EXT); // 配置文件后缀
defined('ENV_PREFIX') or define('ENV_PREFIX', 'PHP_'); // 环境变量的配置前缀

// 环境常量
define('IS_CLI', PHP_SAPI == 'cli' ? true : false);
define('IS_WIN', strpos(PHP_OS, 'WIN') !== false);

// 载入Loader类
require CORE_PATH . 'Loader.php';

// 加载环境变量配置文件
if (is_file(ROOT_PATH . '.env')) {
    $env = parse_ini_file(ROOT_PATH . '.env', true);

    foreach ($env as $key => $val) {
        $name = ENV_PREFIX . strtoupper($key);

        if (is_array($val)) {
            foreach ($val as $k => $v) {
                $item = $name . '_' . strtoupper($k);
                putenv("$item=$v");
            }
        } else {
            putenv("$name=$val");
        }
    }
}

// 注册自动加载
\think\Loader::register();

// 注册错误和异常处理机制
\think\Error::register();

// 加载惯例配置文件
\think\Config::set(include THINK_PATH . 'convention' . EXT);

仔细一看,发现代码虽然有六十多行,但是,代码的作用却显而易见,作用主要有以下六点

  1. 使用define('', '')函数定义了很多个系统常量,外加两个环境常量
  2. 引入loader类(thinkphplibrarythinkloader.php),供后续使用
  3. 加载环境变量配置文件(环境变量配置文件名为.env,这个文件不一定存在,都是在实际开发过程中根据需要加上去的)
  4. 调用thinkLoader::register()注册自动加载机制

    • 注册系统自动加载
    • Composer自动加载支持
    • 注册命名空间定义
    • 加载类库映射文件,存在于runtime缓存目录下classmap.php
    • 自动加载extend目录
  5. 调用thinkError::register()注册异常和错误处理机制
  6. 加载惯例配置文件(thinkphpconvention.php)

执行应用(thinkphplibrarythinkApp.php)下的run方法

为了方便,这个run方法的代码虽然有点长,但是我还是选择把整个方法贴出来,别打我哈

/**
 * 执行应用程序
 * @access public
 * @param  Request $request 请求对象
 * @return Response
 * @throws Exception
 */
public static function run(Request $request = null)
{
    $request = is_null($request) ? Request::instance() : $request;

    try {
        $config = self::initCommon();

        // 模块/控制器绑定
        if (defined('BIND_MODULE')) {
            BIND_MODULE && Route::bind(BIND_MODULE);
        } 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']);

        // 默认语言
        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_dispatch
        Hook::listen('app_dispatch', self::$dispatch);
        // 获取应用调度信息
        $dispatch = self::$dispatch;

        // 未设置调度信息则进行 URL 路由检测
        if (empty($dispatch)) {
            $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);

        // 请求缓存检查
        $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 ($data instanceof Response) {
        $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_end
    Hook::listen('app_end', $response);

    return $response;
}

这大概90行的代码,具体做了什么呢,结合注释分析,主要有以下几步的功能

  • 第一步:处理变量$request,保证有效有用不为null
  • 第二步:self::initCommon()调用当前控制器中的initCommon()方法,负责初始化应用,并返回配置信息

    • Loader::addNamespace(self::$namespace, APP_PATH);注册命名空间
    • self::init()

      🎜🎜En plus de l'opération d'adresse dans la méthode ci-dessus, nous pouvons également configurer un hôte virtuel via Apache ou Nginx pour accéder au projet. Si vous êtes intéressé, vous pouvez consulter le didacticiel spécifique en ligne, puis configurer l'hôte virtuel pour l'accès. 🎜🎜Entrons dans le vif du sujet. Analysons le processus d'exécution de ThinkPHP5 étape par étape...🎜🎜Fichier d'entrée (publicindex.php)🎜🎜Après avoir ouvert le fichier publicindex.php, nous pouvons voir le code original du fichier d'entrée Le code du fichier d'entrée 🎜rrreee🎜 suivant est très concis, juste deux lignes de code, les fonctions sont 🎜
      1. define('APP_PATH', __DIR__ . '/.. /application/'); Définir la constante APP_PATH du répertoire de l'application
      2. require __DIR__ '/../thinkphp/start.php';Charger le framework. fichier de démarrage
      🎜En plus de ce qui précède En plus de ces deux fonctions, nous pouvons également définir nos propres constantes dans le fichier d'entrée, par exemple, ajouter une ligne de code define('PUBLIC_PATH ', __DIR__ .'/../public'); Définir les constantes du répertoire public et certains prétraitements, etc. 🎜🎜Charger le fichier de démarrage du framework (thinkphpstart.php) 🎜🎜De même, après avoir entré le thinkphpstart.php, on peut savoir qu'il n'y a pas beaucoup de code 🎜rrreee 🎜À partir de ces deux courtes lignes de code, on peut voir qu'il y a deux principales gauche et droite 🎜
      1. require __DIR__ '/base.php';Charger le fichier de base
      2. App::run()->send();Exécuter l'application
      🎜Les deux points majeurs suivants seront présentés en détail. Quoi🎜🎜Charger le fichier de base (thinkphpbase.php)🎜🎜Nous continuons à ouvrir le fichier thinkphpbase.php. et constate que ce fichier n'a finalement plus que deux lignes de code comme les deux fichiers précédents...🎜rrreee 🎜En regardant attentivement, j'ai trouvé que même si le code comporte plus de 60 lignes, la fonction du code est évidente. les fonctions sont les suivantes 🎜
      1. Utilisez define('', '')La fonction définit de nombreuses constantes système, plus deux constantes d'environnement
      2. Présentation de la classe de chargement ( thinkphplibrarythinkloader.php) pour une utilisation ultérieure
      3. Chargement du fichier de configuration des variables d'environnement (fichier de configuration des variables d'environnement Nommé .env, ce fichier n'existe pas forcément et est ajouté selon les besoins lors de l'exécution proprement dite. processus de développement)
      4. 🎜Appelez thinkLoader::register()Enregistrez le mécanisme de chargement automatique 🎜<ul> <li>Enregistrez le chargement automatique du système</li> <li> <code> Composer prise en charge du chargement automatique
      5. Enregistrer la définition de l'espace de noms
      6. Charger le fichier de mappage de la bibliothèque de classes, qui existe dans le répertoire de cache runtime classmap .php
      7. Charger automatiquement extend Table des matières
  • Appeler thinkError::register( ) pour enregistrer les exceptions et les mécanismes de gestion des erreurs
  • Charger le fichier de configuration de la convention (thinkphpconvention. php)
  • 🎜Exécuter la méthode run sous l'application (thinkphplibrarythinkApp.php) 🎜🎜Pour plus de commodité, bien que le code de cette méthode d'exécution soit un peu long, j'ai quand même choisi de publier l'intégralité de la méthode. Ne me frappez pas 🎜rrreee🎜Que font exactement ces 90 lignes de code d'après l'analyse ? de commentaires, il a principalement les fonctions suivantes🎜
    • La première étape : traiter la variable $request, Garanti valide et utile et non nulle
    • 🎜 Étape 2 : self::initCommon() Appelle la méthode initCommon() dans le contrôleur actuel, qui est responsable de l'initialisation de l'application et du renvoi des informations de configuration 🎜
      • Loader : :addNamespace(self::$namespace, APP_PATH);Enregistrer l'espace de noms
      • 🎜self::init() code>Appelez la méthode init() de cette classe pour initialiser l'application🎜<ul> <li>Charger divers fichiers de configuration</li> <li>Charger les fichiers d'extension de comportement</li> <li>Charger les fichiers publics</li> <li>Charger les modules linguistiques</li> </ul>
      • Appliquer le traitement lié au mode débogage
      • Charger des fichiers supplémentaires via l'élément de configuration extra_file_list Value to charger les fichiers associésextra_file_list的值去加载相关文件
      • date_default_timezone_set($config['default_timezone']);设置系统时区
      • 调用Hook::listen('app_init');监听app_init标签的行为
    • 第三步:判断是否进行模块或者控制器的绑定
    • 第四步:系统语言设置和加载
    • 第五步:self::routeCheck($request, $config)加载当前控制器的routeCheck()方法进行路由检测

      • 先进行路由地址配置检测,先读取缓存路由,不存在再导入路由文件配置
      • 无路由配置,直接解析模块/控制器/操作
      • 返回module模块信息(模块名、控制器名和操作方法名)
    • 第六步:开启调试模式下,记录路由和请求信息的日志
    • 第七步:self::exec($dispatch, $config)调用控制器中的exec()方法执行调用分发

      • 根据用户请求类型进行分发处理,这里是module模块类型
      • 调用self::module()
      • date_default_timezone_set($config['default_timezone']);Définir le fuseau horaire du système
    • Appelez Hook::listen('app_init'); pour écouter au comportement de l'étiquette app_init

    Étape 3 : Déterminer s'il faut lier des modules ou des contrôleurs

    Étape 4 : Paramétrage et chargement de la langue du système

🎜Étape 5 : self::routeCheck($request, $config) code>Chargez la méthode routeCheck() du contrôleur actuel pour la détection d'itinéraire🎜🎜🎜Effectuez d'abord la détection de la configuration de l'adresse de routage, lisez d'abord la route du cache, si elle n'existe pas, puis importez la configuration du fichier de routage🎜🎜Aucune configuration de routage, directement analyser le module/contrôleur/opération🎜🎜Renvoyer les informations du module (nom du module, nom du contrôleur et nom de la méthode de fonctionnement)🎜🎜🎜🎜Étape 6 : Activez le mode débogage pour enregistrer le journal de routage et demander des informations🎜🎜🎜Étape 7 : <code>self::exec($dispatch, $config)Appelez la méthode exec() dans le contrôleur pour exécuter le traitement de distribution des appels🎜🎜🎜selon le type de demande de l'utilisateur, voici le type de module du module 🎜🎜callself::module()Exécutez le module, déployez et initialisez le module, obtenez et définissez le nom du contrôleur actuel et le nom de l'opération🎜🎜🎜🎜Étape 8 : Effacez l'instanciation de la classe et données de sortie au format correspondant Accédez au client, c'est-à-dire l'interface de sortie vue par l'utilisateur🎜🎜🎜Résumé🎜🎜Cet article analyse grossièrement le processus d'exécution de base de ThinkPHP5. S'il y a quelque chose qui n'est pas en place, il y a. pas besoin de me le dire, car je ne compenserai pas cela. C'est tout simplement méchant, mais si c'est faux, signalez-le-le et je le corrigerai certainement. Au fait, si vous pensez que cela vous est utile, n'hésitez pas à liker et à partir, merci ! 🎜🎜

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer