您好,欢迎来到码863代码分享网! 请[登录] / [注册]

thinkphp6执行流程

编辑

项目目录相对为tp6        4.5执行controller

请求被统一转发到入口文件(入口文件地址为 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构造方法

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,会触发该魔术方法

get($name);
}

get方法从app应用容器中获取http对象实例

has($abstract)) {
        return $this->make($abstract);
    }
 
    throw new ClassNotFoundException('class not exists: ' . $abstract, $abstract);
}


3.2 通过app应用容器中的make方法进行类的实例,以及执行instances方法将实例化的http类绑定到容器数组对象中


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方法,应用程序的执行开始

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')

// 分发请求到路由

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方法


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    这里重要 执行了controller   $this->app->invokeReflectMethod($instance, $reflect, $vars);

(此处调用的exec的类方法所在的文件,由调用者确定, 可能为url, callback, 或者controller, exec 类方法的文件地址为 tp6/vendor/topthink/framework/src/think/route/dispatch/Callback.php|Controller.php')

在exec方法中最终返回了data数据    

    public function exec()
    {
        try {
            // 实例化控制器
            $instance = $this->controller($this->controller);
        } catch (ClassNotFoundException $e) {
            throw new HttpException(404, 'controller not exists:' . $e->getClass());
        }

        // 注册控制器中间件
        $this->registerControllerMiddleware($instance);

        return $this->app->middleware->pipeline('controller')
            ->send($this->request)
            ->then(function () use ($instance) {
                // 获取当前操作名
                $suffix = $this->rule->config('action_suffix');
                $action = $this->actionName . $suffix;

                if (is_callable([$instance, $action])) {
                    $vars = $this->request->param();
                    try {
                        $reflect = new ReflectionMethod($instance, $action);
                        // 严格获取当前操作方法名
                        $actionName = $reflect->getName();
                        if ($suffix) {
                            $actionName = substr($actionName, 0, -strlen($suffix));
                        }

                        $this->request->setAction($actionName);
                    } catch (ReflectionException $e) {
                        $reflect = new ReflectionMethod($instance, '__call');
                        $vars    = [$action, $vars];
                        $this->request->setAction($action);
                    }
                } else {
                    // 操作不存在
                    throw new HttpException(404, 'method not exists:' . get_class($instance) . '->' . $action . '()');
                }

                $data = $this->app->invokeReflectMethod($instance, $reflect, $vars);

                return $this->autoResponse($data);
            });
    }

 

4.6 然后调用了autoResponse方法,并传递4.5返回的data数据

(autoResponse 类方法的文件地址为 tp6/vendor/topthink/framework/src/think/route/Dispatch.php')

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')

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();

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方法

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容器类, 所有类的实例通过容器类进行统一管理,容器类为单例模式全局唯一;


CopyRight 2002~2023 精通2100网 联系邮箱:qqtxt@163.com
版权所有:精通2100网 湘ICP备2023018646号-1
MYSQl共执行 3 个查询,用时 0.0019228458404541 秒,PHP脚本用时 0.004466 秒,占用内存 0.625 MB,Gzip 已启用