Home >Backend Development >PHP Tutorial >Fun with Array Interfaces

Fun with Array Interfaces

Jennifer Aniston
Jennifer AnistonOriginal
2025-02-22 10:46:09324browse

Fun with Array Interfaces

Key Points

  • PHP's array interface allows programmers to simulate the characteristics of native data types in custom classes, similar to Python's methods. This enables custom classes to work like arrays and allows common array operations such as counting elements, looping through elements, and accessing elements through indexes.
  • Interfaces are like contracts for classes, specifying methods that classes must contain. They allow encapsulation of implementation details and provide syntax sugar, thereby improving the readability and maintainability of the code. PHP provides a library of predefined interfaces that can implement these interfaces to make objects similar to arrays.
  • The
  • , Countable and ArrayAccess interfaces in IteratorPHP 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.

Brief description of 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>

SPL and PHP interfaces

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

Using

, we can also delete it with the Tweet ID, but I will leave this for you to implement. offsetUnset

Unfortunately, achieving

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

Interface Iterator

I saved my favorite interface for the last! The

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

First, the following method needs to be implemented:

<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.

Conclusion

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!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn