PHP数组与SPL数据结构

PHP数组与SPL数据结构 引言PHP的数组是一种极为灵活的数据结构结合SPLStandard PHP Library提供的专业数据容器可以高效处理各种数据组织需求。本文将深入探讨数组的高级操作和SPL数据结构的实战应用。数组高级操作PHP数组本质上是有序的哈希表支持丰富的内部函数操作。class ArrayMaster{// 深度合并递归合并保留所有键public static function deepMerge(array ...$arrays): array{$result [];foreach ($arrays as $array) {foreach ($array as $key $value) {if (isset($result[$key]) is_array($result[$key]) is_array($value)) {$result[$key] self::deepMerge($result[$key], $value);} else {$result[$key] $value;}}}return $result;}// 深度 diff递归比较差异public static function deepDiff(array $a, array $b): array{$diff [];foreach ($a as $key $value) {if (!array_key_exists($key, $b)) {$diff[$key] [- $value];} elseif (is_array($value) is_array($b[$key])) {$nested self::deepDiff($value, $b[$key]);if (!empty($nested)) {$diff[$key] $nested;}} elseif ($value ! $b[$key]) {$diff[$key] [- $value, $b[$key]];}}foreach ($b as $key $value) {if (!array_key_exists($key, $a)) {$diff[$key] [ $value];}}ksort($diff);return $diff;}// 数组转树形结构public static function toTree(array $items, string $idKey id, string $parentKey parent_id, string $childrenKey children): array{$tree [];$map [];foreach ($items as $item) {$item[$childrenKey] [];$map[$item[$idKey]] $item;}unset($item);foreach ($map as $node) {$parentId $node[$parentKey];if ($parentId isset($map[$parentId])) {$map[$parentId][$childrenKey][] $node;} else {$tree[] $node;}}unset($node);return $tree;}// 树形结构转回数组public static function fromTree(array $tree, string $childrenKey children): array{$items [];foreach ($tree as $node) {$children $node[$childrenKey] ?? [];unset($node[$childrenKey]);$items[] $node;if (!empty($children)) {$items array_merge($items, self::fromTree($children, $childrenKey));}}return $items;}// 分组public static function groupBy(array $items, callable|string $key): array{$groups [];foreach ($items as $item) {$groupKey is_string($key) ? $item[$key] : $key($item);$groups[$groupKey][] $item;}return $groups;}// 索引数组用指定字段做键public static function indexBy(array $items, callable|string $key): array{$indexed [];foreach ($items as $item) {$idx is_string($key) ? $item[$key] : $key($item);$indexed[$idx] $item;}return $indexed;}// 数据透视public static function pivot(array $items, string $rowKey, string $colKey, string $valueKey): array{$result [];foreach ($items as $item) {$row $item[$rowKey];$col $item[$colKey];$val $item[$valueKey];$result[$row][$col] $val;}return $result;}// 笛卡尔积public static function cartesian(array ...$arrays): array{if (empty($arrays)) return [[]];$first array_shift($arrays);$rest self::cartesian(...$arrays);$result [];foreach ($first as $item) {foreach ($rest as $combo) {$result[] array_merge([$item], $combo);}}return $result;}// 数组转对象递归public static function toObject(array $array): object{return json_decode(json_encode($array));}// 对象转数组递归public static function toArray(object $object): array{return json_decode(json_encode($object), true);}// 数组拍平public static function flatten(array $array, int $depth INF): array{$result [];foreach ($array as $item) {if (is_array($item) $depth 0) {$result array_merge($result, self::flatten($item, $depth - 1));} else {$result[] $item;}}return $result;}// 按列排序public static function sortByColumn(array $array, string $column, int $direction SORT_ASC): void{$values array_column($array, $column);array_multisort($values, $direction, $array);}// 查找并更新可变public static function updateWhere(array $array, callable $condition, callable $updater): void{foreach ($array as $item) {if ($condition($item)) {$item $updater($item);}}}// 数组子集public static function pick(array $array, array $keys): array{return array_intersect_key($array, array_flip($keys));}// 排除指定键public static function omit(array $array, array $keys): array{return array_diff_key($array, array_flip($keys));}// 随机取样不同权重的概率选择public static function weightedRandom(array $items, array $weights): mixed{$total array_sum($weights);$random mt_rand(1, $total * 100) / 100;$cumulative 0;foreach ($items as $i $item) {$cumulative $weights[$i];if ($random $cumulative) {return $item;}}return end($items);}}// 树形结构测试$categories [[id 1, name Electronics, parent_id 0],[id 2, name Computers, parent_id 1],[id 3, name Laptops, parent_id 2],[id 4, name Phones, parent_id 1],[id 5, name Accessories, parent_id 2],];$tree ArrayMaster::toTree($categories);printf(Tree: %s\n, json_encode($tree, JSON_PRETTY_PRINT));// 数据透视$sales [[product A, month Jan, amount 100],[product A, month Feb, amount 150],[product B, month Jan, amount 200],[product B, month Feb, amount 250],];$pivot ArrayMaster::pivot($sales, product, month, amount);print_r($pivot);// 笛卡尔积$colors [red, blue];$sizes [S, M, L];$cartesian ArrayMaster::cartesian($colors, $sizes);printf(Cartesian product: %s\n, json_encode($cartesian));// SPL 数据结构class SplDataStructureDemo{// SplStack — 栈后进先出public static function stack(): void{$stack new SplStack();$stack-push(first);$stack-push(second);$stack-push(third);printf(Stack top: %s\n, $stack-top());printf(Stack pop: %s\n, $stack-pop());printf(Stack count: %d\n, $stack-count());// 迭代foreach ($stack as $item) {printf( %s\n, $item);}}// SplQueue — 队列先进先出public static function queue(): void{$queue new SplQueue();$queue-enqueue(first);$queue-enqueue(second);$queue-enqueue(third);printf(Queue dequeue: %s\n, $queue-dequeue());printf(Queue dequeue: %s\n, $queue-dequeue());printf(Queue count: %d\n, $queue-count());}// SplMaxHeap / SplMinHeap — 堆public static function heap(): void{$maxHeap new SplMaxHeap();$maxHeap-insert(10);$maxHeap-insert(5);$maxHeap-insert(20);$maxHeap-insert(15);printf(Max heap extract:\n);while (!$maxHeap-isEmpty()) {printf( %d\n, $maxHeap-extract());}$minHeap new SplMinHeap();$minHeap-insert(10);$minHeap-insert(5);$minHeap-insert(20);printf(Min heap extract:\n);while (!$minHeap-isEmpty()) {printf( %d\n, $minHeap-extract());}}// SplPriorityQueue — 优先队列public static function priorityQueue(): void{$pq new SplPriorityQueue();$pq-insert(low, 1);$pq-insert(high, 10);$pq-insert(medium, 5);$pq-insert(urgent, 100);printf(Priority queue:\n);while (!$pq-isEmpty()) {printf( %s\n, $pq-extract());}}// SplFixedArray — 固定长度数组public static function fixedArray(): void{$size 1000000;$start memory_get_usage(true);$regular array_fill(0, $size, 0);$memoryRegular memory_get_usage(true) - $start;unset($regular);$start memory_get_usage(true);$fixed new SplFixedArray($size);for ($i 0; $i $size; $i) {$fixed[$i] $i;}$memoryFixed memory_get_usage(true) - $start;printf(SplFixedArray memory: %.2f MB vs array %.2f MB\n,$memoryFixed / 1024 / 1024,$memoryRegular / 1024 / 1024);foreach ($fixed as $value) {}}// SplObjectStorage — 对象存储public static function objectStorage(): void{$storage new SplObjectStorage();$obj1 new stdClass(); $obj1-id 1;$obj2 new stdClass(); $obj2-id 2;$obj3 new stdClass(); $obj3-id 3;$storage-attach($obj1, [name Alice]);$storage-attach($obj2, [name Bob]);$storage-attach($obj3, [name Charlie]);printf(Object storage contains obj1: %s\n, $storage-contains($obj1) ? yes : no);printf(Object storage count: %d\n, $storage-count());foreach ($storage as $obj) {printf( Object: %s\n, $obj-id);}}// SplDoublyLinkedList — 双向链表public static function linkedList(): void{$list new SplDoublyLinkedList();$list-push(first);$list-push(second);$list-push(third);// 双向遍历$list-setIteratorMode(SplDoublyLinkedList::IT_MODE_FIFO);printf(Forward:\n);foreach ($list as $item) {printf( %s\n, $item);}$list-setIteratorMode(SplDoublyLinkedList::IT_MODE_LIFO);printf(Reverse:\n);foreach ($list as $item) {printf( %s\n, $item);}// 中间插入$list-add(1, inserted);printf(After insert at index 1:\n);$list-setIteratorMode(SplDoublyLinkedList::IT_MODE_FIFO);foreach ($list as $item) {printf( %s\n, $item);}}}SplDataStructureDemo::stack();SplDataStructureDemo::queue();SplDataStructureDemo::heap();SplDataStructureDemo::priorityQueue();SplDataStructureDemo::objectStorage();// 自定义 Comparatorsclass PriorityTask{public function __construct(public string $name,public int $priority,public int $timestamp,) {}}class TaskPriorityComparator{public static function compare(PriorityTask $a, PriorityTask $b): int{// 优先级高的先执行if ($a-priority ! $b-priority) {return $a-priority $b-priority;}// 同等优先级先来先执行return $a-timestamp $b-timestamp;}}class OrderedTaskQueue extends SplPriorityQueue{public function compare(mixed $priority1, mixed $priority2): int{return $priority1 $priority2;}}// 用 SplMinHeap 实现 TopKclass TopK{private SplMinHeap $heap;private int $k;public function __construct(int $k){$this-k $k;$this-heap new SplMinHeap();}public function add(mixed $value): void{if ($this-heap-count() $this-k) {$this-heap-insert($value);} elseif ($value $this-heap-top()) {$this-heap-extract();$this-heap-insert($value);}}public function get(): array{$result [];while (!$this-heap-isEmpty()) {array_unshift($result, $this-heap-extract());}return $result;}}$topK new TopK(3);foreach ([5, 2, 8, 1, 9, 3, 7, 4, 6] as $n) {$topK-add($n);}printf(Top 3: %s\n, implode(, , $topK-get()));// LRU Cache 实现class LRUCache{private int $capacity;private array $cache [];private SplDoublyLinkedList $order;public function __construct(int $capacity){$this-capacity $capacity;$this-order new SplDoublyLinkedList();}public function get(mixed $key): mixed{if (!isset($this-cache[$key])) {return null;}$this-touch($key);return $this-cache[$key][value];}public function put(mixed $key, mixed $value): void{if (isset($this-cache[$key])) {$this-cache[$key][value] $value;$this-touch($key);return;}if (count($this-cache) $this-capacity) {$this-evict();}$this-order-push($key);$this-cache[$key] [value $value, node $this-order-key()];}private function touch(mixed $key): void{// 移到末尾最近使用$this-order-push($key);unset($this-cache[$key][node]);$this-cache[$key][node] $this-order-key();}private function evict(): void{// 从链表头部移除最久未使用的$this-order-rewind();$lruKey $this-order-current();$this-order-shift();unset($this-cache[$lruKey]);}public function count(): int{return count($this-cache);}}$lru new LRUCache(3);$lru-put(a, 1);$lru-put(b, 2);$lru-put(c, 3);$lru-get(a);$lru-put(d, 4);printf(LRU cache count: %d\n, $lru-count());printf(LRU cache get a: %d\n, $lru-get(a));printf(LRU cache get b: %s\n, $lru-get(b) ?? evicted);// 去重队列class UniqueQueue{private SplQueue $queue;private \SplObjectStorage $set;public function __construct(){$this-queue new SplQueue();$this-set new SplObjectStorage();}public function enqueue(object $item): void{if (!$this-set-contains($item)) {$this-queue-enqueue($item);$this-set-attach($item);}}public function dequeue(): ?object{if ($this-queue-isEmpty()) {return null;}$item $this-queue-dequeue();$this-set-detach($item);return $item;}public function count(): int{return $this-queue-count();}}// 分页器实现class Paginator{private array $items;private int $perPage;private int $currentPage;private int $totalItems;public function __construct(array $items, int $perPage 15, int $currentPage 1){$this-items $items;$this-perPage max(1, $perPage);$this-currentPage max(1, $currentPage);$this-totalItems count($items);}public function getItems(): array{$offset ($this-currentPage - 1) * $this-perPage;return array_slice($this-items, $offset, $this-perPage);}public function getTotalPages(): int{return (int)ceil($this-totalItems / $this-perPage);}public function hasPrevious(): bool{return $this-currentPage 1;}public function hasNext(): bool{return $this-currentPage $this-getTotalPages();}public function getPageRange(int $range 2): array{$totalPages $this-getTotalPages();$start max(1, $this-currentPage - $range);$end min($totalPages, $this-currentPage $range);$pages [];for ($i $start; $i $end; $i) {$pages[] $i;}return $pages;}public function toArray(): array{return [items $this-getItems(),pagination [current_page $this-currentPage,per_page $this-perPage,total $this-totalItems,total_pages $this-getTotalPages(),has_previous $this-hasPrevious(),has_next $this-hasNext(),],];}}$allItems range(1, 100);$paginator new Paginator($allItems, 10, 3);printf(Page 3 items: %s\n, implode(, , $paginator-getItems()));// 集合操作class Set{private array $elements [];public function __construct(array $elements []){foreach ($elements as $e) {$this-add($e);}}public function add(mixed $element): void{$hash $this-hash($element);$this-elements[$hash] $element;}public function remove(mixed $element): void{unset($this-elements[$this-hash($element)]);}public function contains(mixed $element): bool{return isset($this-elements[$this-hash($element)]);}public function union(Set $other): Set{$result new Set($this-toArray());foreach ($other-toArray() as $e) {$result-add($e);}return $result;}public function intersect(Set $other): Set{$result new Set();foreach ($this-elements as $e) {if ($other-contains($e)) {$result-add($e);}}return $result;}public function diff(Set $other): Set{$result new Set();foreach ($this-elements as $e) {if (!$other-contains($e)) {$result-add($e);}}return $result;}public function toArray(): array{return array_values($this-elements);}public function count(): int{return count($this-elements);}private function hash(mixed $element): string{if (is_object($element)) {return spl_object_hash($element);}return serialize($element);}}$a new Set([1, 2, 3, 4]);$b new Set([3, 4, 5, 6]);printf(Union: %s\n, implode(, , $a-union($b)-toArray()));printf(Intersect: %s\n, implode(, , $a-intersect($b)-toArray()));printf(Diff (a-b): %s\n, implode(, , $a-diff($b)-toArray()));// array_walk_recursive 深度处理class DeepProcessor{public static function apply(array $array, callable $fn): void{array_walk_recursive($array, function ($value, $key) use ($fn) {$fn($value, $key);});}public static function toUtf8(array $array): array{$result [];foreach ($array as $key $value) {if (is_string($value)) {$result[$key] mb_convert_encoding($value, UTF-8, auto);} elseif (is_array($value)) {$result[$key] self::toUtf8($value);} else {$result[$key] $value;}}return $result;}}$nested [name Alice,info [bio PHP Developer,tags [php, laravel],],];DeepProcessor::apply($nested, function ($value, $key) {if (is_string($value)) {$value strtoupper($value);}});print_r($nested);