> PHP 프레임워크 > ThinkPHP > 입력부터 출력 인터페이스까지 TP5 프레임워크의 로딩 프로세스를 분석합니다.

입력부터 출력 인터페이스까지 TP5 프레임워크의 로딩 프로세스를 분석합니다.

藏色散人
풀어 주다: 2021-09-16 15:12:28
앞으로
2848명이 탐색했습니다.

thinkphp 프레임워크 튜토리얼 칼럼에서는 ThinkPHP5 프레임워크의 로딩 과정을 입구부터 출력 인터페이스까지 소개하고 분석하겠습니다. 도움이 필요한 친구들에게 도움이 되길 바랍니다!

ThinkPHP 설치

설치 방법에 대해서는 자세히 설명하지 않겠습니다. 공식 문서인 ThinkPHP 설치는 매우 포괄적입니다. Composer, Git을 사용하거나 ThinkPHP 공식 홈페이지에서 직접 zip 패키지를 다운로드할 수 있습니다. 제가 설치한 버전은 5.0.24

Test run

다운로드 및 설치 후 프로젝트 다운로드 디렉토리가 프로젝트 루트 디렉토리에 있다면 로컬 서버인 경우 브라우저 http://localhost/thinkphp5/public/에 주소를 직접 입력할 수 있습니다. 아래 그림과 같이 ThinkPHP5의 기본 시작 페이지에 입력할 수 있습니다. ThinkPHP5가 성공적으로 설치되었습니다http://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()

      🎜🎜위의 주소 연산 방법 외에도 Apache 또는 Nginx를 통해 가상 호스트를 구성하여 액세스할 수도 있습니다. 관심 있는 사람들은 온라인으로 특정 튜토리얼을 보고 액세스할 가상 호스트를 구성할 수 있습니다. 🎜🎜본론으로 ThinkPHP5의 실행 과정을 단계별로 분석해보겠습니다...🎜🎜입력 파일(publicindex.php)🎜🎜publicindex.php 파일을 열면, 항목 파일의 원본 코드 다음 🎜rrreee🎜 항목 파일 코드는 매우 간결합니다. 단 두 줄의 코드로, 함수는 🎜
      1. define('APP_PATH', __DIR__ . '/.. /application/'); 애플리케이션 디렉토리의 상수 APP_PATH를 정의합니다.
      2. require __DIR__ '/../thinkphp/start.php';프레임워크를 로드합니다. 부팅 파일
      🎜위의 두 가지 기능 외에도 항목 파일에 자체 상수를 정의할 수도 있습니다. 예를 들어 define('PUBLIC_PATH) 코드 줄을 추가합니다. ', __DIR__ .'/../public'); 공용 디렉토리의 상수와 일부 전처리 등을 정의합니다. 🎜🎜프레임워크 부팅 파일(thinkphpstart.php)을 로드합니다. 🎜🎜마찬가지로 thinkphpstart.php 파일을 보면 코드가 많지 않다는 것을 알 수 있습니다 🎜rrreee 🎜이 짧은 두 줄의 코드에서 왼쪽과 오른쪽에 두 개의 주요 🎜
      1. require __DIR__ . '/base.php';기본 파일 로드
      2. App::run()->send();응용 프로그램 실행
      🎜다음 두 가지 주요 사항을 자세히 소개하겠습니다. What🎜🎜기본 파일(thinkphpbase.php) 로드🎜🎜계속해서 thinkphpbase.php 파일을 엽니다. 그리고 마침내 이 파일에는 이전 두 파일처럼 코드가 두 줄밖에 없다는 것을 알게 되었습니다...🎜rrreee 🎜주의깊게 살펴보면 코드가 60줄이 넘지만 코드의 기능이 분명하다는 것을 알았습니다. 🎜
      1. define('', '') 사용이 함수는 많은 시스템 상수와 두 개의 환경 상수를 정의합니다.
      2. 로더 클래스 소개( thinkphplibrarythinkloader.php) 이후 사용을 위해
      3. 환경 변수 구성 파일(.env라는 이름의 환경 변수 구성 파일 로드, 이 파일은 반드시 존재할 필요는 없으며 실제 실행 중에 필요에 따라 추가됩니다. 개발 과정)
      4. 🎜Call thinkLoader::register()자동 로딩 메커니즘 등록 🎜
        • 시스템 자동 로딩 등록
        • Composer 자동 로딩 지원
        • 네임스페이스 정의 등록
        • 런타임 캐시 디렉토리 classmap에 존재하는 클래스 라이브러리 매핑 파일 로드 .php
        • extend 목차 자동 로드
      5. thinkError::register( ) 예외 및 오류 처리 메커니즘을 등록합니다.
      6. 규칙 구성 파일 로드(thinkphpconvention.php)
      🎜애플리케이션(thinkphplibrarythinkApp.php)에서 실행 메소드를 실행합니다. 🎜🎜편의상 이 실행 메소드의 코드는 조금 길지만 그래도 전체 메소드를 게시하기로 했습니다. 🎜rrreee🎜분석에 따르면 이 약 90줄의 코드는 정확히 무엇을 하는 것인가요? 댓글에는 주로 다음과 같은 기능이 있습니다🎜
      • 첫 번째 단계: 변수 $request 처리, 유효하고 유용하며 null이 아님을 보장
      • 🎜 2단계: self::initCommon() 애플리케이션 초기화 및 구성 정보 반환을 담당하는 현재 컨트롤러에서 initCommon() 메서드를 호출합니다. 🎜
        • 로더: :addNamespace(self::$namespace, APP_PATH);네임스페이스 등록
        • 🎜self::init() code>초기화하려면 이 클래스의 init() 메서드를 호출하세요. 애플리케이션🎜<ul> <li>다양한 구성 파일 로드</li> <li>동작 확장 파일 로드</li> <li>공용 파일 로드</li> <li>언어 팩 로드</li> </ul>
        • 디버그 모드 관련 처리 적용
        • 구성 항목 extra_file_list를 통해 추가 파일 로드 관련 파일 로드extra_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']);시스템 시간대 설정
      • Hook::listen('app_init');을 호출하여 듣기 app_init 라벨 동작

      3단계: 모듈 또는 컨트롤러를 바인딩할지 결정

      4단계: 시스템 언어 설정 및 로딩

🎜5단계: self::routeCheck($request, $config) code>경로 감지를 위해 현재 컨트롤러의 RouteCheck() 메서드 로드🎜🎜🎜먼저 라우팅 주소 구성 감지를 수행하고, 먼저 캐시 경로를 읽고, 존재하지 않으면 라우팅 파일 구성을 가져옵니다.🎜🎜라우팅 구성 없음, 직접 모듈/컨트롤러/작업 분석🎜🎜모듈 모듈 정보(모듈 이름, 컨트롤러 이름 및 작업 방법 이름) 반환🎜🎜🎜🎜6단계: 디버그 모드를 켜서 라우팅 및 요청 정보 로그를 기록합니다🎜🎜🎜7단계: <code>self::exec($dispatch, $config)컨트롤러에서 exec() 메소드를 호출하여 호출 분배🎜🎜🎜사용자 요청 유형에 따른 분배 처리를 실행합니다. 모듈 모듈 유형은 다음과 같습니다. 🎜🎜callself::module()모듈 실행, 모듈 배포 및 초기화, 현재 컨트롤러 이름 및 작업 이름 획득 및 설정🎜🎜🎜🎜8단계: 클래스 인스턴스화 지우기 및 해당 형식으로 데이터를 출력합니다. 클라이언트, 즉 사용자가 보는 출력 인터페이스로 갑니다🎜🎜🎜Summary🎜🎜이 글에서는 ThinkPHP5의 기본 실행 과정을 대략적으로 분석해 놓았습니다. 제가 그것을 보상해드릴 수는 없기 때문에 말씀드릴 필요는 없습니다. 하지만 틀린 부분이 있으면 지적해 주시면 바로 수정해 드리겠습니다. 그런데 도움이 되셨다면 좋아요를 눌러주시고 떠나주세요. 🎜🎜

위 내용은 입력부터 출력 인터페이스까지 TP5 프레임워크의 로딩 프로세스를 분석합니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:segmentfault.com
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿