【Hyperf 入门到精通】生命周期 03

生命周期与变量作用范围

Laravel 生命周期是由FPM 决定的, 同样Hyperf 生命周期是由Swoole 生命周期决定的

以HTTP 服务为例, 通过代码解释一下生命周期, 如果使用不当, 会造成内存泄漏、数据混淆, 引发生产事故

  • 全局生命周期(进程生命周期)
  • 请求生命周期
  • 协程生命周期
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

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

use Hyperf\Engine\Http\Server;
use Hyperf\HttpMessage\Server\Response;
use Psr\Http\Message\ServerRequestInterface;
use Swow\Psr7\Server\ServerConnection;

$a = 0;

$server = new Server();
$server->bind('0.0.0.0', 9502);
$server->handle(function (ServerRequestInterface $request, ServerConnection $connection) {
$b = 0;
$response = new Response();
$connection->sendHttpResponse($response->withContent('Hello World'))->close();
});
$server->start();

全局生命周期, 内存里一直存在, 程序结束才会释放

  • start() 前赋值的变量
  • 类静态属性
  • 超全局变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?php

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

use Hyperf\Engine\Http\Server;
use Hyperf\HttpMessage\Server\Response;
use Psr\Http\Message\ServerRequestInterface;
use Swow\Psr7\Server\ServerConnection;

class Count
{
public static int $count = 0;
}

$count = 0;
$globalCount = 0;

$_GET['count'] = 0;

$server = new Server();
$server->bind('0.0.0.0', 9502);
$server->handle(function (ServerRequestInterface $request, ServerConnection $connection) use (&$count) {
global $globalCount;

// start() 前声明的变量
$globalCount++;
$count++;

// 类静态变量
Count::$count++;

// 超全局变量
$_GET['count']++;

echo "Global \$count: {$globalCount}\n";
echo "Global \$globalCount: {$globalCount}\n";
echo "Global Count::count " . Count::$count . "\n";
echo "Global \$_GET {$_GET['count']} \n";

$connection->sendHttpResponse((new Response())->withContent('Hello World'))->close();
});
$server->start();

代码生命周期小于变量作用范围才可能出现内存泄漏
比如请求生命周期内, 操作全局变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

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

use Hyperf\Engine\Http\Server;
use Hyperf\HttpMessage\Server\Response;
use Psr\Http\Message\ServerRequestInterface;
use Swow\Psr7\Server\ServerConnection;

$globalCount = [];

$server = new Server();
$server->bind('0.0.0.0', 9502);
$server->handle(function (ServerRequestInterface $request, ServerConnection $connection) {
global $globalCount;
$globalCount[] = $request;
$connection->sendHttpResponse((new Response())->withContent('Hello World'))->close();
});
$server->start();

注意, 上述代码中的$request本身是请求生命周期, 但是赋值给全局生命周期的变量, 导致变量作用范围逃逸

举个常用的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

namespace App\Controller;

use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;

#[Controller]
class IndexController extends AbstractController
{
public int $count = 0;

#[GetMapping("/add")]
public function add()
{
echo $this->count++, PHP_EOL;
sleep(1);
return $this->count;
}
}

为什么以上代码会出现数据混淆?

其实$count 作用范围隶属于IndexController
IndexController$container->$resolvedEntries 获取
$containerSwoole::start() 前声明, 所以是全局生命周期变量
ApplicationContext::getContainer() 只是方便使用, 并不是根本原因