Files
zhamao-framework/src/ZM/global_functions.php

897 lines
20 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
use Swoole\Atomic;
2020-11-03 21:02:24 +08:00
use Swoole\Coroutine;
use Swoole\Coroutine as Co;
use Swoole\Coroutine\System;
use Swoole\WebSocket\Server;
use Symfony\Component\VarDumper\VarDumper;
2021-06-16 00:17:30 +08:00
use ZM\API\OneBotV11;
2022-03-21 20:08:09 +08:00
use ZM\API\ZMRobot;
2020-08-31 10:11:06 +08:00
use ZM\Config\ZMConfig;
use ZM\ConnectionManager\ManagerGM;
2020-08-31 10:11:06 +08:00
use ZM\Console\Console;
2022-04-05 00:24:03 +08:00
use ZM\Container\Container;
use ZM\Container\ContainerInterface;
2020-09-29 15:07:43 +08:00
use ZM\Context\Context;
use ZM\Context\ContextInterface;
2020-09-29 15:07:43 +08:00
use ZM\Event\EventManager;
use ZM\Exception\RobotNotFoundException;
2020-08-31 10:11:06 +08:00
use ZM\Framework;
use ZM\Store\LightCacheInside;
use ZM\Store\ZMAtomic;
2020-08-31 10:11:06 +08:00
use ZM\Store\ZMBuf;
use ZM\Utils\DataProvider;
2020-05-02 23:27:26 +08:00
2022-03-21 20:08:09 +08:00
/**
* 获取类路径
*/
function get_class_path(string $class_name): ?string
2022-03-13 22:47:11 +08:00
{
$dir = str_replace('\\', '/', $class_name);
2022-03-21 20:08:09 +08:00
$dir = DataProvider::getSourceRootDir() . '/src/' . $dir . '.php';
$dir = str_replace('\\', '/', $dir);
if (file_exists($dir)) {
return $dir;
}
return null;
2020-03-02 16:14:20 +08:00
}
2022-03-13 22:47:11 +08:00
2021-11-02 16:01:24 +08:00
/**
* 检查炸毛框架运行的环境
2022-04-05 00:24:03 +08:00
*
2021-11-02 16:01:24 +08:00
* @internal
*/
2022-03-13 22:47:11 +08:00
function _zm_env_check()
{
if (!extension_loaded('swoole')) {
exit(zm_internal_errcode('E00001') . "Can not find swoole extension.\n");
}
2022-03-21 20:08:09 +08:00
if (version_compare(SWOOLE_VERSION, '4.5.0') === -1) {
exit(zm_internal_errcode('E00002') . 'You must install swoole version >= 4.5.0 !');
}
2022-03-21 20:08:09 +08:00
if (version_compare(PHP_VERSION, '7.2') === -1) {
exit(zm_internal_errcode('E00003') . 'PHP >= 7.2 required.');
}
if (version_compare(SWOOLE_VERSION, '4.6.7') < 0 && !extension_loaded('pcntl')) {
Console::error(zm_internal_errcode('E00004') . 'Swoole 版本必须不低于 4.6.7 或 PHP 安装加载了 pcntl 扩展!');
exit();
2021-11-02 16:01:24 +08:00
}
}
2020-03-02 16:14:20 +08:00
/**
2022-03-21 20:08:09 +08:00
* 分割消息字符串
*
* @param array $includes 需要进行切割的字符串,默认包含空格及制表符(\t)
2020-03-02 16:14:20 +08:00
*/
2022-03-21 20:08:09 +08:00
function explode_msg(string $msg, array $includes = [' ', "\t"]): array
2022-03-13 22:47:11 +08:00
{
2022-03-21 20:08:09 +08:00
$msg = trim($msg);
foreach ($includes as $v) {
$msg = str_replace($v, "\n", $msg);
2020-03-02 16:14:20 +08:00
}
2022-03-21 20:08:09 +08:00
$msg_seg = explode("\n", $msg);
2020-03-02 16:14:20 +08:00
$ls = [];
2022-03-21 20:08:09 +08:00
foreach ($msg_seg as $v) {
if (empty(trim($v))) {
continue;
}
2020-03-02 16:14:20 +08:00
$ls[] = trim($v);
}
return $ls;
}
2022-03-21 20:08:09 +08:00
/**
* 解码Unicode字符串
*/
function unicode_decode(string $str): ?string
2022-03-13 22:47:11 +08:00
{
2022-03-21 20:08:09 +08:00
return preg_replace_callback('/\\\\u([0-9a-f]{4})/i', static function ($matches) {
return mb_convert_encoding(pack('H*', $matches[1]), 'UTF-8', 'UCS-2BE');
2020-03-02 16:14:20 +08:00
}, $str);
}
2022-03-21 20:08:09 +08:00
/**
* 格式匹配
*/
function match_pattern(string $pattern, string $subject): bool
2022-03-13 22:47:11 +08:00
{
$pattern = str_replace(['\*', '\\\\.*'], ['.*', '\*'], preg_quote($pattern, '/'));
$pattern = '/^' . $pattern . '$/i';
return preg_match($pattern, $subject) === 1;
2020-03-02 16:14:20 +08:00
}
2022-04-02 23:37:22 +08:00
/**
* @requires symfony/polyfill-ctype
* @return array|string[]
*/
2022-03-21 20:08:09 +08:00
function split_explode(string $del, string $string, bool $divide_en = false): array
2022-03-13 22:47:11 +08:00
{
2022-03-21 20:08:09 +08:00
$str = explode($del, $string);
for ($i = 0, $i_max = mb_strlen($str[0]); $i < $i_max; ++$i) {
2020-03-02 16:14:20 +08:00
if (
is_numeric(mb_substr($str[0], $i, 1))
&& (
!is_numeric(mb_substr($str[0], $i - 1, 1))
2022-03-21 20:08:09 +08:00
&& mb_substr($str[0], $i - 1, 1) !== ' '
&& ctype_alpha(mb_substr($str[0], $i - 1, 1)) === false
2020-03-02 16:14:20 +08:00
)
) {
$str[0] = mb_substr($str[0], 0, $i) . ' ' . mb_substr($str[0], $i);
2020-03-02 16:14:20 +08:00
} elseif (
$divide_en
2022-03-21 20:08:09 +08:00
&& mb_substr($str[0], $i - 1, 1) !== ' '
&& ctype_alnum(mb_substr($str[0], $i, 1))
&& !ctype_alnum(mb_substr($str[0], $i - 1, 1))
2020-03-02 16:14:20 +08:00
) {
$str[0] = mb_substr($str[0], 0, $i) . ' ' . mb_substr($str[0], $i);
}
}
$str = implode($del, $str);
2022-03-21 20:08:09 +08:00
2020-03-02 16:14:20 +08:00
$ls = [];
2021-06-16 00:17:30 +08:00
foreach (explode($del, $str) as $v) {
2022-03-21 20:08:09 +08:00
if (empty(trim($v))) {
continue;
}
2020-03-02 16:14:20 +08:00
$ls[] = $v;
}
2022-03-21 20:08:09 +08:00
return $ls ?: [''];
2020-03-02 16:14:20 +08:00
}
2022-03-21 20:08:09 +08:00
/**
* 匹配参数
*
* @return array|false 成功时返回匹配到的参数数组失败时返回false
*/
function match_args(string $pattern, string $subject)
2022-03-13 22:47:11 +08:00
{
2020-03-02 16:14:20 +08:00
$result = [];
2022-03-21 20:08:09 +08:00
if (match_pattern($pattern, $subject)) {
if (mb_strpos($pattern, '*') === false) {
return [];
}
$exp = explode('*', $pattern);
2020-03-02 16:14:20 +08:00
$i = 0;
foreach ($exp as $k => $v) {
2022-03-21 20:08:09 +08:00
if (empty($v) && $k === 0) {
continue;
2020-03-02 16:14:20 +08:00
}
2022-03-21 20:08:09 +08:00
if (empty($v) && $k === count($exp) - 1) {
$subject .= '^EOL';
$v = '^EOL';
}
$cur_var = '';
2020-03-02 16:14:20 +08:00
$ori = $i;
2022-03-21 20:08:09 +08:00
while (($a = mb_substr($subject, $i, mb_strlen($v))) !== $v && !empty($a)) {
$cur_var .= mb_substr($subject, $i, 1);
2020-03-02 16:14:20 +08:00
++$i;
}
2022-03-21 20:08:09 +08:00
if ($i !== $ori || $k === 1 || $k === count($exp) - 1) {
2020-03-02 16:14:20 +08:00
$result[] = $cur_var;
}
$i += mb_strlen($v);
}
return $result;
}
return false;
}
2022-03-21 20:08:09 +08:00
/**
* 判断当前连接类型是否为传入的$type
*
2022-05-04 21:05:10 +08:00
* @param string $type 连接类型
2022-03-21 20:08:09 +08:00
*/
function current_connection_is(string $type): bool
2022-03-13 22:47:11 +08:00
{
2022-03-21 20:08:09 +08:00
return ctx()->getConnection()->getName() === $type;
2020-09-29 15:07:43 +08:00
}
2022-03-21 20:08:09 +08:00
/**
* 获取触发当前方法的注解
*/
function get_annotations(): array
2022-03-13 22:47:11 +08:00
{
2020-09-29 15:07:43 +08:00
$s = debug_backtrace()[1];
$list = [];
2021-06-16 00:17:30 +08:00
foreach (EventManager::$events as $v) {
foreach ($v as $vs) {
2022-03-21 20:08:09 +08:00
if ($vs->class === $s['class'] && $vs->method === $s['function']) {
$list[get_class($vs)][] = $vs;
2020-09-29 15:07:43 +08:00
}
}
}
return $list;
}
2022-03-21 20:08:09 +08:00
/**
* 设置协程参数
*/
function set_coroutine_params(array $params): void
2022-03-13 22:47:11 +08:00
{
2022-04-10 00:58:07 +08:00
$cid = co::getCid();
2022-03-21 20:08:09 +08:00
if ($cid === -1) {
exit(zm_internal_errcode('E00061') . 'Cannot set coroutine params at none coroutine mode.');
}
if (isset(Context::$context[$cid])) {
2022-03-21 20:08:09 +08:00
Context::$context[$cid] = array_merge(Context::$context[$cid], $params);
} else {
2022-03-21 20:08:09 +08:00
Context::$context[$cid] = $params;
}
2020-09-29 15:07:43 +08:00
foreach (Context::$context as $c => $v) {
2022-04-10 00:58:07 +08:00
if (!co::exists($c)) {
unset(Context::$context[$c], ZMBuf::$context_class[$c]);
}
}
}
/**
2022-03-21 20:08:09 +08:00
* 获取当前上下文
*/
function context(): ContextInterface
2022-03-13 22:47:11 +08:00
{
2020-05-23 17:23:29 +08:00
return ctx();
}
/**
2022-03-21 20:08:09 +08:00
* 获取当前上下文
*/
function ctx(): ContextInterface
2022-03-13 22:47:11 +08:00
{
2022-04-10 00:58:07 +08:00
$cid = co::getCid();
$c_class = ZMConfig::get('global', 'context_class');
2020-09-29 15:07:43 +08:00
if (isset(Context::$context[$cid])) {
2020-05-23 17:23:29 +08:00
return ZMBuf::$context_class[$cid] ?? (ZMBuf::$context_class[$cid] = new $c_class($cid));
}
Console::debug("未找到当前协程的上下文({$cid}),正在找父进程的上下文");
2022-04-10 00:58:07 +08:00
while (($parent_cid = co::getPcid($cid)) !== -1) {
2022-03-21 20:08:09 +08:00
$cid = $parent_cid;
if (isset(Context::$context[$cid])) {
return ZMBuf::$context_class[$cid] ?? (ZMBuf::$context_class[$cid] = new $c_class($cid));
}
}
2022-04-30 13:38:15 +08:00
Console::warning('当前环境不是协程环境,将返回独立的非协程的容器');
return ZMBuf::$context_class[$cid] ?? (ZMBuf::$context_class[$cid] = new $c_class($cid));
}
2022-03-21 20:08:09 +08:00
/**
* 根据消息类型获取对应的OneBot目标名称
*
* @return string 如传入的消息类型不被支持,将默认返回`user_id`
*/
function get_onebot_target_id_name(string $message_type): string
2022-03-13 22:47:11 +08:00
{
2022-03-21 20:08:09 +08:00
switch ($message_type) {
case 'group':
return 'group_id';
case 'discuss':
return 'discuss_id';
case 'private':
default:
return 'user_id';
}
2020-11-03 21:02:24 +08:00
}
2020-05-23 17:23:29 +08:00
2022-03-21 20:08:09 +08:00
/**
* 协程休眠
*
* {@link sleep()} 一致,只是增加了协程支持
*
* @since 2.7.3 此函数不再返回 true
*/
function zm_sleep(int $seconds = 1): void
2022-03-13 22:47:11 +08:00
{
2022-03-21 20:08:09 +08:00
if (Coroutine::getCid() !== -1) {
System::sleep($seconds);
} else {
usleep($seconds * 1000 * 1000);
}
}
2020-05-23 17:23:29 +08:00
2022-03-21 20:08:09 +08:00
/**
* 协程执行命令
*
* {@link exec()} 一致,只是增加了协程支持
*
* @return array{code: int, signal: int, output: string}
*/
function zm_exec(string $command): array
{
return System::exec($command);
}
/**
* 获取当前协程ID
*
* {@link Co::getCid()} 一致
*/
function zm_cid(): int
2022-03-13 22:47:11 +08:00
{
2022-04-10 00:58:07 +08:00
return co::getCid();
}
2020-05-23 17:23:29 +08:00
2022-03-21 20:08:09 +08:00
/**
* 挂起当前协程
*
* {@link Co::yield()} 一致
*/
2022-03-13 22:47:11 +08:00
function zm_yield()
{
2022-04-10 00:58:07 +08:00
co::yield();
}
2020-05-23 17:23:29 +08:00
2022-03-21 20:08:09 +08:00
/**
* 恢复并继续执行指定协程
*
* {@link Co::resume()} 一致
*/
2022-03-13 22:47:11 +08:00
function zm_resume(int $cid)
{
2022-04-10 00:58:07 +08:00
co::resume($cid);
}
2020-05-23 17:23:29 +08:00
2022-03-21 20:08:09 +08:00
/**
* 指定延迟后执行函数
*
* @param int $delay 延迟时间单位毫秒ms
*/
2022-03-21 23:28:57 +08:00
function zm_timer_after(int $delay, callable $runnable)
2022-03-13 22:47:11 +08:00
{
2022-03-21 20:08:09 +08:00
Swoole\Timer::after($delay, static function () use ($runnable) {
call_with_catch($runnable);
2020-05-23 17:23:29 +08:00
});
}
2020-05-23 17:23:29 +08:00
2022-03-21 20:08:09 +08:00
/**
* 重复在指定时间间隔后执行函数
*
* @param int $interval 间隔时间单位毫秒ms
* @return false|int 定时器ID失败返回false
*/
2022-03-21 23:28:57 +08:00
function zm_timer_tick(int $interval, callable $runnable)
2022-03-21 20:08:09 +08:00
{
if (zm_cid() === -1) {
return go(static function () use ($interval, $runnable) {
Console::debug('Adding extra timer tick of ' . $interval . ' ms');
Swoole\Timer::tick($interval, static function () use ($runnable) {
call_with_catch($runnable);
});
});
}
return Swoole\Timer::tick($interval, static function () use ($runnable) {
call_with_catch($runnable);
});
}
/**
* 执行函数并记录异常
*/
function call_with_catch(callable $callable): void
2022-03-13 22:47:11 +08:00
{
try {
$callable();
} catch (Exception $e) {
$error_msg = $e->getMessage() . ' at ' . $e->getFile() . '(' . $e->getLine() . ')';
Console::error(zm_internal_errcode('E00033') . 'Uncaught exception ' . get_class($e) . ': ' . $error_msg);
Console::trace();
} catch (Error $e) {
$error_msg = $e->getMessage() . ' at ' . $e->getFile() . '(' . $e->getLine() . ')';
Console::error(zm_internal_errcode('E00033') . 'Uncaught ' . get_class($e) . ': ' . $error_msg);
Console::trace();
}
}
2022-03-21 20:08:09 +08:00
/**
* 生成消息的哈希值
*/
function hash_message(array $message): string
2022-03-13 22:47:11 +08:00
{
2022-03-21 20:08:09 +08:00
return md5($message['user_id'] . '^' . $message['self_id'] . '^' . $message['message_type'] . '^' . ($message[$message['message_type'] . '_id'] ?? $message['user_id']));
2020-09-29 15:07:43 +08:00
}
2022-03-21 20:08:09 +08:00
/**
* 获取 Swoole Server 实例
*
* {@link Framework::$server} 一致
*/
2022-04-03 01:47:38 +08:00
function server(): Server
2022-03-13 22:47:11 +08:00
{
2020-09-29 15:07:43 +08:00
return Framework::$server;
2020-08-31 10:11:06 +08:00
}
2022-03-13 22:47:11 +08:00
/**
* 获取缓存当前框架pid的临时目录
2022-04-05 00:24:03 +08:00
*
2022-03-21 20:08:09 +08:00
* @internal
2022-03-13 22:47:11 +08:00
*/
function _zm_pid_dir(): string
{
global $_ZM_HASH;
if (!isset($_ZM_HASH)) {
$_ZM_HASH = md5(DataProvider::getWorkingDir());
}
2022-03-13 22:47:11 +08:00
return '/tmp/.zm_' . $_ZM_HASH;
}
/**
2022-03-21 20:08:09 +08:00
* 获取 ZMRobot 实例
*
* 随机返回一个 ZMRobot 实例,效果等同于 {@link ZMRobot::getRandom()}
*
* 在单机器人模式下,会直接返回该机器人实例。
2022-04-05 00:24:03 +08:00
*
* @throws RobotNotFoundException
*/
2022-03-21 20:08:09 +08:00
function bot(): ZMRobot
2022-03-13 22:47:11 +08:00
{
2022-03-21 20:08:09 +08:00
if (($conn = LightCacheInside::get('connect', 'conn_fd')) === -2) {
2021-06-16 00:17:30 +08:00
return OneBotV11::getRandom();
}
2022-03-21 20:08:09 +08:00
if ($conn !== -1) {
if (($obj = ManagerGM::get($conn)) !== null) {
2022-03-21 20:08:09 +08:00
return new ZMRobot($obj);
}
throw new RobotNotFoundException('单机器人连接模式可能连接了多个机器人!');
}
throw new RobotNotFoundException('没有任何机器人连接到框架!');
}
2020-12-25 16:40:02 +08:00
/**
2022-03-21 20:08:09 +08:00
* 获取指定连接类型的文件描述符ID
2020-12-25 16:40:02 +08:00
*/
2022-03-21 20:08:09 +08:00
function get_all_fd_of_type(string $type = 'default'): array
2022-03-13 22:47:11 +08:00
{
2020-12-25 16:40:02 +08:00
$fds = [];
foreach (ManagerGM::getAllByName($type) as $obj) {
2020-12-25 16:41:14 +08:00
$fds[] = $obj->getFd();
}
2020-12-25 16:40:02 +08:00
return $fds;
}
2022-03-21 20:08:09 +08:00
/**
* 获取原子计数器
*
* {@link ZMAtomic::get()} 一致
*/
function zm_atomic(string $name): ?Atomic
2022-03-13 22:47:11 +08:00
{
return ZMAtomic::get($name);
2021-02-21 22:17:34 +08:00
}
2022-03-21 20:08:09 +08:00
/**
* 生成 UUID
*/
function uuidgen(bool $uppercase = false): string
2022-03-13 22:47:11 +08:00
{
2021-02-21 22:17:34 +08:00
try {
$data = random_bytes(16);
} catch (Exception $e) {
return '';
2021-02-21 22:17:34 +08:00
}
$data[6] = chr(ord($data[6]) & 0x0F | 0x40);
$data[8] = chr(ord($data[8]) & 0x3F | 0x80);
2021-02-21 22:17:34 +08:00
return $uppercase ? strtoupper(vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4))) :
vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}
2022-03-21 20:08:09 +08:00
/**
* 获取框架运行的工作目录
*
* @example 例如你是从 /root/framework-starter/ 目录启动的框架vendor/bin/start server那么 working_dir() 返回的就是 /root/framework-starter。
*/
function working_dir(): string
2022-03-13 22:47:11 +08:00
{
return WORKING_DIR;
}
2022-03-21 20:08:09 +08:00
/**
* 更漂亮地输出变量值
*
* 可替代 {@link var_dump()}
*
* @param mixed $var
* @return array|mixed 返回传入的变量,传入多个变量则会返回数组
*/
2022-03-13 22:47:11 +08:00
function zm_dump($var, ...$moreVars)
{
VarDumper::dump($var);
foreach ($moreVars as $v) {
VarDumper::dump($v);
}
2022-03-21 20:08:09 +08:00
if (func_num_args() > 1) {
return func_get_args();
}
return $var;
}
2022-03-21 20:08:09 +08:00
/**
* 输出info日志
*
* {@link Console::info()} 一致
*
2022-04-02 23:37:22 +08:00
* @param mixed $obj
2022-03-21 20:08:09 +08:00
*/
function zm_info($obj): void
2022-03-13 22:47:11 +08:00
{
2021-11-02 16:01:24 +08:00
Console::info($obj);
}
2022-03-21 20:08:09 +08:00
/**
* 输出warning日志
*
* {@link Console::warning()} 一致
*
2022-04-02 23:37:22 +08:00
* @param mixed $obj
2022-03-21 20:08:09 +08:00
*/
function zm_warning($obj): void
2022-03-13 22:47:11 +08:00
{
2021-11-02 16:01:24 +08:00
Console::warning($obj);
}
2022-03-21 20:08:09 +08:00
/**
* 输出success日志
*
* {@link Console::success()} 一致
*
2022-04-02 23:37:22 +08:00
* @param mixed $obj
2022-03-21 20:08:09 +08:00
*/
function zm_success($obj): void
2022-03-13 22:47:11 +08:00
{
2021-11-02 16:01:24 +08:00
Console::success($obj);
}
2022-03-21 20:08:09 +08:00
/**
* 输出debug日志
*
* {@link Console::debug()} 一致
*
2022-04-02 23:37:22 +08:00
* @param mixed $obj
2022-03-21 20:08:09 +08:00
*/
function zm_debug($obj): void
2022-03-13 22:47:11 +08:00
{
2021-11-02 16:01:24 +08:00
Console::debug($obj);
}
2022-03-21 20:08:09 +08:00
/**
* 输出verbose日志
*
* {@link Console::verbose()} 一致
*
2022-04-02 23:37:22 +08:00
* @param mixed $obj
2022-03-21 20:08:09 +08:00
*/
function zm_verbose($obj): void
2022-03-13 22:47:11 +08:00
{
2021-11-02 16:01:24 +08:00
Console::verbose($obj);
}
2022-03-21 20:08:09 +08:00
/**
* 输出error日志
*
* {@link Console::error()} 一致
*
2022-04-02 23:37:22 +08:00
* @param mixed $obj
2022-03-21 20:08:09 +08:00
*/
function zm_error($obj): void
2022-03-13 22:47:11 +08:00
{
2021-11-02 16:01:24 +08:00
Console::error($obj);
}
2022-03-21 20:08:09 +08:00
/**
* 获取配置项
*
* {@link ZMConfig::get()} 一致
*
* @return mixed
*/
function zm_config(string $name, ?string $key = null)
2022-03-13 22:47:11 +08:00
{
2021-11-02 16:01:24 +08:00
return ZMConfig::get($name, $key);
}
2022-03-21 20:08:09 +08:00
/**
* 生成快速回复闭包
*
2022-04-02 23:37:22 +08:00
* @param mixed $reply
2022-03-21 20:08:09 +08:00
*/
function quick_reply_closure($reply): Closure
2022-03-13 22:47:11 +08:00
{
2022-03-21 20:08:09 +08:00
return static function () use ($reply) {
return $reply;
};
}
2021-06-16 00:17:30 +08:00
2022-03-21 20:08:09 +08:00
/**
* 获取内部错误码
*
2022-04-02 23:37:22 +08:00
* @param int|string $code
2022-03-21 20:08:09 +08:00
*/
2022-03-13 22:47:11 +08:00
function zm_internal_errcode($code): string
{
return "[ErrCode:{$code}] ";
2021-06-16 00:17:30 +08:00
}
2022-03-21 20:08:09 +08:00
if (!function_exists('chain')) {
define('CARRY', '{carry}');
/**
* 链式调用对象方法
*
* 如需使用上一步的返回值作为参数,请使用 CARRY 常量替换对应的参数值
*
* @param object $object 需要进行链式调用的对象
* @return object 链式操作对象,可当成传入的对象使用
*/
function chain(object $object): object
{
return new class($object) {
/**
* 最后一次执行的方法的返回值
*
* @var mixed
*/
protected $return;
/**
* 需要进行链式调用的对象
*
* @var object
*/
protected $wrapped;
/**
* 构造链式调用匿名类
*/
public function __construct(object $object)
{
$this->wrapped = $object;
}
/**
* 代理所有调用
*/
public function __call(string $name, array $arguments)
{
if (($index = array_search(CARRY, $arguments, true)) !== false) {
$arguments[$index] = $this->return;
}
$this->return = $this->wrapped->{$name}(...$arguments);
return $this;
}
/**
* 返回最后执行结果
*/
public function __toString()
{
return (string) $this->return;
}
/**
* 允许调用最后返回结果
*/
public function __invoke()
{
return $this->return;
}
/**
* 使用链式操作对象作为参数,执行回调
*/
public function tap(callable $callback): self
{
$callback($this->wrapped);
return $this;
}
};
}
}
if (!function_exists('stopwatch')) {
/**
* 执行回调函数并返回平均执行耗时
*
* @param int $times 执行次数
* @return float 平均执行耗时
*/
function stopwatch(callable $callback, int $times = 1): float
{
$total = 0;
for ($i = 0; $i < $times; ++$i) {
$start = microtime(true);
$callback();
$total += microtime(true) - $start;
}
return $total / $times;
}
}
/**
* 将可能为数组的参数转换为字符串
*
* 如传入字符串则为原样返回
*
* @param array|string $string_or_array
*/
function implode_when_necessary($string_or_array): string
{
return is_array($string_or_array) ? implode(', ', $string_or_array) : $string_or_array;
}
2022-04-05 00:24:03 +08:00
/**
* 获取容器(请求级)实例
*/
function container(): ContainerInterface
{
return Container::getInstance();
}
/**
* 解析类实例(使用容器)
*
2022-04-05 01:06:47 +08:00
* @template T
2022-05-04 22:25:42 +08:00
* @param class-string<T> $abstract
2022-04-05 01:14:06 +08:00
* @return Closure|mixed|T
2022-04-05 00:24:03 +08:00
*/
function resolve(string $abstract, array $parameters = [])
{
return Container::getInstance()->make($abstract, $parameters);
}
/**
* 获取容器实例
*
2022-04-05 01:06:47 +08:00
* @template T
2022-04-05 01:14:06 +08:00
* @param null|class-string<T> $abstract
* @return Closure|ContainerInterface|mixed|T
2022-04-05 00:24:03 +08:00
*/
function app(string $abstract = null, array $parameters = [])
{
if (is_null($abstract)) {
return container();
}
return resolve($abstract, $parameters);
}
2022-05-09 16:39:09 +08:00
/**
* 根据键名比较对象和数组
*
* @param object $object 对象
* @param array $array 数组
* @param array $keys 键名
*/
function compare_object_and_array_by_keys(object $object, array $array, array $keys): bool
{
foreach ($keys as $key) {
if (!isset($object->{$key}, $array[$key]) || $object->{$key} !== $array[$key]) {
return false;
}
}
return true;
}
2022-05-10 00:32:20 +08:00
function is_assoc_array(array $array): bool
{
return !empty($array) && array_keys($array) !== range(0, count($array) - 1);
}
2022-03-21 20:08:09 +08:00
/**
* 以下为废弃的函数,将于未来移除
*/
/**
* @deprecated 已废弃,请使用 {@link get_all_fd_of_type()}
*/
function getAllFdByConnectType(string $type = 'default'): array
{
return get_all_fd_of_type($type);
}
/**
* @param mixed $class_name
* @deprecated 已废弃,请使用 {@link get_class_path()}
*/
function getClassPath($class_name): ?string
{
return get_class_path($class_name);
}
/**
* @param mixed $msg
* @param mixed $ban_comma
* @deprecated 已废弃,请使用 {@link explode_msg()},参数有变
*/
function explodeMsg($msg, $ban_comma = false): array
{
if ($ban_comma) {
return explode_msg($msg, [' ']);
}
return explode_msg($msg);
}
/**
* @deprecated 已废弃,请使用 {@link current_connection_is()}
*/
function connectIsQQ(): bool
{
return current_connection_is('qq');
}
/**
* @deprecated 已废弃,请使用 {@link current_connection_is()}
*/
function connectIsDefault(): bool
{
return current_connection_is('default');
}
/**
* @param mixed $type
* @deprecated 已废弃,请使用 {@link current_connection_is()}
*/
function connectIs($type): bool
{
return current_connection_is($type);
}
/**
* @deprecated 已废弃,请使用 {@link get_annotations()}
*/
function getAnnotations(): array
{
return get_annotations();
}
/**
* @param mixed $pattern
* @param mixed $context
* @deprecated 已废弃,请使用 {@link match_args()}
*/
function matchArgs($pattern, $context)
{
return match_args($pattern, $context);
}
/**
* @param mixed $pattern
* @param mixed $context
* @deprecated 已废弃,请使用 {@link match_pattern()}
*/
function matchPattern($pattern, $context): bool
{
return match_pattern($pattern, $context);
}
/**
2022-04-02 23:37:22 +08:00
* @param string $message_type 消息类型
2022-03-21 20:08:09 +08:00
* @deprecated 已废弃,请使用 {@link get_onebot_target_id_name()}
*/
function onebot_target_id_name(string $message_type): string
{
return get_onebot_target_id_name($message_type);
}
/**
* @deprecated 已废弃,请直接使用 {@link call_with_catch()}
*/
function zm_go(callable $callable)
{
call_with_catch($callable);
}
/**
* @param mixed $v
* @deprecated 已废弃,请使用 {@link hash_message()}
*/
function zm_data_hash($v): string
{
return hash_message($v);
}