CHAPTER 6 ■ OBJECTS AND DESIGN
Now I’ll address the same problem with some simple classes. First, I create an abstract base class
that will define the interface for the type:
abstract class ParamHandler {
protected $source;
protected $params = array();
function __construct( $source ) {
$this->source = $source;
}
function addParam( $key, $val ) {
$this->prams[$key] = $val;
}
function getAllParams() {
return $this->params;
}
static function getInstance( $filename ) {
if ( preg_match( "/.xml$/i", $filename )) {
return new XmlParamHandler( $filename );
}
return new TextParamHandler( $filename );
}
abstract function write();
abstract function read();
}
I define the addParam() method to allow the user to add parameters to the protected $params
property and getAllParams() to provide access to a copy of the array.
I also create a static getInstance() method that tests the file extension and returns a particular
subclass according to the results. Crucially, I define two abstract methods, read() and write(), ensuring
that any subclasses will support this interface.
■Note Placing a static method for generating child objects in the parent class is convenient. Such a design
decision does have its own consequences, however. The ParamHandler type is now essentially limited to working
with the concrete classes in this central conditional statement. What happens if you need to handle another
format? Of course, if you are the maintainer of ParamHandler, you can always amend the getInstance() method.
If you are a client coder, however, changing this library class may not be so easy (in fact, changing it won’t be
hard, but you face the prospect of having to reapply your patch every time you reinstall the package that provides
it). I discuss issues of object creation in Chapter 9.
Now, I’ll define the subclasses, once again omitting the details of implementation to keep the
example clean: