PHP 有預定義一些 interface 及 class,妥善運用這些類別與介面,有助於讓標準函式或敘述式使用它們,也易於讓其它開發者理解。
實現了 Traversable 的 class 表示它可以被 foreach 。
Iterator 或 IteratorAggregate 的 interface 中被繼承instanceof 做搭配if( is_array( $items ) || $items instanceof Traversable ) {
// 表示 $items 可以用 foreach
foreach ($items as $item) { }
}
Iterator 又稱「迭代器」,這是 Traversable 的具現化之一。
Iterator 需要實現五個 methods
current(): mixed:取得目前的項目key(): scalar:取得目前項目的索引next(): void:取得下一個項目rewind(): void:回到第一個項目valid(): bool:確認目前位置是否有效,通常在 next() 或 rewind() 之後使用class DemoIterator implements Iterator
{
private $position = 0;
private $data = ['one', 'two', 'three'];
public function currnet()
{
return $this->data[$position];
}
public function key()
{
return $this->position;
}
public function next()
{
$this->position++;
}
public function rewind()
{
$this->position = 0;
}
public function valid()
{
return isset($this->data[$this->position]);
}
}
IteratorAggregate 又稱「聚合迭代器」,是另一個 Traversable 的具現化。
IteratorAggregate 需要實現一個 method:
getIterator(): Traversable:直接回傳具有 Traversable 的 Class,它有助於整合多個 Iterator 或其它實現了 Traversable 的 Class。class DemoIteratorAggregate implements IteratorAggregate
{
private $data1;
private $data2;
public function __construct()
{
$this->data1 = [1, 2, 3];
$this->data2 = new ArrayIterator([4, 5, 6]);
}
public function getIterator()
{
return new ArrayIterator([$this->data1, $this->data2]);
}
}
Throwable 表示該 Class 可被 throw,這實現於 Error 及 Exception(PHP 7 之後,內部 Error 會被當作一個可被 catch 存在)
通常 Throwable 不會自行實現,因為通常都是建立 Exception,但與 Traversable 不同 Throwable 是可以被直接拿來使用的。
try {
} catch(Exception $e) {
// 表示丟出 Exception,這通常是出現一些邏輯層的問題
} catch (Error $e) {
// 表示丟出 Error,這通常是語法上具有問題(例如 type error)
}
// 我們可以將上敘述式簡化為
try {
} catch (Throwable $e) {
}
ArrayAccess 表示該類別所建立出來的變數可以像 array 一樣直接使用 offset 存取。
ArrayAccess 需要實現四個 methods:
offsetExists(mixed $offset): bool:確認 offset 是否存在offsetGet(mixed $offset): mixed:取得該 offset 所在之值offsetSet(mixed $offset, mixed $value): void:為指定的 offset 設定 valueoffsetUnset(mixed $offset): void:移除指定的 offsetclass DemoArrayAccess implements ArrayAccess
{
private $data = [1, 2, 3];
public function offsetExists($offset)
{
return isset($this->data[$offset]);
}
public function offsetGet($offset)
{
return $this->data[$offset];
}
public function offsetSet($offset, $value)
{
$offset === null
? $this->data[] = $value;
: $this->data[$offset] = $value;
}
public function offsetUnset($offset)
{
unset($this->data[$offset]);
}
}
Serializable 表示此 Class 可以被「序列化」,序列化表示將一個 Class 的資訊轉為 string,有需要時可以利用該 string 還原回原本的 Class:例如將一個 class 做 json_encode() 就是一種序列化,它只要再被 json_decode() 就可以還原回來。
值得注意的是,如果 Class 有實現 __sleep() 及 __wakeup() 再實現 Serializable,__sleep() 及 __wakeup() 會失效。
Serializable 需要實現兩個 methods:
serialize(): string:表示序列化所需的操作unserialize(string $serialized): void:表示反序列化時的操作class DemoSerializable implements Serializable
{
private $data = 'My Data';
public function serialize()
{
return $this->data;
}
public function unserialize(string $serialized)
{
$this->data = $serialized;
}
}
$obj = new DemoSerializable();
$serialized = serialize($obj);
$unserialized = unserialize($obj);
Closure 主要用於表示匿名函式。
$a = function () { echo 'hello world'; }
$a instanceof Closure; // true
Generator 主要用於 yield 的回傳值,這部份可參考我昨天的文章:Day 06: yield 的使用。
值得注意的是,Generator 無法被 new 出來。
function generator(): Generator
{
yield 1;
yield 2;
yield 3;
}
foreach (generator() as $item) {
}
WeakReference 是一個來自於 WeakRef 的 extension,在 PHP 7.4 之後被加入標準之中。
Weak Reference 又名「弱引用」,這在部份的物件導向程式設計中被認為是優化 GC 行為的一項 Feature。
PHP 的 GC 與 Java 類似,當兩個條件達成時,使用的記憶體就會被回收
class A
{
}
$a = new A; // $a 與 Class A 是引用關係,在 unset($a) 或生命週期結束之前它不會被 GC。
WeakReference 的引入目的在於做到類似於「Object 的快取」:當 Object 存活時,WeakReference 就可以使用它,當 Object 被回收時,WeakReference 也不會阻止 GC 去回收它。
class A
{
}
$a = new A;
$b = $a;
$weakA = WeakReference::create($a);
$weakA->get(); // object (A)#1 (0) {}
unset($a)
$weakA->get(); // null
通常預定義的 Interface 及 Class 比較常用於 Array 系列(Iterator、ArrayAccess),事實上只要瞭解如何使用就能寫出易於理解的程式碼