02 08 2020

执行流程

// 执行应用并响应
Container::get('app')->run()->send();


thinkphp/library/think/App.php

/**
 * 执行应用程序
 * @access public
 * @return Response
 * @throws Exception
 */
public function run()
{
    try {
        ......
    
        $dispatch = $this->dispatch;
    
        if (empty($dispatch)) {
            // 路由检测
            $dispatch = $this->routeCheck()->init();
        }
    
        // 记录当前调度信息
        $this->request->dispatch($dispatch);
    
        ......
        
    } catch (HttpResponseException $exception) {
        ......
    }

    $this->middleware->add(function (Request $request, $next) use ($dispatch, $data) {
        return is_null($data) ? $dispatch->run() : $data;
    });

    ......
}


$dispatch 获取控制器和操作名,执行路由调度


thinkphp/library/think/route/Dispatch.php

/**
 * 执行路由调度
 * @access public
 * @return mixed
 */
public function run()
{
    ......

    $data = $this->exec();

    ......
}


exec() 通过反射实例化控制器和执行方法


thinkphp/library/think/route/dispatch/Module.php

public function exec()
{
    // 监听module_init
    $this->app['hook']->listen('module_init');

    try {
        // 实例化控制器
        $instance = $this->app->controller($this->controller,
            $this->rule->getConfig('url_controller_layer'),
            $this->rule->getConfig('controller_suffix'),
            $this->rule->getConfig('empty_controller'));
    } catch (ClassNotFoundException $e) {
        throw new HttpException(404, 'controller not exists:' . $e->getClass());
    }

    $this->app['middleware']->controller(function (Request $request, $next) use ($instance) {
        // 获取当前操作名
        $action = $this->actionName . $this->rule->getConfig('action_suffix');

        // 检查实例中是否可以执行方法
        if (is_callable([$instance, $action])) {
            // 执行操作方法
            $call = [$instance, $action];

            // 严格获取当前操作方法名
            $reflect    = new ReflectionMethod($instance, $action);
            $methodName = $reflect->getName();
            $suffix     = $this->rule->getConfig('action_suffix');
            $actionName = $suffix ? substr($methodName, 0, -strlen($suffix)) : $methodName;
            $this->request->setAction($actionName);

            // 自动获取请求变量
            $vars = $this->rule->getConfig('url_param_type')
            ? $this->request->route()
            : $this->request->param();
            $vars = array_merge($vars, $this->param);
        } elseif (is_callable([$instance, '_empty'])) {
            // 空操作
            $call    = [$instance, '_empty'];
            $vars    = [$this->actionName];
            $reflect = new ReflectionMethod($instance, '_empty');
        } else {
            // 操作不存在
            throw new HttpException(404, 'method not exists:' . get_class($instance) . '->' . $action . '()');
        }

        $this->app['hook']->listen('action_begin', $call);

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

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

    return $this->app['middleware']->dispatch($this->request, 'controller');
}


最终获得Response对象,调用send()方法输出数据


thinkphp/library/think/Response.php

/**
 * 发送数据到客户端
 * @access public
 * @return void
 * @throws \InvalidArgumentException
 */
public function send()
{
    // 监听response_send
    $this->app['hook']->listen('response_send', $this);

    // 处理输出数据
    $data = $this->getContent();

    // Trace调试注入
    if ('cli' != PHP_SAPI && $this->app['env']->get('app_trace', $this->app->config('app.app_trace'))) {
        $this->app['debug']->inject($this, $data);
    }

    if (200 == $this->code && $this->allowCache) {
        $cache = $this->app['request']->getCache();
        if ($cache) {
            $this->header['Cache-Control'] = 'max-age=' . $cache[1] . ',must-revalidate';
            $this->header['Last-Modified'] = gmdate('D, d M Y H:i:s') . ' GMT';
            $this->header['Expires']       = gmdate('D, d M Y H:i:s', $_SERVER['REQUEST_TIME'] + $cache[1]) . ' GMT';

            $this->app['cache']->tag($cache[2])->set($cache[0], [$data, $this->header], $cache[1]);
        }
    }

    if (!headers_sent() && !empty($this->header)) {
        // 发送状态码
        http_response_code($this->code);
        // 发送头部信息
        foreach ($this->header as $name => $val) {
            header($name . (!is_null($val) ? ':' . $val : ''));
        }
    }

    $this->sendData($data);

    if (function_exists('fastcgi_finish_request')) {
        // 提高页面响应
        fastcgi_finish_request();
    }

    // 监听response_end
    $this->app['hook']->listen('response_end', $this);

    // 清空当次请求有效的数据
    if (!($this instanceof RedirectResponse)) {
        $this->app['session']->flush();
    }
}