摘要:如下图目录结构主要针对的是非常驻内存方式运行,为了兼容,虽然做了很多优化,但是仍然无法像,等一些针对开发的框架一样。在非常住内存框架中,为了方便会有一些写法导致在常驻内存方式下不容易被释放内存,小则内存泄漏,大则数据错乱。
前言
ThinkPHP即将迎来最新版本6.0,针对目前越来越流行Swoole,thinkphp也推出了最新的扩展think-swoole 3.0架构分析
tp-swoole3.0不同于2.0版本,采用了全新的架构。(如下图目录结构)
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 hinkRequest $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来使用。
当我们在非常住内存方式开发时,这些都不需要注意,因为每次请求都相当于一个多带带的线程,初始化所有数据,最后在将所有数据销毁,且所有数据都是按照顺序执行的。长住内存方式,就需要注意这些问题,不然会出现类似线程安全的问题。至于为何会出现这样的问题,下文再叙。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/31641.html
摘要:由于是基于容器创建和销毁资源的,那么各个容器之间是相对隔离的。也就是说每次请求都会创建一个新的环境用于执行和解析,由于容器的隔离性,每个请求都不会和其他请求进行干扰。因为只有当前协程才可以读取到该数据。 前言 ThinkPHP即将迎来最新版本6.0,针对目前越来越流行Swoole,thinkphp也推出了最新的扩展think-swoole 3.0 沙盒 本文主要介绍在ThinkPHP-...
摘要:前言即将迎来最新版本,针对目前越来越流行,也推出了最新的扩展安装由于目前没有稳定版本,所以只能安装开发板接下来安装,目前最新的稳定版本是配置安装结束可以根据自己的需求对配置信息进行修改。 前言 ThinkPHP即将迎来最新版本6.0,针对目前越来越流行Swoole,thinkphp也推出了最新的扩展think-swoole 3.0 安装 由于目前thinkphp 6.0没有稳定版本,所...
摘要:前言即将迎来最新版本,针对目前越来越流行,也推出了最新的扩展。介绍即将推出的,已经适配并推出,并且默认适配了。和版本在使用方法上面有些许不同。其中的第一个参数和的第一个参数一致,作为事件名称。 前言 ThinkPHP即将迎来最新版本6.0,针对目前越来越流行Swoole,thinkphp也推出了最新的扩展think-swoole 3.0。 介绍 即将推出的tp6.0,已经适配swool...
摘要:安装框架安装如果已经安装了可以跳过本步骤,但是请确定通过命令来确保已经使用了最新版本的使用以下命令可以直接通过官网下载并自动安装到目录下如果以上安装过程极慢的话,可以尝试用以下方式通过国内镜像来安装。 《当 Swoole 遇上 ThinkPHP5》:Hello,World! 本文假设你已经有了 Linux 操作系统的 PHP 环境,强烈推荐使用 Vagrant 来搭建开发环境 安装 ...
摘要:文章目录一线性模型二绘图工具三作业一线性模型不要小看简单线性模型哈哈,虽然这讲我们还没正式用到,但是用到的前向传播损失函数两种绘图等方法在后面是很常用的。 文章目...
阅读 3774·2021-11-12 10:36
阅读 3234·2021-09-22 15:35
阅读 3204·2021-09-04 16:41
阅读 1426·2019-08-30 15:55
阅读 3849·2019-08-29 18:43
阅读 2340·2019-08-23 18:24
阅读 1879·2019-08-23 18:10
阅读 2172·2019-08-23 11:31