thinkphp6執行流程(一)


項目目錄相對為tp6
請求被統一轉發到入口文件(入口文件地址為 tp6/index.php)
1.入口文件引入了composer自動載入文件類庫
<php?
namespace think;

require __DIR__ . '/../vendor/autoload.php';

  

 

(文件地址為 tp6/vendor/autoload.php')

 

2.實例化 think\App 對象 賦值給$app
<?php

$app = new App();

  

 

(App類文件地址為 tp6/vendor/topthink/framework/src/think/App.php')
執行App類中的__construct構造方法
<?php
public function __construct(string $rootPath = '')
{
    // 框架類庫目錄
    $this->thinkPath   = dirname(__DIR__) . DIRECTORY_SEPARATOR;
    // 項目根目錄
    $this->rootPath    = $rootPath ? rtrim($rootPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR : $this->getDefaultRootPath();
    // 應用目錄
    $this->appPath     = $this->rootPath . 'app' . DIRECTORY_SEPARATOR;
    // 項目緩存目錄
    $this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATOR;
    // 加載服務provide容器
    if (is_file($this->appPath . 'provider.php')) {
        // 執行 Container\bind()方法 綁定類、閉包、實例、接口
        $this->bind(include $this->appPath . 'provider.php');
    }
    // 設置一個容器實例
    static::setInstance($this);
    // 綁定類的實例到容器
    $this->instance('app', $this);
    $this->instance('think\Container', $this);
}

  

其中在屬性$bind中已經有了一些框架類的別名與實現的映射數組

 

此時$app因為是繼承了Container類,所以$app實際也是一個容器

 

3.通過$app類調用http類(web管理類)

 

$http = $app->http;

  

 

3.0 引用http類的過程如下:
(http類文件地址為 tp6/vendor/topthink/framework/src/think/Http.php')
3.1 首先App中不存在http方法,但是在容器類中存在魔術方法__get,會觸發該魔術方法
<?php
public function __get($name)
{
    return $this->get($name);
}

  

get方法從app應用容器中獲取http對象實例
<php?
/**
* 獲取容器中的對象實例
* @access public
* @param string $abstract 類名或者標識
* @return object
*/
public function get($abstract)
{
    if ($this->has($abstract)) {
        return $this->make($abstract);
    }

    throw new ClassNotFoundException('class not exists: ' . $abstract, $abstract);
}

  

3.2 通過app應用容器中的make方法進行類的實例,以及執行instances方法將實例化的http類綁定到容器數組對象中
<?php
/**
    * 創建類的實例 已經存在則直接獲取
    * @access public
    * @param string $abstract    類名或者標識
    * @param array  $vars        變量
    * @param bool   $newInstance 是否每次創建新的實例
    * @return mixed
    */
public function make(string $abstract, array $vars = [], bool $newInstance = false)
{
    $abstract = $this->getAlias($abstract);

    if (isset($this->instances[$abstract]) && !$newInstance) {
        return $this->instances[$abstract];
    }

    if (isset($this->bind[$abstract]) && $this->bind[$abstract] instanceof Closure) {
        $object = $this->invokeFunction($this->bind[$abstract], $vars);
    } else {

        $object = $this->invokeClass($abstract, $vars);
    }

    if (!$newInstance) {
        $this->instances[$abstract] = $object;
    }

    return $object;
}

  

返回http對象實例到調用處 第3步開始的地方

 

4 http對象執行run方法,應用程序的執行開始
<?php
/**
* 執行應用程序
* @access public
* @param Request|null $request
* @return Response
*/
public function run(Request $request = null): Response
{
    //自動創建request對象
    $request = $request ?? $this->app->make('request', [], true);
    // 綁定request類的實例化對象到容器中
    $this->app->instance('request', $request);

    try {
        // 執行應用程序返回response類
        $response = $this->runWithRequest($request);
    } catch (Throwable $e) {
        $this->reportException($e);

        $response = $this->renderException($request, $e);
    }
    return $response;
}

  

4.1 run 方法中首先創建Request類,執行instances方法將實例化的Request類綁定到容器數組對象中,標識為request

 

然后進行路由調度,執行 app容器中runWithRequest方法
/**
    * 執行應用程序
    * @param Request $request
    * @return mixed
    */
protected function runWithRequest(Request $request)
{
    // 初始化app應用程序
    $this->initialize();

    // 加載全局中間件
    $this->loadMiddleware();

    // 監聽HttpRun
    $this->app->event->trigger(HttpRun::class);
    // 中間件調度
    return $this->app->middleware->pipeline()
        ->send($request)
        ->then(function ($request) {
            return $this->dispatchToRoute($request);
        });
}

  

4.2然后在在http類中runWithRequest方法中執行了dispatchToRoute 講請求分發到路由
 (dispatchToRoute 類方法的文件地址為 tp6/vendor/topthink/framework/src/think/Route.php')
// 分發請求到路由
<?php
protected function dispatchToRoute($request)
{
    // 是否啟用路由, 默認啟用路由
    $withRoute = $this->app->config->get('app.with_route', true) ? function () {
        $this->loadRoutes();
    } : null;
    // 執行路由調度
    return $this->app->route->dispatch($request, $withRoute);
}

  

4.3 在http類中dispatchToRoute 通過app容器獲取了route實例,並調用了route實例中的dispatch方法
<?php
/**
* 路由調度
* @param Request $request
* @param Closure|bool $withRoute
* @return Response
*/
public function dispatch(Request $request, $withRoute = true)
{
    $this->request = $request;
    $this->host    = $this->request->host(true);
    $this->init();

    if ($withRoute) {
        // 加載路由設置
        if ($withRoute instanceof Closure) {  
            $withRoute();
        }
        // 檢查路由
        $dispatch = $this->check();
    } else {
        // 如果沒有路由,則使用默認url解析
        $dispatch = $this->url($this->path());
    }
    // $dispatch 為think\route\dispatch\Controller 的實例化 中的初始化,提取控制名稱以及操作名稱
    // 1, 通過最終think\route\Rule::dispatch來確路由調度的最終執行動作
    
    $dispatch->init($this->app);
    return $this->app->middleware->pipeline('route')
        ->send($request)
        ->then(function () use ($dispatch) {
            // 執行動作方法
            return $dispatch->run();
        });
}
4.4 在route類中的dispatch中執行了run方法, 
(run 類方法的文件地址為 tp6/vendor/topthink/framework/src/think/route/Dispatch.php')
<?php
/** * 執行路由調度 * @access public * @return mixed */ public function run(): Response { if ($this->rule instanceof RuleItem && $this->request->method() == 'OPTIONS' && $this->rule->isAutoOptions()) { $rules = $this->rule->getRouter()->getRule($this->rule->getRule()); $allow = []; foreach ($rules as $item) { $allow[] = strtoupper($item->getMethod()); } return Response::create('', 'html', 204)->header(['Allow' => implode(', ', $allow)]); } // 此處調用的$this類,由調用者確定, 可能為url, callback, 或者controller // $data 為返回的response 類 $data = $this->exec(); return $this->autoResponse($data); }

  

4.5 run方法調用了exec 
(此處調用的exec的類方法所在的文件,由調用者確定, 可能為url, callback, 或者controller, exec 類方法的文件地址為 tp6/vendor/topthink/framework/src/think/route/dispatch/Callback.php|Controller.php')
在exec方法中最終返回了data數據

 

4.6 然后調用了autoResponse方法,並傳遞4.5返回的data數據
(autoResponse 類方法的文件地址為 tp6/vendor/topthink/framework/src/think/route/Dispatch.php')
<?php
protected function autoResponse($data): Response
{
    if ($data instanceof Response) {
        $response = $data;
    } elseif (!is_null($data)) {
        // 默認自動識別響應輸出類型
        $type     = $this->request->isJson() ? 'json' : 'html';
        $response = Response::create($data, $type);
    } else {
        $data = ob_get_clean();

        $content  = false === $data ? '' : $data;
        $status   = '' === $content && $this->request->isJson() ? 204 : 200;
        // 創建response類返回,使用html
        $response = Response::create($content, 'html', $status);
    }
    return $response;
}

  

4.7 autoResponse 方法中執行了 Response::create方法
最終方法返回了response對象;
(Response::create 類方法的文件地址為 tp6/vendor/topthink/framework/src/think/Response.php')

 

<?php
/**
    * 創建Response對象
    * @access public
    * @param  mixed  $data 輸出數據
    * @param  string $type 輸出類型
    * @param  int    $code 狀態碼
    * @return Response
    */
public static function create($data = '', string $type = 'html', int $code = 200): Response
{
    $class = false !== strpos($type, '\\') ? $type : '\\think\\response\\' . ucfirst(strtolower($type));

    return Container::getInstance()->invokeClass($class, [$data, $code]);
}

  

4.8 最終返回了 response Html類的對象實例

 

5 執行run方法
$response = $http->run();

  

 

6 response 執行send輸出數據的操作;
(Html 類文件所在地址為 tp6/vendor/topthink/framework/src/think/response/Html.php )

 

6.1 執行send方法
(send方法 類文件所在地址為 tp6/vendor/topthink/framework/src/think/Response.php )
$response->send();
<?php
/**
    * 發送數據到客戶端
    * @access public
    * @return void
    * @throws \InvalidArgumentException
    */
public function send(): void
{
    // 處理輸出數據
    $data = $this->getContent();
    if (!headers_sent() && !empty($this->header)) {
        // 發送狀態碼
        http_response_code($this->code);
        // 發送頭部信息
        foreach ($this->header as $name => $val) {
            header($name . (!is_null($val) ? ':' . $val : ''));
        }
    }
    if ($this->cookie) {
        $this->cookie->save();
    }

    $this->sendData($data);

    if (function_exists('fastcgi_finish_request')) {
        // 提高頁面響應
        fastcgi_finish_request();
    }
}

  

 

6.1 在send方法中最終執行了 sendData 方法
(sendData方法 類文件所在地址為 tp6/vendor/topthink/framework/src/think/Response.php )
<?php
/**
* 輸出數據
* @access protected
* @param string $data 要處理的數據
* @return void
*/
protected function sendData(string $data): void
{
    echo $data;
}

  

7 執行 http對象中的end方法
<?php
$http->end($response);

  

 

(http類文件地址為 tp6/vendor/topthink/framework/src/think/Http.php')
<?php
/**
* HttpEnd
* @param Response $response
* @return void
*/
public function end(Response $response): void
{
$this->app->event->trigger(HttpEnd::class, $response);

//執行中間件
$this->app->middleware->end($response);

// 寫入日志
$this->app->log->save();
}

  

8整個程序結束
 
應用類App繼承了Container容器類, 所有類的實例通過容器類進行統一管理,容器類為單例模式全局唯一;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM