Segregated Interfaces in PHP

In this first part of a programming series, you will learn how to create segregated interfaces to perform specific tasks in PHP. In this instance, you will be using them to iterate through arrays.

One of the big pillars of "Design by Contract" (http://en.wikipedia.org/wiki/Design_by_contract), interfaces are powerful structures that permit you to develop well-organized, object-oriented applications, even in weakly-typed languages such as PHP. If you’ve used interfaces in the construction of your own PHP programs, then you should be aware of the many benefits they bring to the table: coding to an interface and not an implementation, favoring Composition over Inheritance (a crucial facet of Dependency Injection), type-hinting arguments in class methods and so forth.

Editor's Note: This article has been published out of sequence. You can find the second and third parts of this series at:

  • Dynamic Registry in PHP
  • Implementing a Cache System in PHP

    Unfortunately, due to the fact that we’re imperfect and sometimes “unconscious” creatures, we tend to abuse interfaces and misuse them. Not that I’m claiming that you’re guilty of this (in my case, mea culpa), but eventually the contracts that we define for our classes can be too generous. But what does this mean in simple terms?

    Well, consider the following example: say that you’re building a custom array iterator, which will be capable of traversing arrays by using a “foreach” construct. To add the functionality required by this class, you define an interface called “Collection”, which extends the native classes “Countable”, “Iterator” and “ArrayAccess”. Finally, you make the iterator an implementer of the shiny “Collection” interface.

    Now, think about this situation a bit more carefully: if your iterator will be aimed only at traversing arrays, why are you giving it the ability (in this case unnecessary) to count and access elements? In fact, what you’re doing defining a contract for the iterator that gives it more functionality than the one that it really needs to get its job done.

    The good news is that this issue can be easily solved by means of segregated interfaces. Don’t worry about their fancy names, because you’ve probably used them before without knowing what they were called. Back to the earlier example – if you modify your array iterator and make it only implement the “Iterator” PHP interface, you’re already utilizing a segregated interface. This implies that a segregated interface is nothing but an ordinary interface, whose contract suits (exactly) the needs of one or multiple classes, be they related to each other or not. 

    Of course, the best manner to demonstrate the functionality of segregated interfaces is by example. In this article series I’ll be developing some segregated interfaces in the construction of some practical projects, which you’ll be able to tweak at will.

    {mospagebreak title=Building an Array Collection in PHP}

    Getting started: building an array collection

    To start illustrating why segregated interfaces are really useful, in the lines to come I’m going to build an example that will recreate the scenario described in the introduction. Basically, what I want to achieve here is to construct a custom countable array collection.

    At this first stage, the collection will only be capable of counting the elements added to it and nothing else; it’ll use only the contract declared by the “Countable” PHP interface. Based on this, here’s how this sample collection looks:


  • (ArrayCollection.php)

    class ArrayCollection implements Countable
    {
        protected $_data = array();
       
        /**
         * Constructor
         */
        public function __construct(array $data = array())
        {
            if (!empty($data)) {
                $this->_data = $data;
            }
        }
       
        /**
         * Count the number of elements in the collection (implementation required by Countable interface)
         */
        public function count()
        {
            return count($this->_data);
        }
    }

    As you can see, the functionality of the above “ArrayCollection” class is pretty limited. However, this has been done deliberately, as the only thing that the class needs to do, at least for now, is to count its inputted elements.

    In keeping with this, the collection only implements the “Countable” native interface, which (not surprisingly) turns out to be a segregated interface, as it only provides its implementer with the functionality that it requires.

    Next it’s time to add one more to the earlier array collection. Considering that this class must also be capable of traversing its internal elements, it must then implement the “Iterator” PHP interface.

    Making the collection iterable: implementing the “Iterator” interface

    The next step that must be taken is to provide the previous array collection with the ability to traverse the elements added to it. Of course, this can be accomplished using another segregated interface, which turns out to the built-in “Iterator”.

    Having said that, now check the following code sample, which shows the results of this implementation process:

    (ArrayCollection.php) class ArrayCollection implements Countable, Iterator
    {
        protected $_data = array();
       

        /**
         * Constructor
         */
        public function __construct(array $data = array())
        {
            if (!empty($data)) {
                $this->_data = $data;
                $this->rewind();
            }
        }
       
        /**
         * Count the number of elements in the collection (implementation required by Countable interface)
         */
        public function count()
        {
            return count($this->_data);
        }
       
        /**
         * Reset the collection (implementation required by Iterator interface)
         */    
        public function rewind()
        {
            reset($this->_data);
        }
       
        /**
         * Get the key of the current element in the collection (implementation required by Iterator interface)
         */
        public function key()
        {
            return key($this->_data);
        }
       
        /**
         * Get the current element in the collection (implementation required by Iterator interface)
         */
        public function current()
        {
            return current($this->_data);
        }     /**
         * Check if there're more elements in the collection (implementation required by Iterator Interface)
         */
       
        public function valid()
        {
            return ($this->current() !== false);
        }
       
        /**
         * Move to the next element in the collection (implementation required by Iterator interface)
         */
        public function next()
        {
            next($this->_data);
        }
    }

    Thanks to the use of another segregated interface, the previous array collection class is capable of iterating over its inputted elements by using a “foreach” construct.

    Taking into account that this is a straightforward process, which you’ve probably tackled many times before when you wrote your own custom iterators, it’s time to move forward and provide the earlier array collection with the ability for adding, removing and accessing its internal elements. Well, not surprisingly this enhancement procedure can be easily achieved by making the class an implementer of the “ArrayAccess” native interface.

    {mospagebreak title=Implementing the ArrayAccess Interface}

    Giving the final touches to the collection: implementing the “ArrayAccess” interface

    As noted in the preceding segment, the last step that must be taken to get the earlier array collection up and running is to make it an implementer of another segregated interface – in this case the built-in “ArrayAccess”. Even when this process has nothing specially difficult, below I included the finished code of the collection, so that you can study it in depth. Here it is: 

    (ArrayCollection.php) <?php class ArrayCollection implements Countable, Iterator, ArrayAccess
    {
        protected $_data = array();
       
        /**
         * Constructor
         */
        public function __construct(array $data = array())
        {
            if (!empty($data)) {
                $this->_data = $data;
                $this->rewind();
            }
        }
       
        /**
         * Count the number of elements in the collection (implementation required by Countable interface)
         */
        public function count()
        {
            return count($this->_data);
        }
       
        /**
         * Reset the collection (implementation required by Iterator interface)
         */    
        public function rewind()
        {
            reset($this->_data);
        }
       
        /**
         * Get the key of the current element in the collection (implementation required by Iterator interface)
         */
        public function key()
        {
            return key($this->_data);
        }
       
        /**
         * Get the current element in the collection (implementation required by Iterator interface)
         */
        public function current()
        {
            return current($this->_data);
        }     /**
         * Check if there're more elements in the collection (implementation required by Iterator Interface)
         */
       
        public function valid()
        {
            return ($this->current() !== false);
        }
       
        /**
         * Move to the next element in the collection (implementation required by Iterator interface)
         */
        public function next()
        {
            next($this->_data);
        }
       
        /**
         * Add an element to the collection (implementation required by ArrayAccess interface)
         */
        public function offsetSet($key, $value)
        {
            if ($key === null) {
                if (!in_array($key, $this->_data, true)) {
                    $this->_data[] = $value;
                    return true;
                }
            }
            else if (!array_key_exists($key, $this->_data)) {
                $this->_data[$key] = $value;
                return true;
            }
            return false;
        }
       
        /**
         * Remove an element from the collection (implementation required by ArrayAccess interface)
         */
        public function offsetUnset($key)
        {
            if (array_key_exists($key, $this->_data)) {
                unset($this->_data[$key]);
                return true;
            }
            return false;
        }
       
        /**
         * Get the specified element in the collection (implementation required by ArrayAccess interface)
         */
        public function offsetGet($key)
        {
            return array_key_exists($key, $this->_data) ?
                   $this->_data[$key] :
                   null;
        } 
       
        /**
         * Check if the specified element exists in the collection (implementation required by ArrayAccess interface)
         */    
        public function offsetExists($key)
        {
            return array_key_exists($key, $this->_data);
        }
    }

    If you thought that segregated interfaces were a hard-to-grasp concept, the above example should make you change your mind. Although it’s quite probable that you’ve already created a custom array collection similar to the one above, you should think of it as a class which uses three different segregated interfaces in order to implement only the functionality that it needs to get its job done.

    In addition, here’s a short script that shows how to use the pertaining collection for iterating over a trivial array and counting its elements as well. Look at it, please:

    <?php // include the collection
    require_once 'ArrayCollection.php'; // create a range of values
    $data = range(1, 20); // add the range to the collection
    $collection = new ArrayCollection($data); // iterate over the collection
    echo 'Elements in the collection: <br />';
    foreach ($collection as $key => $value) {
        echo 'Key: ' . $key . ' Value: ' . $value . '<br />';
    } // count the number of elements in the collection
     echo 'Number of elements in the collection: ' . count($collection); /*
    displays the following Elements in the collection:
    Key: 0 Value: 1
    Key: 1 Value: 2
    Key: 2 Value: 3
    Key: 3 Value: 4
    Key: 4 Value: 5
    Key: 5 Value: 6
    Key: 6 Value: 7
    Key: 7 Value: 8
    Key: 8 Value: 9
    Key: 9 Value: 10
    Key: 10 Value: 11
    Key: 11 Value: 12
    Key: 12 Value: 13
    Key: 13 Value: 14
    Key: 14 Value: 15
    Key: 15 Value: 16
    Key: 16 Value: 17
    Key: 17 Value: 18
    Key: 18 Value: 19
    Key: 19 Value: 20
    Number of elements in the collection: 20 */

    Undeniably, the above example speaks for itself, meaning that you shouldn’t have major troubles using it as a starting point for defining your own segregated interfaces. But, still don’t have a clue on how to use a segregated interface in other uses cases, other than when building array collections?

    Well, don’t worry and feel free to offload this task to me. And I’m saying this because in the following tutorial I’m going to demonstrate how to utilize a segregated interface in the construction of a dynamic registry. Meanwhile, stop by the article’s final thoughts.

    Final thoughts

    In this first installment of the series, I provided you with an introduction to using segregated interfaces in PHP. Moreover, through a fairly simple example, I demonstrated what they are and how useful they can be when it comes to provide their eventual implementers with the functionality that they require to perform specific tasks.

    In the coming part, things will become even more interesting, as I’m going to show you how to utilize a segregated interface in the development of an extendable registry system.

    As usual, don’t miss the next post! 

    [gp-comments width="770" linklove="off" ]

    antalya escort bayan antalya escort bayan Antalya escort diyarbakir escort