# 3.0 升级指南

- 3.0 版本主要修改了 `PHP` 最低版本为 `8.0`
- 框架移除了 `Doctrine Annotations`，改成使用 `PHP8 Attributes`
- 框架增加了大量的成员变量类型限制

## 转化所有注解为原生注解

**注意: 这个步骤只能在 2.2 版本下执行**

以下脚本会将所有 `Doctrine Annotations` 转化为 `PHP8 Attributes`。

```shell
composer require hyperf/code-generator
php bin/hyperf.php code:generate -D app
```

## 修改 Hyperf 组件版本

直接将 `composer.json` 中的 `hyperf/*` 统一修改为 `3.0.*` 即可。

> hyperf/engine 不跟随框架版本号，故不需要修改，确保为 ^2.1.0 版本即可，如果使用的 Hyperf 版本低于 v3.0，则需要使用 ^1.5 版本的 engine 组件。

后面只需要执行 `composer update -o`，就可以正常完成升级了。

## 升级数据库模型类

因为模型基类增加了成员变量的类型支持，所以需要使用以下脚本，将其升级为新版本。

```shell
composer require hyperf/code-generator
php vendor/bin/regenerate-models.php $PWD/app/Model
```

## Logger

`monolog/monolog` 3.x 版本因为使用了 PHP8.1 的新特性，所以需要对某些类进行特殊修改

将 `array $record` 修改为 `array|LogRecord $record` 即可兼容 3.x 版本，示例代码如下

```php
<?php

declare(strict_types=1);

namespace App\Kernel\Log;

use Hyperf\Context\Context;
use Hyperf\Coroutine\Coroutine;
use Monolog\LogRecord;
use Monolog\Processor\ProcessorInterface;

class AppendRequestIdProcessor implements ProcessorInterface
{
    public const REQUEST_ID = 'log.request.id';

    public function __invoke(array|LogRecord $record)
    {
        $record['extra']['request_id'] = Context::getOrSet(self::REQUEST_ID, uniqid());
        $record['extra']['coroutine_id'] = Coroutine::id();
        return $record;
    }
}

```

## Command

`3.0` 版本后，命令行默认开启了事件监听器，所以当有监听器监听了 `Command` 的事件，且进行了 `AMQP` 或者其他多路复用的逻辑后，会导致进程无法退出。

解决办法

- 方法一：

执行命令时，增加选项 `--disable-event-dispatcher`

- 方法二：

增加监听器

```php
<?php

declare(strict_types=1);

namespace App\Listener;

use Hyperf\Command\Event\AfterExecute;
use Hyperf\Coordinator\Constants;
use Hyperf\Coordinator\CoordinatorManager;
use Hyperf\Event\Annotation\Listener;
use Hyperf\Event\Contract\ListenerInterface;

#[Listener]
class ResumeExitCoordinatorListener implements ListenerInterface
{
    public function listen(): array
    {
        return [
            AfterExecute::class,
        ];
    }

    public function process(object $event): void
    {
        CoordinatorManager::until(Constants::WORKER_EXIT)->resume();
    }
}
```

## 替换 Hyperf\Utils\Context

- 由于 3.0 的 Context 换了命名空间 , 得全局替换 `Hyperf\Utils\Context` => `Hyperf\Context\Context`。

## 启动服务

接下来只需要启动服务，就可以看到不适配的地方，逐一修改即可。

- AMQP Consumer 和 Producer 成员变量增加了类型
- Listener 监听器的 `process` 方法增加了 `void` 返回值类型
- 注解 CircuitBreaker 将 `$timeout` 参数改为了 `$options.timeout`
- 异步队列 Async Queue 的成员变量增加了类型
- 异步队列，`event->message` 字段修改为非 public 类型，需要使用 `event->getMessage()` 读取。

## gRPC

框架根据 `gRPC` 规范修改了 `gRPC Server` 返回的 `Http status` 固定为为 200， `gRPC Server` 返回对应的 `status code`，更新前如果有使用 `gRPC`，请务必将相关的服务升级到 `3.x` 版本，不然会导致请求出现异常时，对端无法正常解析错误。

