mirror of
https://github.com/zhamao-robot/zhamao-framework.git
synced 2026-03-17 20:54:52 +08:00
update docs and change console command suitable
This commit is contained in:
parent
0972a1959e
commit
ccadec23e4
161
docs/component/console.md
Normal file
161
docs/component/console.md
Normal file
@ -0,0 +1,161 @@
|
||||
# Console 控制台
|
||||
|
||||
Console 类所在命名空间:`\ZM\Console\Console`
|
||||
|
||||
Console 类为框架的终端输出管理类。
|
||||
|
||||
## 设置 Log 输出等级
|
||||
|
||||
**输出等级** 控制了输出到命令行的内容的重要性。在框架的输出中,消息有以下几种不同等级的类别
|
||||
|
||||
- **error** / **log**: 0
|
||||
- **warning**: 1
|
||||
- **info** / **success**: 2
|
||||
- **verbose**: 3
|
||||
- **debug**: 4
|
||||
|
||||
输出等级设置后显示的消息类别为小于等于当前 log 的。假设你将 log 等级设置为 3,你可以看到除 debug 外的所有 log 内容。
|
||||
|
||||
通过配置文件 `global.php` 中的 `init_atomics -> info_level` 的数值你可以更改框架的默认 log 等级(默认为 2)。
|
||||
|
||||
你也可以在启动框架的命令行中添加参数来切换 log 等级:
|
||||
|
||||
```bash
|
||||
vendor/bin/start server --log-error # 以 error 等级启动框架
|
||||
vendor/bin/start server --log-warning # 以 warning 等级启动框架
|
||||
vendor/bin/start server --log-info # 以 info 等级启动框架
|
||||
vendor/bin/start server --log-verbose # 以 verbose 等级启动框架
|
||||
vendor/bin/start server --log-debug # 以 debug 等级 启动框架
|
||||
```
|
||||
|
||||
## 使用 Log 输出内容
|
||||
|
||||
作为模块开发者的你,你可以主动调用框架内的 Console 类输出信息到终端。
|
||||
|
||||
### Console::log()
|
||||
|
||||
输出 0 级别的普通 log。
|
||||
|
||||
- 参数:`$msg, $color`,分别为内容和字体颜色。
|
||||
|
||||
> 此 log 不会被 info_level 所限制,无论如何也会输出到终端。
|
||||
|
||||
### Console::error()
|
||||
|
||||
输出 error 级别的红色醒目 log。一般此 log 为框架内部出现不可忍受的错误,比如内存不足、PHP fatal error 等错误。
|
||||
|
||||
- 参数:`$msg`
|
||||
|
||||
> 此 log 不会被 info_level 所限制,无论如何也会输出到终端。
|
||||
|
||||
### Console::warning()
|
||||
|
||||
输出 warning 级别的 log。
|
||||
|
||||
!!! warning 注意
|
||||
|
||||
框架内出现的用户态异常,比如无法发送 API、无法连接数据库等错误,都是 warning 错误,不会导致框架崩溃或功能错误的异常情况建议都使用 warning 输出而不是 error。
|
||||
|
||||
|
||||
### Console::info()
|
||||
|
||||
输出 info 级别的 log。
|
||||
|
||||
### Console::success()
|
||||
|
||||
输出 success 级别的log。
|
||||
|
||||
### Console::verbose()
|
||||
|
||||
输出 verbose 级别的 log。
|
||||
|
||||
### Console::debug()
|
||||
|
||||
输出 debug 级别的 log。
|
||||
|
||||
### Console::stackTrace()
|
||||
|
||||
输出栈追踪信息。
|
||||
|
||||
### Console::setColor()
|
||||
|
||||
返回:彩色的字符串。
|
||||
|
||||
- **string**: 要变颜色的字符串
|
||||
- **color**: 要变的颜色。支持 `red`,`green`,`yellow`,`reset`,`blue`,`gray`,`gold`,`pink`,`lightblue`,`lightlightblue`
|
||||
|
||||
```php
|
||||
Console::log("This is normal msg. (0)");
|
||||
Console::error("This is error msg. (0)");
|
||||
Console::warning("This is warning msg. (1)");
|
||||
Console::info("This is info msg. (2)");
|
||||
Console::success("This is success msg. (2)");
|
||||
Console::verbose("This is verbose msg. (3)");
|
||||
Console::debug("This is debug msg. (4)");
|
||||
Console::stackTrace();
|
||||
$str = Console::setColor("I am gold color.", "gold");
|
||||
```
|
||||
|
||||
## 终端交互命令
|
||||
|
||||
炸毛框架支持从终端输入命令来进行一些操作,例如重启框架、停止框架、执行函数等。
|
||||
|
||||
::: warning 注意
|
||||
|
||||
在 Docker、systemd、daemon 状态下启动的框架会自动关闭终端等待输入,交互不可用。
|
||||
|
||||
:::
|
||||
|
||||
### reload
|
||||
|
||||
重新加载除 `src/Framework/` 下的所有模块。
|
||||
|
||||
- 别名:`r`
|
||||
|
||||
### stop
|
||||
|
||||
停止框架。
|
||||
|
||||
### logtest
|
||||
|
||||
输出各种等级的 log 示例文本。
|
||||
|
||||
### call
|
||||
|
||||
执行对应类的成员方法。下面是例子:
|
||||
|
||||
```bash
|
||||
call \ZM\Utils\ZMUtil reload
|
||||
```
|
||||
|
||||
### bc
|
||||
|
||||
直接执行 PHP 代码,输入格式为 base64。
|
||||
|
||||
```bash
|
||||
bc XEZyYW1ld29ya1xDb25zb2xlOjp3YXJuaW5nKCJoZWxsbyB3YXJuaW5nISIpOw==
|
||||
# 代码内容:\ZM\Console\Console::warning("hello warning!");
|
||||
# 终端输出:[19:14:32] [W] hello warning!
|
||||
```
|
||||
|
||||
### echo
|
||||
|
||||
输出文本
|
||||
|
||||
```bash
|
||||
echo hello
|
||||
```
|
||||
|
||||
### color
|
||||
|
||||
按照颜色输出文本
|
||||
|
||||
```bash
|
||||
color green 我是绿色的字
|
||||
```
|
||||
|
||||
## MOTD
|
||||
|
||||
在 1.4 版本开始,框架支持启动时的 motd 内容修改。
|
||||
|
||||
文件位置:`config/motd.txt`
|
||||
63
docs/component/coroutine-pool.md
Normal file
63
docs/component/coroutine-pool.md
Normal file
@ -0,0 +1,63 @@
|
||||
# 协程池
|
||||
|
||||
首先要声明的一点是,协程池这个概念是我自己编的。
|
||||
|
||||
因为协程的特点,它是单线程下运行的,所以在一个进程内同时实际上只会有一个协程的代码在执行逻辑,但是后面的 IO 操作、协程挂起等待的操作都是同时去做的,比如数据库的大数据读取、写入需要耗时几秒甚至几十秒,这时用基于协程的 MySQL 连接池就完全不是问题。
|
||||
|
||||
但是就拿 MySQL 举例,我们 MySQL 使用的是 TCP 连接,而无论是 MySQL 还是 TCP 连接,最大数量都是有限的。我们即使设置了允许最大协程数量非常大,比如上百万,但是也不能让数据库连接池一个池支持上百万的连接。
|
||||
|
||||
这时假设高并发进来了怎么办呢?这时就需要框架提出的一个折中方案:协程池了。
|
||||
|
||||
顾名思义,协程池是一个容纳协程的区域,而协程里又容纳着各种各样需要阻塞调用被协程调用的 IO 操作,协程池用作限制协程的数量。
|
||||
|
||||
```php
|
||||
use ZM\Utils\CoroutinePool;
|
||||
use ZM\DB\DB;
|
||||
|
||||
// 传统写法,一旦高并发则可能导致 Too many connections
|
||||
go(funuction(){
|
||||
DB::rawQuery("INSERT INTO users VALUES(?,?)", ["admin", "password"]);
|
||||
});
|
||||
// 协程池写法
|
||||
CoroutinePool::go(function(){
|
||||
DB::rawQuery("INSERT INTO users VALUES(?,?)", ["admin", "password"]);
|
||||
}, "foo");
|
||||
```
|
||||
|
||||
参数:`go(callable $func, $name = "default")`
|
||||
|
||||
`$name` 为协程池对应的名字,你可以设置多个协程池,用来支持不同的需要限制并发 IO 数量的地方,例如 Redis 和 MySQL 设置不同的名字。`$func` 可为闭包或可调用的方法名称或数组。
|
||||
|
||||
## 配置
|
||||
|
||||
默认情况下,直接调用 `CoroutinePool::go()` 时,协程池大小为 30,也就是如果有 30 个协程进入了挂起状态(比如数据库在执行查询语句),那么更多的协程执行时就会阻塞并以协程等待的方式等待,直到现有的 30 个协程中的一部分完成了它的工作。
|
||||
|
||||
## 方法
|
||||
|
||||
### CoroutinePool::go()
|
||||
|
||||
将协程放入协程池运行。
|
||||
|
||||
如果不写 `$name` 参数,则使用的是默认协程池。
|
||||
|
||||
### CoroutinePool::defaultSize()
|
||||
|
||||
设置默认协程池的大小(默认 30)
|
||||
|
||||
```php
|
||||
CoroutinePool::defaultSize(64);
|
||||
for($i = 0; $i < 1000; ++$i) {
|
||||
CoroutinePool::go(function(){
|
||||
DB::rawQuery("SELECT * FROM users");
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### CoroutinePool::setSize()
|
||||
|
||||
定义:`setSize($name, int $size)`
|
||||
|
||||
`$name` 为字符串,是你要用的协程池的名称。
|
||||
|
||||
`$size` 为大小,最大不可超过 Swoole 配置文件中指定的最大协程数量。
|
||||
|
||||
231
docs/component/global-functions.md
Normal file
231
docs/component/global-functions.md
Normal file
@ -0,0 +1,231 @@
|
||||
# 全局方法
|
||||
|
||||
全局方法就是 PHP 的全局函数,任意位置都可以调用,无需使用 use 字样。
|
||||
|
||||
## getClassPath()
|
||||
|
||||
根据加载的用户编写的代码类名来获取类所在的文件路径。
|
||||
|
||||
=== "src/Module/Example/Hello.php"
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace Module\Example;
|
||||
class Hello { ... }
|
||||
```
|
||||
|
||||
=== "src/Module/Example/Start.php"
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace Module\Example;
|
||||
use ZM\Annotation\Swoole\OnStart;
|
||||
class Start {
|
||||
/**
|
||||
* @OnStart()
|
||||
*/
|
||||
public function onStart() {
|
||||
Console::info("Path: ".getClassPath(Hello::class));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
=== "输出结果"
|
||||
|
||||
```
|
||||
[11:12:02] [I] [#0] Path: /mnt/d/project/zhamao-framework/src/Module/Example/Hello.ph
|
||||
```
|
||||
|
||||
## explodeMsg()
|
||||
|
||||
切割字符串的函数,支持多空格,换行,tab。
|
||||
|
||||
定义:`explodeMsg($msg, $ban_comma = false)`
|
||||
|
||||
```php
|
||||
$s = explodeMsg("你好啊 你好你好\n我还有多个空格 哈哈哈");
|
||||
echo json_encode($s, 128|256); // ["你好啊","你好你好","我还有多个空格","哈哈哈"]
|
||||
```
|
||||
|
||||
## unicode_decode()
|
||||
|
||||
Unicode 解码,一般用于被转义的 Unicode 转回来。
|
||||
|
||||
```php
|
||||
echo unicode_decode("\u4f60\u597d"); // 你好
|
||||
```
|
||||
|
||||
## matchPattern()
|
||||
|
||||
根据星号匹配字符串(非正则表达式)。
|
||||
|
||||
匹配示例:
|
||||
|
||||
- `你今天*了吗` -> 你今天喝水了吗
|
||||
- `*的天气怎么样` -> 德州的天气怎么样
|
||||
- `把*翻译成*` -> 把茶翻译成英语
|
||||
|
||||
定义:`matchPattern($pattern, $context)`
|
||||
|
||||
`$pattern` 为匹配模式,例如 `你今天*了吗`。
|
||||
|
||||
`$context` 为要判断是否匹配的内容。
|
||||
|
||||
返回值:`bool`,当为 true 时代表规则是匹配的,false 代表不匹配。
|
||||
|
||||
```php
|
||||
matchPattern("*是个啥?", "996是个啥?"); // true
|
||||
matchPattern("我想听*唱歌", "你想听谁唱歌"); // false
|
||||
matchPattern("*把*翻译成*", "请把你好翻译成阿拉伯语"); // true
|
||||
```
|
||||
|
||||
## split_explode()
|
||||
|
||||
和 `explodeMsg()` 类似,用作分割字符串,不过此函数加入了对 `中文|数字` 两者的分割,也就是说中文和数字之间也会被分割。
|
||||
|
||||
定义:`split_explode($del, $str, $divide_en = false)`
|
||||
|
||||
```php
|
||||
split_explode(" ", "前进20 急啊急啊"); // ["前进","20","急啊急啊"]
|
||||
```
|
||||
|
||||
`$del` 和 `explode()` 的第一个参数作用相同,作为初期分割的标志。
|
||||
|
||||
`$str` 表示待分割的内容。
|
||||
|
||||
`$divide_en` 表示是否分割中文和英文,如果为是,则中文和英文之间也会被分割开。
|
||||
|
||||
## matchArgs()
|
||||
|
||||
`matchPattern()` 的扩展,如果 `matchPattern()` 格式的字符串和模式匹配成功,则通过星号位置来提取星号匹配到的内容,参数同 `matchPattern()`。
|
||||
|
||||
```php
|
||||
$r = matchArgs("把*翻译成*", "把日语翻译成英语"); // ["日语","英语"]
|
||||
```
|
||||
|
||||
## connectIsQQ()
|
||||
|
||||
判断当前 WebSocket 连接是否为 OneBot 标准的机器人客户端。
|
||||
|
||||
## connectIsDefault()
|
||||
|
||||
判断连接是否是未定义类型的 WebSocket 连接。
|
||||
|
||||
## connectIs()
|
||||
|
||||
判断连接是否是对应类型的 WebSocket 连接。
|
||||
|
||||
```php
|
||||
connectIs("your_another_type_connect");
|
||||
```
|
||||
|
||||
## set_coroutine_params()
|
||||
|
||||
设置当前上下文中的一些变量。
|
||||
|
||||
```php
|
||||
set_coroutine_params(["data" => [
|
||||
"post_type" => "message",
|
||||
...
|
||||
]]);
|
||||
```
|
||||
|
||||
## ctx()
|
||||
|
||||
别名:`context()`,获取当前协程的上下文,见 [上下文](/component/context/)。
|
||||
|
||||
## zm_debug()
|
||||
|
||||
同 `Console::debug($msg)`。
|
||||
|
||||
## zm_sleep()
|
||||
|
||||
协程版 `sleep()` 函数。
|
||||
|
||||
定义:`zm_sleep($s = 1)`
|
||||
|
||||
`$s`:睡眠的时间:秒,可支持小数。(例如:0.001 代表 1 毫秒)
|
||||
|
||||
为什么不用 PHP 自带的 sleep 呢?因为炸毛框架是基于协程的,协程版 sleep 需要使用 Swoole 自带的 sleep。此函数做了一个简单的封装。
|
||||
|
||||
```php
|
||||
zm_sleep(5);
|
||||
zm_sleep(0.05);
|
||||
```
|
||||
|
||||
## zm_exec()
|
||||
|
||||
执行系统命令,替代 PHP 的 `exec()`。
|
||||
|
||||
定义:`zm_exec($cmd)`
|
||||
|
||||
返回值:
|
||||
|
||||
```php
|
||||
array(
|
||||
'code' => 0, // 进程退出的状态码
|
||||
'signal' => 0, // 信号
|
||||
'output' => 'hello world', // 输出内容
|
||||
);
|
||||
```
|
||||
|
||||
```php
|
||||
$result = zm_exec("echo 'hello world'")["output"];
|
||||
```
|
||||
|
||||
## zm_cid()
|
||||
|
||||
获取当前协程的 ID,效果等同于 `\Swoole\Coroutine::getCid()`。
|
||||
|
||||
## zm_yield()
|
||||
|
||||
挂起当前协程,直到手动恢复,效果等同于 `\Swoole\Coroutine::yield()`。
|
||||
|
||||
## zm_resume()
|
||||
|
||||
恢复继续执行协程,效果等同于 `\Swoole\Coroutine::resume()`。
|
||||
|
||||
```php
|
||||
$r = 0;
|
||||
function test() {
|
||||
echo "hello-1\n";
|
||||
global $r;
|
||||
$r = zm_cid();
|
||||
zm_yield();
|
||||
echo "hello-2\n";
|
||||
}
|
||||
|
||||
go("test");
|
||||
echo "hello-3\n";
|
||||
zm_resume($r);
|
||||
```
|
||||
|
||||
输出结果:
|
||||
|
||||
```
|
||||
hello-1
|
||||
hello-3
|
||||
hello-2
|
||||
```
|
||||
|
||||
## server()
|
||||
|
||||
获取 Swoole Server 对象进行操作,效果等同于 `\ZM\Framework::$server`。
|
||||
|
||||
```php
|
||||
echo server()->worker_id.PHP_EOL; // 0
|
||||
```
|
||||
|
||||
## bot()
|
||||
|
||||
返回 ZMRobot 操作机器人 API 的对象。
|
||||
|
||||
对于默认的模式,如果框架连接了多个机器人实例,则会随机返回一个机器人的 API 实例。如果使用了单例模式,则返回单例模式的机器人 API 实例。
|
||||
|
||||
```php
|
||||
bot()->sendPrivateMsg(123456, "你好啊!!");
|
||||
// 等同于 ZMRobot::getRandom()->sendPrivateMsg(123456, "你好啊!!");
|
||||
```
|
||||
|
||||
|
||||
|
||||
43
docs/component/singleton-trait.md
Normal file
43
docs/component/singleton-trait.md
Normal file
@ -0,0 +1,43 @@
|
||||
# 单例类(SingletonTrait)
|
||||
|
||||
单例类,顾名思义,就是让用户声明的类拥有单例的特性,而这一组件引入的方式也最直接。它是一个 PHP 的 `trait`。
|
||||
|
||||
我们传统写单例类的方式很手动,比如下面这样:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
class Foo {
|
||||
public $test = 0;
|
||||
private static $instance;
|
||||
public static function getInstance() {
|
||||
if (null === self::$instance) {
|
||||
self::$instance = new Foo();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
}
|
||||
Foo::getInstance()->test = 4;
|
||||
$obj = Foo::getInstance()->test;
|
||||
var_dump($obj); // 4
|
||||
```
|
||||
|
||||
这就要求我们每个需要声明为单例的类都写一个成员静态方法和成员静态变量。
|
||||
|
||||
框架使用了 PHP Trait 来快速让一个类支持这一特性:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use ZM\Utils\SingletonTrait;
|
||||
class Foo {
|
||||
use SingletonTrait;
|
||||
public $test = 0;
|
||||
}
|
||||
|
||||
Foo::getInstance()->test = 5;
|
||||
var_dump(Foo::getInstance()->test);
|
||||
```
|
||||
|
||||
只需要在类中使用:`use \ZM\Utils\SingletonTrait;` 一句话即可。
|
||||
@ -70,4 +70,4 @@ public function test() {
|
||||
|
||||
## 性能
|
||||
|
||||
使用自旋锁几乎没有性能损失,相反,使用自旋锁要比其他类型的锁性能强很多,在上方举例使用的 `ab` 压测工具测试 100万请求 下,使用自旋锁和不适用自旋锁的测试成绩时间分别为:7.4s 和 6.9s。
|
||||
使用自旋锁几乎没有性能损失,自旋锁要比其他类型的锁性能强很多,在上方举例使用的 `ab` 压测工具测试 100万请求 下,使用自旋锁和不适用自旋锁的测试成绩时间分别为:7.4s 和 6.9s。
|
||||
272
docs/component/zmrequest.md
Normal file
272
docs/component/zmrequest.md
Normal file
@ -0,0 +1,272 @@
|
||||
# ZMRequest(HTTP 客户端)
|
||||
|
||||
框架提供了轻量的 HTTP 请求发起工具类,直接静态调用即可。
|
||||
|
||||
命名空间:`use ZM\Requests\ZMRequest;`
|
||||
|
||||
!!! warning "注意"
|
||||
|
||||
在使用 Swoole 4.6.0 以下(不包含)的版本时,最好使用 Swoole 官方推荐的 Saber 或者 ZMRequest 这个轻量的 HTTP 请求客户端,不要使用 curl_exec,因为在老版本的 Swoole 上对 curl 的协程 Hook 支持不是很完善。
|
||||
|
||||
|
||||
## ZMRequest::get()
|
||||
|
||||
发起 GET 请求。
|
||||
|
||||
定义:`ZMRequest::get($url, $headers = [], $set = [], $return_body = true)`
|
||||
|
||||
全局函数别名:`zm_request_get($url, $headers = [], $set = [], $return_body = true)`
|
||||
|
||||
`$url`:要请求的 url,如 `http://captive.apple.com/`
|
||||
|
||||
`$headers`:要请求的 Headers,例如:`["User-Agent" => "Chrome"]`,数组形式
|
||||
|
||||
`$set`:请求时的一些设置,例如超时时间等等。详见下方“设置参数”
|
||||
|
||||
`$return_body`:是否只返回请求回来的内容部分,默认为 true,如果为 false 时则会返回一个 `\Swoole\Coroutine\Http\Client` 对象,可查阅 [Swoole 文档](http://wiki.swoole.com/#/coroutine_client/http_client) 进行接下来的一系列操作。
|
||||
|
||||
如果 `$return_body` 为 true,但是请求失败(HTTP 状态码不是 200 或无法连接到目标服务器或者无法解析域名等问题)时,方法会返回 false,否则会返回内容。
|
||||
|
||||
返回值:`false|string|\Swoole\Coroutine\Http\Client`
|
||||
|
||||
```php
|
||||
$r = ZMRequest::get("http://captive.apple.com/", ["User-Agent" => "Chrome"]);
|
||||
echo $r.PHP_EOL; // <HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>
|
||||
```
|
||||
|
||||
```php
|
||||
$r = zm_request_get("http://captive.apple.com/", [], [], false);
|
||||
echo $r->body.PHP_EOL; // 这行输出和上方的一致
|
||||
dump($r);
|
||||
/*
|
||||
^ Swoole\Coroutine\Http\Client {#170
|
||||
+errCode: 0
|
||||
+errMsg: ""
|
||||
+connected: false
|
||||
+host: "captive.apple.com"
|
||||
+port: 80
|
||||
+ssl: false
|
||||
+setting: array:1 [
|
||||
"timeout" => 15.0
|
||||
]
|
||||
+requestMethod: "GET"
|
||||
+requestHeaders: []
|
||||
+requestBody: null
|
||||
+uploadFiles: null
|
||||
+downloadFile: null
|
||||
+downloadOffset: 0
|
||||
+statusCode: 200
|
||||
+headers: array:4 [
|
||||
"content-type" => "text/html"
|
||||
"content-length" => "68"
|
||||
"date" => "Thu, 07 Jan 2021 06:22:32 GMT"
|
||||
"connection" => "keep-alive"
|
||||
]
|
||||
+set_cookie_headers: null
|
||||
+cookies: null
|
||||
+body: "<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>"
|
||||
}
|
||||
*/
|
||||
```
|
||||
|
||||
## ZMRequest::post()
|
||||
|
||||
发送一个 POST 请求。
|
||||
|
||||
定义:`ZMRequest::post($url, array $header, $data, $set = [], $return_body = true)`
|
||||
|
||||
全局函数别名:`zm_request_post($url, array $header, $data, $set = [], $return_body = true)`
|
||||
|
||||
`$url`:同上,填入 url,必填
|
||||
|
||||
`$header`:请求的 Headers,必填,数组形式,例如 `["Content-Type" => "application/json"]`
|
||||
|
||||
`$data`:请求的数据体,默认应该传入数组,如果传入 `array` 类型,则会默认当作 `Content-Type: application/x-www-form-urlencoded` 方式自动转码和转换,例如 `["key1" => "b1", "key2" => "b2"]` 会变成 `key1=b1&key2=b2`
|
||||
|
||||
`$set`:同上,见下面的设置参数部分。
|
||||
|
||||
`$return_body`:同上。
|
||||
|
||||
```php
|
||||
$s = ZMRequest::post("http://captive.apple.com/", ["Content-Type" => "application/json"], json_encode(["key1" => "value1"]));
|
||||
```
|
||||
|
||||
## ZMRequest::request()
|
||||
|
||||
发起自定义一切参数的 HTTP 请求。
|
||||
|
||||
参数:
|
||||
|
||||
- `$url`:请求的链接,自动解析端口、HTTPS、DNS 等操作
|
||||
- `$attribute`:请求的属性,示例见下方
|
||||
- `$return_body`:可选参数,`bool` 类型,和上面的 `$return_body` 参数意义相同
|
||||
|
||||
其中 `$attribute` 参数对应可设置的有:
|
||||
|
||||
- `method`:可选 `GET`,`POST` 等 HTTP 请求的方式
|
||||
- `set`:设置 Swoole 客户端的参数
|
||||
- `headers`:要请求的 HTTP Headers
|
||||
- `data`:请求的 body 数据,为数组时自动转换头部为 `x-www-form-urlencoded`
|
||||
- `file`:要发送的文件,数组,可选多个文件
|
||||
|
||||
例1:使用 GET 请求发送带有 Body 的 HTTP 请求
|
||||
|
||||
```php
|
||||
$r = ZMRequest::request("http://example.com", [
|
||||
"method" => "GET",
|
||||
"data" => [
|
||||
"key1" => "value1"
|
||||
]
|
||||
]);
|
||||
```
|
||||
|
||||
例2:设置请求超时时间并指定自定义头部
|
||||
|
||||
```php
|
||||
$r = ZMRequest::request("http://example.com", [
|
||||
"method" => "POST",
|
||||
"headers" => [
|
||||
"X-Custom-Header" => "Hello world",
|
||||
"User-Agent" => "HEICORE"
|
||||
],
|
||||
"set" => ["timeout" => 10.0]
|
||||
]);
|
||||
```
|
||||
|
||||
例3:发送文件和 data
|
||||
|
||||
```php
|
||||
$r = ZMRequest::request("http://example.com/sendfile", [
|
||||
"file" => [
|
||||
[
|
||||
"path" => "/path/to/image1.jpg", // path字段必填
|
||||
"name" => "file1", // name字段必填,这个是 POST 过去的 key
|
||||
//"mime_type" => "image/jpeg", // 可选字段,底层会自动推断
|
||||
//"filename" => "a.jpg", // 可选字段,文件名称
|
||||
//"offset" => 0, // 可选字段,可以从指定文件的中间部分开始传输数据,此特性用于断点续传
|
||||
//"length" => 1024 // 可选字段,默认为整个文件的尺寸
|
||||
],
|
||||
[
|
||||
"path" => "/path/to/image2.jpg",
|
||||
"name" => "file2"
|
||||
]
|
||||
],
|
||||
"data" => [
|
||||
"key1" => "value1"
|
||||
]
|
||||
]);
|
||||
```
|
||||
|
||||
## ZMRequest::downloadFile()
|
||||
|
||||
下载文件到本地。
|
||||
|
||||
定义:`ZMRequest::downloadFile($url, $dst = null)`
|
||||
|
||||
`$url`:不多讲,下载链接。
|
||||
|
||||
`$dst`:本地位置,例如 `/tmp/hello.html`
|
||||
|
||||
下载成功返回 true 或指定的文件位置,失败返回 false。
|
||||
|
||||
```php
|
||||
ZMRequest::downloadFile("http://captive.apple.com/", "/tmp/apple.html");
|
||||
```
|
||||
|
||||
## ZMRequest::websocket()
|
||||
|
||||
创建一个 WebSocket 连接。因为 Swoole 提供的是同步协程的方案,但对于 WebSocket 这样的全双工通信,反而不是一个好的代码逻辑,炸毛框架将此同步协程的方案封装成了异步事件调用的方式。
|
||||
|
||||
定义:`ZMRequest::websocket($url, $set = ['websocket_mask' => true], $header = [])`
|
||||
|
||||
返回:一个 `\ZM\Requests\ZMWebSocket` 对象
|
||||
|
||||
效果等同于:`$s = new \ZM\Requests\ZMWebSocket($url, $set = ['websocket_mask' => true], $header = [])`
|
||||
|
||||
这个是 ZMRequest 扩展而来的异步 WebSocket 客户端,可供方便地连接、收发 WebSocket 消息所定制。
|
||||
|
||||
命名空间:`\ZM\Requests\ZMWebSocket`
|
||||
|
||||
```php
|
||||
$ws = ZMRequest::websocket("ws://127.0.0.1:12345/"); //使用工具函数
|
||||
// $ws = new ZMWebSocket("ws://127.0.0.1:12345/"); //直接构造
|
||||
if($ws->is_available) {
|
||||
$ws->onMessage(function(\Swoole\WebSocket\Frame $frame, $client) {
|
||||
var_dump($frame->data);
|
||||
});
|
||||
$ws->onClose(function($client){
|
||||
Console::info("Websocket closed.");
|
||||
});
|
||||
$result = $ws->upgrade();
|
||||
var_dump($result);
|
||||
}
|
||||
```
|
||||
|
||||
### 属性
|
||||
|
||||
#### is_available
|
||||
|
||||
`bool` 类型,用于判断构造对象是否成功或链接是否可用。在构建新的对象并执行 `upgrade()` 前,如果 ws 链接没有问题,则会变为 true;在 `onClose()` 回调执行后,此值变回 false。
|
||||
|
||||
### 方法
|
||||
|
||||
#### __construct()
|
||||
|
||||
客户端对象的构造方法。
|
||||
|
||||
参数:
|
||||
|
||||
- `$url`:要请求到的 WebSocket 目标地址,必须以 `ws(s)://` 开头
|
||||
- `$set`:可选,Swoole 客户端的参数,例如超时、是否使用 `websocket_mask` 等,如果为空数组则默认为 `["websocket_mask" => true]`,具体可设置的内容见 [Swoole 文档](https://wiki.swoole.com/#/coroutine_client/http_client?id=set)
|
||||
- `$header`:可选,请求的头部信息,数组
|
||||
|
||||
```php
|
||||
$a = new ZMWebSocket("ws://127.0.0.1:8080/", ["websocket_mask" => true], [
|
||||
"User-Agent" => "Firefox"
|
||||
]);
|
||||
```
|
||||
|
||||
#### onMessage()
|
||||
|
||||
设置收到消息的回调函数。
|
||||
|
||||
回调的参数:
|
||||
|
||||
- `$frame`:`Swoole\WebSocket\Frame` 类型,消息帧,一般只用 `$frame->data` 获取数据,具体见 [Swoole 文档](https://wiki.swoole.com/#/websocket_server?id=swoolewebsocketframe)
|
||||
- `$client`:`Swoole\Coroutine\Http\Client` 类型,为客户端本身的对象,用于 push 数据等
|
||||
|
||||
```php
|
||||
$a->onMessage(function($frame, $client){
|
||||
echo "收到消息:".$frame->data.PHP_EOL;
|
||||
$client->push("hello world");
|
||||
});
|
||||
```
|
||||
|
||||
#### onClose()
|
||||
|
||||
设置连接断开后执行的回调函数。
|
||||
|
||||
回调的参数:
|
||||
|
||||
- `$client`:同上,但断开连接后不能使用 `push()` 发送数据了,只建议作为重连等机制的使用
|
||||
|
||||
```php
|
||||
$a->onClose(function($client){
|
||||
echo "WS 链接断开了!".PHP_EOL;
|
||||
});
|
||||
```
|
||||
|
||||
#### upgrade()
|
||||
|
||||
发起连接。
|
||||
|
||||
返回值:`true|false`,当为 `true` 时代表握手成功,此时可以在回调里愉快地收发消息了。如果为 `false` 表明握手失败。
|
||||
|
||||
!!! warning "注意"
|
||||
|
||||
这里由于是协程转异步,所以不能确定 `upgrade()` 和 `onMessage()` 哪个先会被触发(一般情况下如果服务器不是立刻响应回包信息,总是会先返回 `upgrade()` 的结果。
|
||||
|
||||
## 设置参数
|
||||
|
||||
见:[Swoole - HTTP 客户端](http://wiki.swoole.com/#/coroutine_client/http_client?id=set)
|
||||
|
||||
23
docs/component/zmutil.md
Normal file
23
docs/component/zmutil.md
Normal file
@ -0,0 +1,23 @@
|
||||
# ZMUtil 杂项工具类
|
||||
|
||||
调用前先 use:`use ZM\Utils\ZMUtil;`
|
||||
|
||||
## ZMUtil::stop()
|
||||
|
||||
停止框架运行。
|
||||
|
||||
## ZMUtil::reload()
|
||||
|
||||
重载框架,这会断开所有到框架的连接和重载所有 `src/` 目录下的用户源码并重新加载所有 Worker 进程。
|
||||
|
||||
## ZMUtil::getModInstance()
|
||||
|
||||
根据类名称拿到此类的单例(前提是目标的类的构造函数为空)。
|
||||
|
||||
```php
|
||||
class ASD{
|
||||
public $test = 0;
|
||||
}
|
||||
ZMUtil::getModInstance(ASD::class)->test = 5;
|
||||
```
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
# 快速上手 - HTTP 服务器篇
|
||||
|
||||
HTTP 服务器篇暂时先放一放,大家应该主要都是奔着机器人开发来的吧~
|
||||
HTTP 服务器篇主要讲解如何通过炸毛框架来实现微服务、API 通用接口等等这些东西的。
|
||||
|
||||
- [HTTP 服务器 - 路由和静态文件篇](/event/route-annotations/)
|
||||
- [HTTP 服务器 - 存储 - LightCache 轻量缓存](/component/light-cache/)
|
||||
- [HTTP 服务器 - 存储 - Redis](/component/redis/)
|
||||
- [HTTP 服务器 - 存储 - MySQL](/component/mysql/)
|
||||
- [HTTP 客户端](/component/zmrequest/)
|
||||
|
||||
|
||||
10
mkdocs.yml
10
mkdocs.yml
@ -10,8 +10,8 @@ theme:
|
||||
favicon: assets/favicon.png
|
||||
language: zh
|
||||
palette:
|
||||
primary: deep orange
|
||||
accent: deep orange
|
||||
primary: blue
|
||||
accent: blue
|
||||
features:
|
||||
- navigation.tabs
|
||||
extra_javascript:
|
||||
@ -81,6 +81,12 @@ nav:
|
||||
- Redis 数据库: component/redis.md
|
||||
- ZMAtomic 原子计数器: component/atomics.md
|
||||
- SpinLock 自旋锁: component/spin-lock.md
|
||||
- 协程池: component/coroutine-pool.md
|
||||
- 单例类: component/singleton-trait.md
|
||||
- ZMUtil 杂项: component/zmutil.md
|
||||
- 全局方法: component/global-functions.md
|
||||
- HTTP 和 WebSocket 客户端: component/zmrequest.md
|
||||
- Console 终端: component/console.md
|
||||
- 进阶开发:
|
||||
- 进阶开发: advanced/index.md
|
||||
- 从 v1 升级: advanced/to-v2.md
|
||||
|
||||
@ -255,6 +255,7 @@ class Framework
|
||||
}
|
||||
break;
|
||||
case 'disable-console-input':
|
||||
case 'no-interaction':
|
||||
if ($y) $terminal_id = null;
|
||||
break;
|
||||
case 'log-error':
|
||||
@ -267,6 +268,7 @@ class Framework
|
||||
if ($y) Console::setLevel(2);
|
||||
break;
|
||||
case 'log-verbose':
|
||||
case 'verbose':
|
||||
if ($y) Console::setLevel(3);
|
||||
break;
|
||||
case 'log-debug':
|
||||
@ -277,6 +279,10 @@ class Framework
|
||||
Console::$theme = $y;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Console::info("Calculating ".$x);
|
||||
dump($y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($coroutine_mode) Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user