PHP 內建多個強大的預定義接口,讓對象能像數組、迭代器或可計數實體一樣工作。掌握這些接口能顯著提升代碼的靈活性與可讀性。本文詳細解析四大核心接口的機制與最佳實踐。
當對象實現 IteratorAggregate 時,foreach 將調用其 getIterator() 方法獲取一個 Traversable 實例進行遍歷,而非直接訪問公開屬性。
interface IteratorAggregate extends Traversable {
public function getIterator(): Traversable;
}
<?php
// 未實現接口:遍歷公開屬性
class My {
private $_data = ['a' => '燕睿濤', 'b' => 'yanruitao', 'c' => 'LULU'];
public function getIterator() { return new ArrayIterator($this->_data); }
}
$obj = new My;
foreach ($obj as $key => $value) { echo "$key => $value\n"; }
// 輸出:空(因屬性為 private)
<?php
// 實現接口:自定義遍歷邏輯
class My implements IteratorAggregate {
private $_data = ['a' => '燕睿濤', 'b' => 'yanruitao', 'c' => 'LULU'];
public function getIterator() { return new ArrayIterator($this->_data); }
}
$obj = new My;
foreach ($obj as $key => $value) { echo "$key => $value\n"; }
// 輸出:
// a => 燕睿濤
// b => yanruitao
// c => LULU
關鍵點:getIterator() 必須返回 Traversable 實例(如 ArrayIterator),否則拋出異常。
實現 Countable 後,count($obj) 將調用對象的 count() 方法,否則永遠返回 1。
interface Countable {
public function count(): int;
}
<?php
class CountMe { protected $_myCount = 3; public function count() { return $this->_myCount; } }
$countable = new CountMe();
echo count($countable); // 輸出 1(未實現接口)
<?php
class CountMe implements Countable { protected $_myCount = 3; public function count() { return $this->_myCount; } }
$countable = new CountMe();
echo count($countable); // 輸出 3
實現此接口後,可使用 $obj['key'] 語法進行讀寫、判斷存在性、刪除操作,底層自動映射到對應方法。
interface ArrayAccess {
public function offsetExists(mixed $offset): bool;
public function offsetGet(mixed $offset): mixed;
public function offsetSet(mixed $offset, mixed $value): void;
public function offsetUnset(mixed $offset): void;
}
<?php
class myObj implements ArrayAccess {
public function offsetSet($offset, $value) { echo "offsetSet : {$offset} => {$value}\n"; }
public function offsetExists($offset) { echo "offsetExists : {$offset}\n"; }
public function offsetUnset($offset) { echo "offsetUnset : {$offset}\n"; }
public function offsetGet($offset) { echo "offsetGet : {$offset}\n"; }
}
$obj = new myObj;
$obj[1] = '燕睿濤';
isset($obj['name']);
unset($obj['name']);
$obj['yrt'];
/* 輸出:
offsetSet : 1 => 燕睿濤
offsetExists : name
offsetUnset : name
offsetGet : yrt
*/
<?php
class myObj implements ArrayAccess {
private $_data = [];
public function offsetSet($offset, $value) { $this->_data[$offset] = $value; }
public function offsetExists($offset) { return isset($this->_data[$offset]); }
public function offsetUnset($offset) { unset($this->_data[$offset]); }
public function offsetGet($offset) { return $this->_data[$offset]; }
}
$obj = new myObj;
$obj['yrt'] = '燕睿濤';
var_dump($obj['yrt']); // string(9) "燕睿濤"
var_dump(isset($obj['yrt'])); // bool(true)
unset($obj['yrt']);
var_dump(isset($obj['yrt'])); // bool(false)
var_dump($obj['yrt']); // Notice: Undefined index: yrt
<?php
class myObj implements ArrayAccess, IteratorAggregate {
private $_data = [];
public function getIterator() { return new ArrayIterator($this->_data); }
// ... ArrayAccess 方法同上 ...
}
$obj = new myObj;
$obj['yrt'] = '燕睿濤'; $obj[1] = '燕睿濤'; $obj['name'] = '燕睿濤'; $obj['age'] = 23;
foreach ($obj as $key => $value) { echo "{$key} => {$value}\n"; }
/* 輸出:
yrt => 燕睿濤
1 => 燕睿濤
name => 燕睿濤
age => 23
*/
與 IteratorAggregate 委託外部迭代器不同,Iterator 要求類內部實現完整的迭代邏輯,適合複雜遍歷場景。
interface Iterator extends Traversable {
public function current(): mixed;
public function key(): scalar;
public function next(): void;
public function rewind(): void;
public function valid(): bool;
}
<?php
class myObj implements Iterator {
private $_data = [];
public function __construct(array $arr) { $this->_data = $arr; }
public function current() { return current($this->_data); }
public function key() { return key($this->_data); }
public function next() { next($this->_data); }
public function rewind() { reset($this->_data); }
public function valid() { return $this->key() !== null; } // 注意:值為 false 時不會中斷
}
$t = ['yrt' => '燕睿濤', 'name' => '燕睿濤', false, '燕睿濤'];
$obj = new myObj($t);
foreach ($obj as $key => $value) {
echo "{$key} => " . var_export($value, true) . "\n";
}
/* 輸出:
yrt => '燕睿濤'
name => '燕睿濤'
0 => false
1 => '燕睿濤'
*/
注意:valid() 判斷鍵名而非值,避免值為 false 導致提前終止。
| 接口 | 核心用途 | 關鍵方法 | 適用場景 |
|---|---|---|---|
| IteratorAggregate | 委託外部迭代器 | getIterator() | 簡單封裝數組/集合遍歷 |
| Countable | 自定義計數邏輯 | count() | 集合類、分頁對象 |
| ArrayAccess | 數組式語法訪問 | offsetGet/Set/Exists/Unset | 配置對象、數據容器 |
| Iterator | 完全控制迭代過程 | current/key/next/rewind/valid | 複雜數據流、資源游標 |
善用這些接口,能讓你的 PHP 類庫更符合語言習慣,提供優雅的 API 體驗。