As I expressed in the introduction, I left off of the previous article of the series showing an example where a protected constructor was used to prevent the direct instantiation of an array iterator class, as this was originally conceived to be extended by other subclasses. While this approach certainly isn’t the best one to take when shielding a class from its eventual instantiation, as PHP 5 allows you to define abstract classes easily, it's good for illustrating the usage of a protected constructor in a particular case. Below I reintroduced the full source code of this specific example, so you can quickly recall how it was initially developed. First, here’s the definition of the base array iterator class that declares its constructor protected. Take a look at it: class DataIterator implements Iterator, Countable { protected $_pointer = 0; protected $_data = array();
protected function __construct(array $data) { if (empty($data)) { throw new Exception('Input data must be a non-empty array.'); } $this->_data = $data; }
// implement 'count()' method required by Countable interface public function count() { return count($this->_data); }
// implement 'rewind()' method required by Iterator interface public function rewind() { $this->_pointer = 0; }
// implement 'current()' method required by Iterator interface public function current() { if (!$this->valid()) { return FALSE; } return $this->_data[$this->_pointer]; }
// implement 'valid()' method required by Iterator interface public function valid() { return $this->_pointer < $this->count(); }
// implement 'next()' method required by Iterator interface public function next() { ++$this->_pointer; }
// implement 'key()' method required by Iterator interface public function key() { return $this->_pointer; } } Definitely, the inner workings of the above “DataIterator” class are quite easy to follow. Apart from declaring its constructor protected, the class implements a few straightforward methods that permit you to go backward and forward across the elements of an inputted array. That’s about it. Since this array iterator is actually very generic, it should be extended by one or multiple concrete classes, which is done through the following file iterator class: class FileIterator extends DataIterator { private $_file = 'data.txt';
// override parent constructor public function __construct($file = '') { if ($file !== '') { if (!file_exists($file)) { throw new Exception('Target file must be an existing file.'); } $this->_file = $file; } $data = file($this->_file); parent::__construct($data); } } Simple to code and read, isn’t it? As seen before, the “FileIterator” class is nothing but a simple subclass of the base array iterator that overrides its constructor to give itself the ability to traverse the contents of a specified text file. Also, if you still have some doubts regarding the way that this last iterator does its thing, below I coded a script that shows how to use the class for walking through the lines of a sample text file. The corresponding code sample is as follows: // use FileIterator class try { // create instance of FileIterator $fit = new FileIterator(); // reset iterator pointer $fit->rewind(); // display current file line echo $fit->current(); // move iterator pointer forward $fit->next(); // display current file line echo $fit->current(); // move iterator pointer forward $fit->next(); // display current file line echo $fit->current(); // reset iterator pointer $fit->rewind(); // display current file line echo $fit->current(); }
// catch exceptions catch (Exception $e) { echo $e->getMessage(); exit(); } There you have it. Thanks to the implementation of a simple protected constructor, it was possible to build a hierarchy of iterator classes that together allow you to traverse different data structures in a painless way. Even though this example isn’t very useful, it should be analyzed as what it really is: an example, and nothing else. Using a protected constructor to prevent the instantiation of a class does work decently, but this approach can be enhanced by declaring the class abstract. That’s much simpler and faster. Thus, in the lines to come I’m going to refactor the previous “DataIterator,” which this time will be defined as an abstract class. To learn the full details of how this refactoring process will be done, click on the link below and read the following section.
blog comments powered by Disqus |
|
|
|
|
|
|
|