think-swoole 3.0入门教程(thinkphp 6.0)架构分析 1

栏目: PHP · 发布时间: 5年前

内容简介:ThinkPHP即将迎来最新版本6.0,针对目前越来越流行Swoole,thinkphp也推出了最新的扩展think-swoole 3.0tp-swoole3.0不同于2.0版本,采用了全新的架构。(如下图目录结构)

前言

ThinkPHP即将迎来最新版本6.0,针对目前越来越流行Swoole,thinkphp也推出了最新的扩展think-swoole 3.0

架构分析

tp-swoole3.0不同于2.0版本,采用了全新的架构。(如下图目录结构)

think-swoole 3.0入门教程(thinkphp 6.0)架构分析 1

tp主要针对的是非常驻内存方式运行,为了兼容swoole,虽然做了很多优化,但是仍然无法像swoft,sd等一些针对swoole开发的框架一样。这里所说的不同,不是指tp不好,而是因为两种模式都要兼容,不得不做出一些取舍。

请求

分析该框架的运行机制,其实主要分析swoole的OnRequest函数即可,路由分发,数据处理等都是在函数处进行处理的。

Swoole.php

public function onRequest($req, $res)
    {
        $this->app->event->trigger('swoole.request');

        $this->resetOnRequest();

        /** @var Sandbox $sandbox */
        $sandbox = $this->app->make(Sandbox::class);
        $request = $this->prepareRequest($req);

        try {
            $sandbox->setRequest($request);

            $sandbox->init();

            $response = $sandbox->run($request);

            $this->sendResponse($sandbox, $response, $res);
        } catch (Throwable $e) {
            try {
                $exceptionResponse = $this->app
                    ->make(Handle::class)
                    ->render($request, $e);

                $this->sendResponse($sandbox, $exceptionResponse, $res);
            } catch (Throwable $e) {
                $this->logServerError($e);
            }
        } finally {
            $sandbox->clear();
        }
    }

函数初始处,触发了一个request事件,这里方便用户自定义处理请求,进行一些定制化处理

$this->app->event->trigger('swoole.request');

重置请求,当是Websocket的时候,重置该类,具体为什么,下次我们分析Websocket的时候在进行解释

$this->resetOnRequest();

protected function resetOnRequest()
    {
        // Reset websocket data
        if ($this->isServerWebsocket) {
            $this->app->make(Websocket::class)->reset(true);
        }
    }

接下来通过容器获取沙盒,这里也是关键之处。在非常住内存框架中,为了方便会有一些写法导致在常驻内存方式下不容易被释放内存,小则内存泄漏,大则数据错乱。而沙盒可以很好的解决这个问题。(文章最后会介绍一个造成内存泄漏和数据错乱的案例)

$sandbox = $this->app->make(Sandbox::class);

请求进行预处理,这里进行的是request的转换,从swoole的request转换到tp的request

$request = $this->prepareRequest($req);

$header = $req->header ?: [];
        $server = $req->server ?: [];

        if (isset($header['x-requested-with'])) {
            $server['HTTP_X_REQUESTED_WITH'] = $header['x-requested-with'];
        }

        if (isset($header['referer'])) {
            $server['http_referer'] = $header['referer'];
        }

        if (isset($header['host'])) {
            $server['http_host'] = $header['host'];
        }

        // 重新实例化请求对象 处理swoole请求数据
        /** @var \think\Request $request */
        $request = $this->app->make('request', [], true);

        return $request->withHeader($header)
            ->withServer($server)
            ->withGet($req->get ?: [])
            ->withPost($req->post ?: [])
            ->withCookie($req->cookie ?: [])
            ->withInput($req->rawContent())
            ->withFiles($req->files ?: [])
            ->setBaseUrl($req->server['request_uri'])
            ->setUrl($req->server['request_uri'] . (!empty($req->server['query_string']) ? '&' . $req->server['query_string'] : ''))
            ->setPathinfo(ltrim($req->server['path_info'], '/'));

对沙盒进行设置,并初始化沙盒

$sandbox->setRequest($request);
$sandbox->init();

启动沙盒

$response = $sandbox->run($request);

如果发生异常,则将异常信息处理并发送

try {
    $exceptionResponse = $this->app
        ->make(Handle::class)
        ->render($request, $e);

    $this->sendResponse($sandbox, $exceptionResponse, $res);
} catch (Throwable $e) {
    $this->logServerError($e);
}

最终需要将沙盒信息清除

$sandbox->clear();

以上是tp-swoole对HTTP的处理流程,下文会详细介绍沙盒的运行机制

番外篇

常驻内存易忽略的问题

class A{
    private static $intance=null;
    public static function getInstance(){
        if (!empty(self::$intance)){
            return self::$intance;
        }
        self::$intance = new static();
        return self::$intance;
    }
    public static function clear(){
        self::$intance=null;
    }

    public function echo(){
        echo "echo";
    }
    
}

$b = A::getInstance();
A::clear();
print_r($b->echo());

以上代码会报错吗?

不会。仍然会输出echo

下面在做另外一个实验

class A
{
    private static $intance = null;
    private $echo = 'echo';
    public static function getInstance()
    {
        if (!empty(self::$intance)) {
            return self::$intance;
        }
        self::$intance = new static();
        return self::$intance;
    }
    public static function clear()
    {
        self::$intance = null;
    }

    public function echo()
    {
        echo $this->echo;
    }


    public function setEcho($echo)
    {
        $this->echo = $echo;
    }
}

$b = A::getInstance();
$a = A::getInstance();
$a->setEcho("b");
print_r($b->echo());
A::clear();
print_r($b->echo());
$a->setEcho("a");
print_r($b->echo());

以上代码会输出什么?

答案是:bba。那么为什么不仅没有报错,还输出这样的答案

PHP的变量对象引入是地址引用,当$a和$b被赋值时,他们所存的内容都是一样的,且只有一份都是self::$intance位置所存放的内容。修改$a或$b都会修改self::$intance,那么为何当self::$intance为清除后,$a和$b仍然正常?基于 PHP 写时复制,当self::$intance被清空,就会复制出来一份给$a和$b来使用。

当我们在非常住内存方式开发时,这些都不需要注意,因为每次请求都相当于一个单独的线程,初始化所有数据,最后在将所有数据销毁,且所有数据都是按照顺序执行的。长住内存方式,就需要注意这些问题,不然会出现类似线程安全的问题。至于为何会出现这样的问题,下文再叙。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

结网

结网

王坚 / 人民邮电出版社 / 2010-4 / 55.00元

本书作者一直从事互联网产品的研究和实战,经验丰富,同时作为导师,指导了大量优秀的产品经理,本书的内容也是作者8年来培养产品经理新兵的经验集萃。如果你缺乏培养产品经理的教材,本书正好总结了产品经理知识体系,无疑是你很好的选择。 本书覆盖了相当全面的互联网知识,对于想要了解互联网行业或想要借助互联网进行营销的人来说,都是很好的入门读物。 本书并不是一本完善的互联网创业指南,而是写给胸怀互联......一起来看看 《结网》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

URL 编码/解码
URL 编码/解码

URL 编码/解码

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具