mtphp 文档

辅助工具类(`Mtphp\Support\*`)

平台开发中反复手写的“纯工具”已统一实现于 mtphp/Support/ 下,零依赖、纯 PHP、不依赖任何扩展,可离线安装即用。它们彼此独立,既可在框架里直接用,也可脱离框架单独 require 后使用。

触发词:唯一 ID、UUID、雪花 ID、业务流水号、XML 互转、数据脱敏、树形、IP、限流、中文大写金额、CSV、重试。

28.1 Str —— 字符串

静态类 Mtphp\Support\Str:

方法说明
uuid4() / uuid7(?\DateTimeInterface)UUID v4(随机)/ v7(48 位毫秒时间戳前缀,时间有序,适合做主键,避免索引碎片)
ulid()26 位 Crockford Base32、字典序可排序
random($len=16, $alphabet=null)随机字符串(默认字母+数字)
camel/snake/kebab/studly命名风格互转
contains/startsWith/endsWith子串 / 前后缀判断(支持数组)
limit($s,$n,$end='...')安全截断(按字符数,不掉多字节)
replaceFirst/replaceLast替换首次 / 末次出现
before/after取分隔符前 / 后内容
slug($title,$sep='-')URL 友好 slug(仅保留字母数字,中文会被移除)
mask($s,$start,$end,$mask='*')保留前 $start 与后 $end 个字符,掩码中间段
isUuid/isUlid/isJson类型判断

Str::uuid7();                                  // 36 位时间有序 UUID,推荐做主键
Str::camel('hello_world');                     // helloWorld
Str::mask('13800001111', 3, 4);                // 138****1111

28.2 Id —— 唯一数 / 序号

静态类 Mtphp\Support\Id(Str 的 uuid 委托于此,避免重复实现):

方法说明
uuid4() / uuid7() / ulid()同 Str
nanoid($size=21)URL 安全随机串(Crockford 风格字母表)
shortId($length=12)Base62 短码
snowflake($workerId=null,$datacenterId=null)分布式 64 位 ID(41 位时间戳 + 10 位 worker/datacenter + 12 位序列),返回 int
serial($prefix='',$seq=0,$dateFormat='Ymd',$width=6)业务流水号 ORD-20261015-000001

Id::snowflake(1, 1);          // 分布式场景,需稳定 workerId
Id::serial('ORD-', 1);        // ORD-20261015-000001(前缀+日期+零填充序号)

28.3 Arr —— 数组

静态类 Mtphp\Support\Arr:点号路径读写、dot/undot 展平还原、only/except、divide、flatten、sortBy、crossJoin、shuffle(可选种子,便于测试复现)、pluck、isAssoc、wrap、forget。

Arr::get($data, 'user.profile.name', '默认');
Arr::dot(['a'=>['b'=>1]]);                     // ['a.b'=>1]
Arr::crossJoin([1,2],[3,4]);                  // [[1,3],[1,4],[2,3],[2,4]]

28.4 Xml —— XML 与数组互转

静态类 Mtphp\Support\Xml(基于内置 SimpleXML + DOMDocument):

$data = Xml::parse($xmlString);                // 微信/支付/第三方开放平台回调直接转数组
$xml  = Xml::toXml(['item'=>[['id'=>1],['id'=>2]]], 'root'); // 重复 <item>

28.5 Mask —— 数据脱敏

静态类 Mtphp\Support\Mask(隐私合规展示):phone/email/name/idCard/bankCard,以及通用 mask()。

Mask::phone('13800001111');     // 138****1111
Mask::email('zhangsan@example.com'); // z*******@example.com
Mask::name('张三丰');           // 张*丰
Mask::idCard('110101199001011234'); // 110101********1234
Mask::bankCard('6222021234567890'); // **** **** **** 7890

28.6 Tree —— 树形结构

静态类 Mtphp\Support\Tree:build(扁平列表→嵌套树)、flatten(树→扁平,去 children)、ancestors(祖先)、descendants(后代)、maxDepth。常用于部门 / 分类 / 菜单 / 权限树。

$tree = Tree::build($flatList, 'id', 'parent_id', 'children');
$desc = Tree::descendants($flatList, $rootId);

28.7 Filesystem —— 文件 / 路径

静态类 Mtphp\Support\Filesystem:join(路径拼接,保留绝对前导 /)、normalize(反斜杠转正、合并连续斜杠)、mimeFromExt、humanSize(1.2 MB)、ensureDir、get、put(自动建父目录)、tempName、delete、copy、move。

Filesystem::join('/var', 'www/', 'file.txt');  // /var/www/file.txt
Filesystem::humanSize(1234567);                // 1.18 MB

28.8 Date —— 日期时间

静态类 Mtphp\Support\Date(纯包 DateTimeImmutable,不引入 Carbon):format、humanize(“刚刚”/“3分钟前”/“2天前”)、startOfDay/endOfDay、between、diffInSeconds/Minutes/Hours/Days、isToday/isPast/isFuture、add。

Date::humanize(strtotime('-3 minutes'));       // 3分钟前
Date::startOfDay(time());                      // 当日 00:00:00 时间戳

28.9 Csv —— CSV 读写

静态类 Mtphp\Support\Csv:parse/parseFile(首行作表头→关联数组列表)、toCsv(@header 显式表头,或自动取首行键)。

$rows = Csv::parse($csvString);                // 后台导入
$csv  = Csv::toCsv($list);                      // 后台导出

28.10 Number —— 数字 / 金额

静态类 Mtphp\Support\Number:thousands(千分位)、currency、percent、safeDivide(分母为 0 返回默认)、wan(万 / 亿单位)、rmbUpperCase(中文大写金额)。

Number::rmbUpperCase(1234.56);  // 壹仟贰佰叁拾肆圆伍角陆分
Number::wan(123456789);         // 1.23亿
Number::currency(1234.5);       // ¥1,234.50

28.11 Hash —— 哈希 / 签名 / 口令

静态类 Mtphp\Support\Hash:hmac、bcrypt/verify(口令)、token(随机令牌)、sign/verifySign(载荷签名 + 可选有效期)、signedQuery/verifySignedQuery(签名查询串,用于临时免登录链接)。

$hash = Hash::bcrypt('password');  Hash::verify('password', $hash);
$url  = '/download?'.Hash::signedQuery(['file'=>$fid], $secret, 3600);

28.12 Encoding / Ip / Url / Html

28.13 RateLimiter —— 通用限流

Mtphp\Support\RateLimiter(从 Throttle 中间件抽离,基于缓存驱动的固定窗口):tooManyAttempts、attempts、hit、clear、attempt(一键式)。Throttle 中间件内部已改用它。

$limiter = new RateLimiter(cache());
if ($limiter->tooManyAttempts('sms:'.$ip, 5, 60)) { abort(429, '发送过于频繁'); }
$limiter->hit('sms:'.$ip, 60);

28.14 Macroable —— 运行时扩展

Mtphp\Support\Macroable trait 已应用于 Str、Arr、Collection:可在不改动框架源码的情况下动态挂载方法。

Str::macro('rev', fn (string $s) => strrev($s));
Str::rev('abc');                 // cba

28.15 全局助手 retry()

mtphp/helpers.php 新增全局函数 retry($times, $callback, $delayMs=0, $catch=[\Throwable::class]):最多尝试 $times 次,仅当抛出 $catch 所列类型时重试(其余异常直接抛出),可选毫秒退避;回调接收当前尝试次数(0 起)。

$resp = retry(3, fn () => http('https://api')->get('/x'), 200);

28.16 校验规则扩展(中国)

Validator 内置了三条带校验位的中国规则,无需再用 extend() 自实现:

Validator::make($input, ['mobile'=>'required|mobile_cn','id'=>'required|id_card'])->validate();

以上工具均配套零依赖单测 tests/SupportUtilsTest.php(32 用例 / 147 断言),php tests/run.php SupportUtilsTest 单独跑;全量 php tests/run.php 也已通过。

29. 集成胶水层(Storage / JWT / 统一 API 响应)

真实业务里最高频、却最该“框架统一掉”的三块——对象存储、JWT 鉴权、API 响应信封——mtphp 现已内置,零依赖、可插拔。

29.1 统一存储抽象 Storage

屏蔽本地磁盘与对象存储(七牛 / 阿里云 OSS / 腾讯云 COS)的差异,业务层只依赖接口。

// 默认盘(config/storage.php 的 default)
storage()->put('avatars/1.jpg', $binary);
$content = storage()->get('avatars/1.jpg');
$url     = storage()->url('avatars/1.jpg');   // 公开访问 URL

// 指定盘
storage('qiniu')->put('x.jpg', $binary);

接口 Mtphp\Storage\StorageInterface:put / get / exists / delete / size / mime / url / tempUrl。框架内置 LocalDriver(零依赖);云驱动不在框架内内置(引入各云 SDK 会破坏零依赖),用 StorageManager::extend 注册即可:

use Mtphp\Storage\StorageManager;
StorageManager::extend('qiniu', fn (array $cfg) => new App\Storage\QiniuDriver($cfg));

QiniuDriver 只需实现 StorageInterface(引入对应 composer SDK 后包装),注册后即可 storage('qiniu')->... 使用,业务代码零改动切换。配置 config/storage.php:default + disks[local][root|url]。

29.2 标准 JWT 鉴权

Mtphp\Auth\Jwt 零依赖实现,支持 HS256/384/512(对称)与 RS256/384/512(非对称,私钥签、公钥验),自动校验 exp/nbf/iat。

$token = jwt()->encode(['uid' => 1, 'role' => 'admin']);   // 默认 HS256
$p     = jwt()->decode($token);                              // 成功返回载荷,失败 null

// 微服务非对称:私钥签发、公钥校验
$token = jwt()->encode($payload, $privateKeyPem, 'RS256');
$p     = jwt()->decode($token, $publicKeyPem, 'RS256');

密钥优先级:显式传入 > config/jwt.secret > config/app.key。中间件 Mtphp\Http\Middleware\JwtAuth 从 Authorization: Bearer <token> 取令牌并挂载到 $request->authUser(),失败时返回 401;按路由/路由组挂载即可(同 AuthApi)。配置 config/jwt.php:secret / alg / ttl。

与既有的无状态 opaque Token(AuthApi + Mtphp\Auth\Token,支持吊销名单)并存:JWT 适合标准互操作 / 跨服务,opaque Token 适合需要服务端吊销的场景。

29.3 统一 API 响应信封

前后端分离项目几乎每个接口都要返回统一结构的 JSON,框架提供三个助手(code=0 成功,非 0 失败):

return api_success($list, '获取成功');                 // {code:0,message,data}
return api_error('参数错误', 1001);                     // {code:1001,message,data:null} HTTP 400
return api_error('未登录', 401, null, 401);             // 第四参为 HTTP 状态码
return api_paginate(DB::table('users')->paginate(15));  // data=当前页, meta={total,per_page,current_page,last_page}

配套零依赖单测 tests/IntegrationGlueTest.php(16 用例 / 43 断言),php tests/run.php IntegrationGlueTest 单独跑;全量 php tests/run.php 也已通过。