Login

Using Restrictive Constructors in PHP 5

What exactly is a restrictive constructor, and why would you want to use one? If you’re a PHP programmer who uses such design patterns as Singleton and Factory, this series of articles on restrictive constructors will give you another tool to use in your applications.

As you’ll probably know, with the release of PHP 5 quite some time ago, the language was provided with the ability to specify the visibility of properties and methods in classes, something that had already been implemented in more mature programming languages such as Java and C++.

In a pretty straightforward fashion, PHP developers can establish three different levels of restriction to several class data members, through the use of the “public,” “protected” and “private” keywords respectively. It’s even possible to appeal to the “final” keyword to make a whole class or method closed to further modifications.

Naturally, at this point member visibility brings nothing new to the table, especially for seasoned programmers with a lot of experience in developing object-oriented applications. However, there’s a particular case when this feature can be a bit more interesting than usual. It occurs when using restrictive constructors. But, what are they, actually?

Well, as its name clearly suggests, a restrictive constructor is nothing but a regular constructor method whose level of visibility has been declared protected or private. It’s as simple as that. Yet, this rather pragmatic definition also brings with it an intriguing question: why should a constructor be restricted to being accessed only from its originating class or even from a subclass?

True to form, there are a number of specific situations where assigning a stronger level of restriction to a constructor than “public” is indispensable, not to say mandatory. For instance, the implementation of certain creation design patterns, such a Singleton and Factory, quite often requires coding protected and private constructors to more strictly control class instantiation, or when building classes that are intended to be used out of the object context.

Given the variety of cases where restrictive constructors can be truly helpful, in the following lines I’m going to code for you some easy-to-follow examples aimed at demonstrating the use of protected and private constructors in PHP 5.

Ready to take the first step of this hopefully educational journey? Then, let’s get started!

In order to illustrate a basic usage of a restrictive constructor, in the following lines I’m going to define a generic class that will permit you to iterate over an array through a very simple API. Of course, before I hear your complaints, it’s valid to point out that the Standard PHP library (SPL) bundled with PHP 5 comes with a class that allows you to traverse arrays, called “ArrayIterator.” But in this case, I’m going to build a custom array iterator, so you can see more clearly the use of a protected constructor.

Having clarified that point, it’s time to show the definition of the aforementioned custom array iterator, which is as follows:

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;

}

}

As I said before, all that the above “DataIterator” class does is expose a short API that allows you to traverse arrays very simply. As the class has been defined as an implementer of the Iterator and Countable PHP 5 native interfaces, it must logically implement all of the inherited methods.

Due to its generic nature, the class is set up to be extended by other subclasses, instead of dealing directly with instances of itself. To prevent this instantiation in a very rudimentary fashion, the class declares its constructor protected, which recreates a basic scenario where a restrictive constructor can be used to avoid creating certain type of objects.

Naturally, if you closely analyze the definition of this iterator class, you’ll realize that there’s a simpler way to prevent its instantiation. Declaring the iterator abstract will get the job done without having to deal with a restrictive constructor. Nonetheless, for the moment I’ll keep the class’s code untouched, so you can see from a basic example that a protected constructor may be pretty useful in certain situations.

Now that you’ve grasped the logic of the previous array iterator class, it’s time to extend its functionality by creating a brand new subclass from it. For this example, the subclass will be used for traversing text files.

To learn more on how this subclass will be defined, read the section to come. It’s only one click away.

{mospagebreak title=Building a basic file iterator}

In the previous section, I demonstrated how to build an array iterator class that, thanks to the implementation of a protected constructor, can’t be directly instantiated. Given that restriction, the next step that I’m going to take will consist of deriving a subclass from the iterator. The subclass will declare a pretty refined constructor method for traversing simple text files.

Please take a close look at the definition of this new file iterator class, which is as follows:

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);

}

}

As depicted above, the logic that drives the “FileIterator” class is extremely easy to follow. It simply overrides its parent’s constructor to take as an input argument the text file that must be iterated over. The remaining methods are simply inherited from the base “DataIterator,” so I’m not going to get back to them again, since they were already discussed in the previous section.

So far, everything looks pretty good, right? At this point, there’s a class that allows you to traverse text files in a painless fashion, thanks to the inherited functionality of a base class which implements a protected constructor. At the risk of being repetitive, I’d like to stress that a better result could be produced by declaring the corresponding parent abstract, but for now the parent iterator will live as a concrete class.

Having explained how the file iterator does its thing, it’s time to give it a try so you can see it in action. Therefore, in the last section of this tutorial I’m going to set up an example for you, which will demonstrate how to iterate easily over the contents of a sample text file.

To see how this particular example will be developed, click on the link below and read the following segment.

{mospagebreak title=Traversing a simple text file}

In the section that you just read, I built a basic iterator class whose main task was to traverse the contents of a specified text file. Having discussed briefly the inner workings of this class, it’d be really useful to set up an example that shows it in action. Below I coded a short script that demonstrates how to work with the mentioned iterator, assuming that the text file that will be traversed has been defined like this:

(data.txt)

line 1

line 2

line 3

line 4

line 5

line 6

line 7

line 8

line 9

line 10

Since the definition of the above “data.txt” file doesn’t bear any further discussion, please look at the following code fragment. It shows a simple usage of the earlier “FileIterator” class, provided that the definition of the corresponding parent has been previously included in the script:

// 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 within the base “DataIterator” class, I managed to build a neat hierarchy of classes that let you easily navigate the contents of a target text file. Although it’s fair to admit that this particular example can be improved for the reasons given previously, it’s handy for demonstrating a simple use of a restrictive constructor in PHP 5. As usual, feel free to introduce your own modifications to all of the code samples shown before, which hopefully will spark your creativity for implementing protected and private constructors when developing your PHP applications.

Final thoughts

In this introductory part of the series, I showed you a trivial example where a protected constructor was used to prevent the direct instantiation of a parent, generic array iterator class. While this approach will produce the expected results, it’s admittedly pretty pointless because a stronger level of restriction can be achieved by declaring the class in question abstract.

Since PHP 5 offers great support for working with abstract classes, in the next tutorial I’m going to recreate the example that you saw before, but this time by simply using an abstract iterator class.