PHP 原生數組功能強大,但在需要強類型、面向對象風格操作集合時,參考 C# ArrayList 設計一個封裝類能提升代碼可讀性與複用性。本文實現一個功能完整的 ArrayList 類。
class ArrayList implements IteratorAggregate, Countable, ArrayAccess {
private array $items = [];
public function __construct(array $items = []) {
$this->items = array_values($items);
}
// 基礎操作
public function add(mixed $element): self {
$this->items[] = $element;
return $this; // 支持鏈式調用
}
public function get(int $index): mixed {
if (!isset($this->items[$index])) {
throw new OutOfBoundsException("Index $index 不存在");
}
return $this->items[$index];
}
public function set(int $index, mixed $value): self {
if (!isset($this->items[$index])) {
throw new OutOfBoundsException("Index $index 不存在");
}
$this->items[$index] = $value;
return $this;
}
public function removeAt(int $index): mixed {
if (!isset($this->items[$index])) {
throw new OutOfBoundsException("Index $index 不存在");
}
$value = $this->items[$index];
unset($this->items[$index]);
$this->items = array_values($this->items); // 重新索引
return $value;
}
public function remove(mixed $value): bool {
$key = array_search($value, $this->items, true);
if ($key === false) return false;
$this->removeAt($key);
return true;
}
public function clear(): self {
$this->items = [];
return $this;
}
// 查詢操作
public function contains(mixed $value): bool {
return in_array($value, $this->items, true);
}
public function indexOf(mixed $value): int {
return array_search($value, $this->items, true) ?? -1;
}
public function lastIndexOf(mixed $value): int {
$keys = array_keys($this->items, $value, true);
return $keys ? end($keys) : -1;
}
// 狀態屬性
public function count(): int {
return count($this->items);
}
public function isEmpty(): bool {
return empty($this->items);
}
public function toArray(): array {
return $this->items;
}
// 迭代器支持
public function getIterator(): Traversable {
return new ArrayIterator($this->items);
}
// ArrayAccess 支持
public function offsetExists(mixed $offset): bool {
return isset($this->items[$offset]);
}
public function offsetGet(mixed $offset): mixed {
return $this->get($offset);
}
public function offsetSet(mixed $offset, mixed $value): void {
if ($offset === null) {
$this->add($value);
} else {
$this->set($offset, $value);
}
}
public function offsetUnset(mixed $offset): void {
$this->removeAt($offset);
}
// 實用方法
public function filter(callable $callback): self {
return new self(array_values(array_filter($this->items, $callback)));
}
public function map(callable $callback): self {
return new self(array_map($callback, $this->items));
}
public function slice(int $offset, int $length = null): self {
return new self(array_slice($this->items, $offset, $length));
}
public function reverse(): self {
return new self(array_reverse($this->items));
}
public function shuffle(): self {
$items = $this->items;
shuffle($items);
return new self($items);
}
// 靜態工廠
public static function create(array $items = []): self {
return new self($items);
}
public static function range(int $start, int $end, int $step = 1): self {
return new self(range($start, $end, $step));
}
}
$list = ArrayList::create(['apple', 'banana', 'orange']);
$list->add('grape')
->add('mango');
echo $list->count(); // 5
echo $list[1]; // banana (ArrayAccess)
$list[1] = 'blueberry'; // 修改
foreach ($list as $fruit) { // IteratorAggregate
echo $fruit . PHP_EOL;
}
$filtered = $list->filter(fn($f) => strlen($f) > 6); // 過濾長度>6
$upper = $list->map(fn($f) => strtoupper($f)); // 映射轉換
// 類 C# 風格
$numbers = ArrayList::range(1, 10);
$evens = $numbers->filter(fn($n) => $n % 2 === 0);
IteratorAggregate、Countable、ArrayAccess,原生支持 foreach、count()、[] 操作$this,支持流暢接口filter、map、slice 返回新實例,避免副作用OutOfBoundsException,符合 PHP 標準mixed 類型提示,IDE 友好| 操作 | 原生數組 | ArrayList |
|---|---|---|
| 添加元素 | $arr[] = $v | $list->add($v) |
| 刪除元素 | unset($arr[$i]) + array_values | $list->removeAt($i) |
| 查找索引 | array_search($v, $arr) | $list->indexOf($v) |
| 鏈式過濾 | 需臨時變量 | $list->filter(...)->map(...) |
| 類型安全 | 無 | 可擴展泛型版本 |
class ArrayList<T> (需註解或工具支持)onChange 回調,監聽集合變更JsonSerializable、序列化存儲封裝集合類不僅是語法糖,更能在團隊中統一代碼風格,減少邊界錯誤。