first commit

This commit is contained in:
2026-01-25 18:18:09 +08:00
commit 509312e604
8136 changed files with 2349298 additions and 0 deletions

163
Serializers/Serializer.php Normal file
View File

@ -0,0 +1,163 @@
<?php
namespace app\serializers;
class Serializer
{
/* ========= 规则存储 ========= */
protected array $handlerTrie = [];
protected array $removeTrie = [];
protected array $appendRules = [];
public function __construct(
protected array|null $source = null
) {}
/* ========= API ========= */
public function handle(string $path, callable $fn): static
{
$this->insertTrie($this->handlerTrie, explode('.', $path), $fn);
return $this;
}
public function remove(string $path): static
{
$this->insertTrie($this->removeTrie, explode('.', $path), true);
return $this;
}
/**
* 节点级追加path 指向节点)
*/
public function append(string $path, callable $fn): static
{
$this->appendRules[] = [
'path' => explode('.', $path),
'fn' => $fn,
];
return $this;
}
/* ========= 执行 ========= */
public function serialize(): array
{
$data = $this->source ?? [];
// Phase 1字段级Trie
$this->walkTrie($data, $this->handlerTrie, $this->removeTrie);
// Phase 2节点级append
$this->applyAppend($data);
return $data;
}
/* ========= Phase 1 ========= */
protected function walkTrie(
&$node,
array $handlerNode,
array $removeNode
): void {
if (!is_array($node)) return;
foreach ($node as $key => &$value) {
// list不消费 trie
if (is_int($key)) {
$this->walkTrie($value, $handlerNode, $removeNode);
continue;
}
$nextHandler = $handlerNode[$key] ?? [];
$nextRemove = $removeNode[$key] ?? [];
// 删除优先
if (isset($nextRemove['_end'])) {
unset($node[$key]);
continue;
}
// 修改字段
if (isset($nextHandler['_fn'])) {
$value = ($nextHandler['_fn'])($value);
}
if (is_array($value)) {
$this->walkTrie($value, $nextHandler, $nextRemove);
}
}
}
/* ========= Phase 2 ========= */
protected function applyAppend(array &$data): void
{
foreach ($this->appendRules as $rule) {
$this->walkAppend($data, $rule['path'], $rule['fn']);
}
}
protected function walkAppend(
&$node,
array $path,
callable $fn
): void {
if (!is_array($node)) return;
// 命中节点
if (empty($path)) {
if (!$this->isList($node)) {
$fn($node);
}
return;
}
$key = array_shift($path);
if ($this->isList($node)) {
foreach ($node as &$item) {
$this->walkAppend($item, array_merge([$key], $path), $fn);
}
return;
}
if (isset($node[$key])) {
$this->walkAppend($node[$key], $path, $fn);
}
}
/* ========= Trie ========= */
protected function insertTrie(array &$trie, array $path, $value): void
{
$node = &$trie;
foreach ($path as $segment) {
if (!isset($node[$segment])) {
$node[$segment] = [];
}
$node = &$node[$segment];
}
if (is_callable($value)) {
$node['_fn'] = $value;
} else {
$node['_end'] = true;
}
}
protected function isList(array $arr): bool
{
return array_keys($arr) === range(0, count($arr) - 1);
}
}