Home >Backend Development >PHP Tutorial >Fun with Array Interfaces
Countable
and ArrayAccess
interfaces in Iterator
PHP allow objects to pass count()
methods, access like maps, and iterate over sets, respectively. These interfaces can be used to create more dynamic and interactive objects, such as Twitter timeline classes that can count their number of tweets, loop through them, and access tweets through their ID. As a programmer who uses different programming languages every day, I really enjoy learning different things in other languages and trying to implement the same functionality in PHP. I especially like the feature in Python how to simulate native data types in custom classes.
For example, this member list class:
<code class="language-php">class Members { public function __construct(array $members) { $this->members = $members; } // 其他方法 }</code>
By implementing the __iter__
method, you can iterate over the data in such instances like iterating over a list (array in PHP):
<code class="language-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"; }</code>
Membership test only needs to be implemented __contains__
Method:
<code class="language-php">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"; }</code>
I think it would be great if I could do the following in PHP in an instance of a custom class (not just an array):
<code class="language-php">isset($myObject["test"]);</code>
PHP allows us to achieve this using an array interface.
Treat an interface as a contract for the specified class to contain methods.
<code class="language-php">interface Multiplier { public function multiply($num1, $num2); }</code>
Any class using this interface must have this multiply
method. There is a keyword that indicates that the class satisfies this contract: implements
.
<code class="language-php">class SmartMultiplier implements Multiplier { public function multiply($num1, $num2) { return $num1 * $num2; } }</code>
As long as the contract is satisfied, the implementation method is irrelevant. Another way to implement the multiply
method is as follows:
<code class="language-php">class NotSoSmartMultiplier implements Multiplier { public function multiply($num1, $num2) { $product = $num1; for ($i = 1; $i < $num2; $i++) { $product += $num1; } return $product; } }</code>
PHP provides a library of predefined interfaces that can make our objects similar to arrays by implementing these interfaces in a class.
Some of these interfaces are included in predefined interfaces and classes lists, and some are included in the standard PHP library (SPL).
If these terms sound intimidating, don't worry. You have used $_GET
before. $_GET
is a language structure called predefined .
On the other hand, according to the documentation, SPL is just
A collection of interfaces and classes designed to solve common problems.
What we need to do now is to see the actual application of these interfaces. Let's dig into it!
We will create a Twitter timeline class,
<code class="language-php">class Members { public function __construct(array $members) { $this->members = $members; } // 其他方法 }</code>
Can be able to calculate the number of tweets,
<code class="language-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"; }</code>
Loop through them,
<code class="language-php">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"; }</code>
and get the tweet via the tweet ID,
<code class="language-php">isset($myObject["test"]);</code>
Just like we are in a normal array!
However, we must first solve some problems. If you don't have a Twitter account yet, create one first. Register a developer account now and generate an access token and key.
Next, download or clone the code from Github and run composer install
in the source folder. If you are not familiar with Composer, see previous articles from SitePoint. Open the index.php
file and add the necessary OAuth data.
Countable
Interface Countable
The interface is probably the most self-explanatory. Just implement the count
method and you can pass the object to the count()
method.
We can get the number of tweets of users by performing a GET request on "/users/show".
<code class="language-php">interface Multiplier { public function multiply($num1, $num2); }</code>
ArrayAccess
Interface We will now increase the difficulty by learning a more interesting interface.
After implementation, will enable our objects to be accessed like maps, which is exactly their essence. The method to achieve is ArrayAccess
<code class="language-php">class SmartMultiplier implements Multiplier { public function multiply($num1, $num2) { return $num1 * $num2; } }</code>This is very convenient in our Twitter timeline objects. Testing whether a tweet exists in the timeline can be done by passing our object to
as shown below: isset
<code class="language-php">class NotSoSmartMultiplier implements Multiplier { public function multiply($num1, $num2) { $product = $num1; for ($i = 1; $i < $num2; $i++) { $product += $num1; } return $product; } }</code>To do this, we just need to perform a GET request to the tweet ID.
<code class="language-php">$tweets = new Timeline("jeunito");</code>Better yet, we can also use the above for
and let offsetGet
call offsetExists
in turn. offsetGet
, we can also delete it with the Tweet ID, but I will leave this for you to implement. offsetUnset
doesn't make much sense. For something like this, the simple solution is to throw a custom exception, such as offsetSet
. But on the other hand, it may also depend on the specific business rules of your application. UnsupportedOperationException
Iterator
interface is very useful here, because I don't think there is a better way to encapsulate the details of remote collection pagination than iterating over timeline objects like iterating over normal arrays. Iterator
<code class="language-php">count($tweets);</code>We can explicitly use the above method to loop through our timeline, as shown below:
<code class="language-php">foreach ($tweets as $tweet) { echo $tweet; }</code>But why do this, when you can:
<code class="language-php">// 获取 if (isset($tweets["some tweet id"])) { echo $tweets["some tweet id"]; }</code>In our example, we will loop through the tweets in the timeline by retrieving tweet blocks in chronological order and storing them in a buffer. We will iterate over this buffer until it runs out, and then we use the ID of the last tweet as the offset to get another batch of tweets.
Initially we didn’t have any tweets, and that’s where the rewind
method comes in: Get the latest 10 tweets to start off the offset from where we can get the next 10 tweets.
<code class="language-php">class Members { public function __construct(array $members) { $this->members = $members; } // 其他方法 }</code>The
valid()
method is only used to indicate whether the loop continues. This can be done by checking if our tweet buffer is empty:
<code class="language-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"; }</code>The
key()
and current()
methods simply return the keys and values of the current tweet in our iteration. For our purposes, we will simply get the tweet ID and text of the latest tweet from the buffer.
<code class="language-php">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"; }</code>
Lastly next
method. Here we dequeue from the head of the buffer to get the next element to iterate over. Then, if we are on the last element of the buffer, we will make sure to get the next set of tweets.
<code class="language-php">isset($myObject["test"]);</code>
We're done! This is a very basic implementation of looping through user tweets. There are more things that can be done, such as local cache to save API calls, but that's the beauty of using interfaces: they allow us to change our policies in the background, and as long as our implementation is still correct, we can expect it to still work .
But now, you can observe how our timeline objects work by running php index.php
on the command line.
The benefits of the interface are twofold. They allow us to encapsulate implementation details and provide us with syntactic sugar, both of which are very useful in any application that requires interoperability. If you have any questions or comments, please leave them in the comment section below!
The above is the detailed content of Fun with Array Interfaces. For more information, please follow other related articles on the PHP Chinese website!