Countable
、ArrayAccess
和 Iterator
接口分別允許對像傳遞 count()
方法、像映射一樣被訪問以及迭代集合。這些接口可用於創建更動態和交互式的對象,例如可以計算其推文數量、循環遍歷它們以及通過其 ID 訪問推文的 Twitter 時間線類。 作為一名每天使用不同編程語言的程序員,我非常享受學習其他語言中不同的事物,並嘗試在 PHP 中實現相同的功能。我特別喜歡 Python 中如何在自定義類中模擬原生數據類型的特性。
例如,這個成員列表類:
class Members { public function __construct(array $members) { $this->members = $members; } // 其他方法 }
通過實現 __iter__
方法,您可以像迭代列表(PHP 中的數組)一樣迭代此類實例中的數據:
class Members implements Iterator { private $members; private $position = 0; public function __construct(array $members) { $this->members = $members; } public function current() { return $this->members[$this->position]; } public function key() { return $this->position; } public function next() { $this->position++; } public function rewind() { $this->position = 0; } public function valid() { return isset($this->members[$this->position]); } } $ls = new Members(["你", "我"]); foreach ($ls as $member) { echo $member . "\n"; }
成員資格測試只需實現 __contains__
方法:
class Members { public function __construct(array $members) { $this->members = $members; } public function contains($member) { return in_array($member, $this->members); } } $members = new Members(["你", "我"]); if ($members->contains("我")) { echo "我是一个成员!\n"; }
我認為如果可以在自定義類的實例(不僅僅是數組)中在 PHP 中執行以下操作,那就太好了:
isset($myObject["test"]);
PHP 允許我們使用數組接口來實現這一點。
將接口視為指定類必須包含的方法的契約。
interface Multiplier { public function multiply($num1, $num2); }
使用此接口的任何類都必須具有此 multiply
方法。有一個關鍵字表示類滿足此契約:implements
。
class SmartMultiplier implements Multiplier { public function multiply($num1, $num2) { return $num1 * $num2; } }
只要滿足契約,實現方式就無關緊要。實現 multiply
方法的另一種方法如下:
class NotSoSmartMultiplier implements Multiplier { public function multiply($num1, $num2) { $product = $num1; for ($i = 1; $i < $num2; $i++) { $product += $num1; } return $product; } }
PHP 提供了一個預定義接口庫,只需在類中實現這些接口,就可以使我們的對像類似於數組。
其中一些接口包含在預定義接口和類列表中,一些包含在標準 PHP 庫 (SPL) 中。
如果這些術語聽起來令人生畏,請不要擔心。您之前都使用過 $_GET
。 $_GET
是一個被稱為預定義的語言結構。
另一方面,根據文檔,SPL 只是
一個旨在解決常見問題的接口和類集合。
現在要做的是看看這些接口的實際應用。讓我們深入研究一下!
我們將創建一個 Twitter 時間線類,
class Members { public function __construct(array $members) { $this->members = $members; } // 其他方法 }
能夠計算其推文數量,
class Members implements Iterator { private $members; private $position = 0; public function __construct(array $members) { $this->members = $members; } public function current() { return $this->members[$this->position]; } public function key() { return $this->position; } public function next() { $this->position++; } public function rewind() { $this->position = 0; } public function valid() { return isset($this->members[$this->position]); } } $ls = new Members(["你", "我"]); foreach ($ls as $member) { echo $member . "\n"; }
循環遍歷它們,
class Members { public function __construct(array $members) { $this->members = $members; } public function contains($member) { return in_array($member, $this->members); } } $members = new Members(["你", "我"]); if ($members->contains("我")) { echo "我是一个成员!\n"; }
並通過推文 ID 獲取推文,
isset($myObject["test"]);
就像我們在普通數組中一樣!
不過,我們必須先解決一些問題。如果您還沒有 Twitter 帳戶,請先創建一個。現在註冊一個開發者帳戶並生成訪問令牌和密鑰。
接下來,從 Github 下載或克隆代碼,並在源文件夾內運行 composer install
。如果您不熟悉 Composer,請參閱 SitePoint 之前的文章。打開 index.php
文件並添加必要的 OAuth 數據。
Countable
接口Countable
接口可能是最不言自明的。只需實現 count
方法,就可以將對像傳遞給 count()
方法。
我們可以通過對“/users/show”執行 GET 請求來獲取用戶的推文數量。
interface Multiplier { public function multiply($num1, $num2); }
ArrayAccess
接口我們現在將通過學習一個更有趣的接口來提高難度。
實現後,ArrayAccess
將使我們的對象能夠像映射一樣被訪問,這正是它們的本質。要實現的方法是
class SmartMultiplier implements Multiplier { public function multiply($num1, $num2) { return $num1 * $num2; } }
這在我們的 Twitter 時間線對像中非常方便。測試推文是否存在於時間線中可以通過將我們的對像傳遞給 isset
來完成,如下所示:
class NotSoSmartMultiplier implements Multiplier { public function multiply($num1, $num2) { $product = $num1; for ($i = 1; $i < $num2; $i++) { $product += $num1; } return $product; } }
為此,我們只需對推文 ID 執行 GET 請求。
$tweets = new Timeline("jeunito");
更好的是,我們還可以將上述內容用於 offsetGet
,並讓 offsetExists
依次調用 offsetGet
。
使用 offsetUnset
,我們還可以通過推文 ID 進行刪除,但我將把這留給您去實現。
不幸的是,實現 offsetSet
沒有多大意義。對於這樣的事情,簡單的解決方法是拋出自定義異常,例如 UnsupportedOperationException
。但另一方面,這也可能取決於您的應用程序的特定業務規則。
Iterator
接口我把最喜歡的接口留到最後! Iterator
接口在這裡非常有用,因為我認為沒有比像迭代普通數組一樣迭代時間線對象更好的方法來封裝遠程集合分頁的細節了。
首先,需要實現以下方法:
count($tweets);
我們可以顯式地使用上述方法來循環遍歷我們的時間線,如下所示:
foreach ($tweets as $tweet) { echo $tweet; }
但是,為什麼這樣做,當您可以這樣做時:
// 获取 if (isset($tweets["some tweet id"])) { echo $tweets["some tweet id"]; }
在我們的示例中,我們將通過按時間順序檢索推文塊並將它們存儲在緩衝區中來循環遍歷時間線中的推文。我們將迭代此緩衝區,直到它用盡,然後我們使用最後一個推文的 ID 作為偏移量來獲取另一批推文。
最初我們沒有任何推文,這就是 rewind
方法的用武之地:獲取最新的 10 條推文,以便從我們可以獲取接下來的 10 條推文的地方開始偏移。
class Members { public function __construct(array $members) { $this->members = $members; } // 其他方法 }
valid()
方法只是用於指示是否繼續循環。這可以通過檢查我們的推文緩衝區是否為空來完成:
class Members implements Iterator { private $members; private $position = 0; public function __construct(array $members) { $this->members = $members; } public function current() { return $this->members[$this->position]; } public function key() { return $this->position; } public function next() { $this->position++; } public function rewind() { $this->position = 0; } public function valid() { return isset($this->members[$this->position]); } } $ls = new Members(["你", "我"]); foreach ($ls as $member) { echo $member . "\n"; }
key()
和 current()
方法只是返回我們迭代中當前推文的鍵和值。出於我們的目的,我們將簡單地從緩衝區中獲取推文 ID 和最新推文的文本。
class Members { public function __construct(array $members) { $this->members = $members; } public function contains($member) { return in_array($member, $this->members); } } $members = new Members(["你", "我"]); if ($members->contains("我")) { echo "我是一个成员!\n"; }
最後是 next
方法。在這裡,我們從緩衝區的頭部出隊以獲取要迭代的下一個元素。然後,如果我們位於緩衝區的最後一個元素,我們將確保獲取下一組推文。
isset($myObject["test"]);
我們完成了!這是一個非常基本的循環遍歷用戶推文的實現。還可以做更多的事情,例如本地緩存以節省API 調用,但這就是使用接口的美妙之處:它們允許我們在後台更改我們的策略,只要我們的實現仍然正確,我們就可以期望它仍然有效。
但是現在,您可以通過在命令行中運行 php index.php
來觀察我們的時間線對象的工作情況。
接口的好處是雙重的。它們允許我們封裝實現細節並為我們提供語法糖,這兩者在任何需要互操作性的應用程序中都非常有用。如果您有任何問題或意見,請在下面的評論部分留下它們!
以上是陣列接口的樂趣的詳細內容。更多資訊請關注PHP中文網其他相關文章!