# 注册事件响应(机器人篇)

现在模块已经创建完毕,我们可以开始编写实际代码了。本段以机器人会话为例子来讲述事件注册和响应,有关 HTTP 服务器等注册事件响应请看后面事件和注解章节。

# 机器人聊天事件处理

首先知道,QQ 等聊天机器人的消息我们的处理逻辑为如下简单的模式:

  • QQ 用户消息 -> 机器人客户端 -> 连接客户端的框架(炸毛框架)
  • 框架处理逻辑后返回给用户的消息 -> 机器人客户端 -> QQ用户

第一步,我们以框架这边的角度考虑,我们称之为“事件”,我们编写代码所做的就是要响应这一事件。

首先我们以一句简单的功能——查天气,我们要从零实现一个查天气的功能进行示范如何快捷有效地开发一个功能。

# 确定问法

我们首先要确定的用户问法是一般由我们自己定义,但最好贴合用户的自然语言来进行定义。比如我们这里提到的天气功能,用户一般就会询问“北京天气”,“北京天气怎么样”,“天气 北京”。

# 注册消息事件

我们以最简单的命令方式“天气 北京”进行处理。问法为参数化的,通过空格来分开,这也是炸毛框架默认支持最基本的聊天事件之一。我们通过上一部分的方式新建一个单文件模块 Weather.phpsrc/Module 目录下,并编写:

<?php
namespace Module;
use ZM\Annotation\CQ\CQCommand;
class Weather {
    /**
     * @CQCommand("天气")
     * @return string
     */
    public function searchWeather() {
        $city = ctx()->getNextArg("请告诉我你要查询的城市"); // 发送 “天气 北京”时,变量为“北京”
        // 这里假设是天气API接口的对接,返回了天气的数据
        $weather = "2020年12月22日,晴,-2~9℃ blablabla";
        return "$city 天气情况:".$weather;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

提示

为了简单起见,我们在这里的例子中没有接入真实的天气数据,但要接入也非常简单,你可以使用中国天气网、和风天气等网站提供的 API,本教程的进阶一栏后期会详细编写如何对接一个天气 API 接口。

在上方代码编写完毕后,运行框架(或运行过程中终端输入 reload),然后使用机器人客户端连接到炸毛框架,即可实现我们的第一个功能。我们在代码中编写了一个注解事件@CQCommand,此注解事件是用于接收用户的普通消息并切分成各类命令规则的一个注解事件绑定。代码中的注解事件省去了注解中的键名,也可以写作 @CQCommand(match="天气")

这里注解事件的概念请看 事件和注解 一栏描述的概念即可。到这里,我们就完成一个可以处理命令 天气 xxx 的方法了!

# 处理消息事件

第一行 ctx() 是炸毛框架内的上下文获取方式,每条用户聊天信息发过来,被炸毛框架收到,都会创建一次上下文,同时这次聊天的全部信息,比如用户的 ID(QQ 号码),发消息的时间,如果是群消息的话所在的群号等等,都被存到了上下文中。ctx() 获取的是一个上下文对象,内部有许多可操作上下文的方法,其中代码的 getNextArg(),作用是根据空格分隔获取命令中的下一个参数。

在之前我们知道:天气 北京 是我们发送的消息,我们要获取到用户发送的参数 北京getNextArg() 是框架封装好的一个快速获取下一个参数的方法,我们这里直接使用它来获取。

对于 getNextArg() 中的文本,可为空,不为空的时候如果用户只发送天气两个字,机器人还是会响应,但是它会询问你这句话,然后你回复机器人“北京”,这里 $city 变量就接受到并赋值为“北京”了,代码会继续执行,和直接一次性发送机器人“天气 北京”是一个效果,此为框架封装的消息会话机制,以贴近自然会话的方式来编写代码逻辑。

最后,函数直接返回了一个字符串,作为事件的响应,炸毛框架会自动处理并调用机器人客户端的接口,最后返回给用户消息。这里也可以使用上下文的 ctx()->reply("xxx") 方法替代,不返回字符串。注意两者只能选择一种方式,取决于开发者的开发习惯。

天气 北京
北京 天气情况:2020年12月22日,晴,-2~9℃ blablabla
天气
请告诉我你要查询的城市
北京
北京 天气情况:2020年12月22日,晴,-2~9℃ blablabla