Posts Tagged 'Interfaces&'

Nov

15

Working with Class Types: Abstract Classes and Interfaces

Posted by admin under technology - No Comments

Working with Class Types: Abstract Classes and Interfaces
Intended Audience
Introduction
Class Types
So Why are Class Types Important?
Testing and Enforcing Type
Working with Class Types: Abstract Classes
Working with Class Types: Interfaces
Summary
About the Author
Intended Audience
This article is intended for experienced PHP programmers interested in exploring PHP 5′s support for working with class types through argument hinting, abstract classes and interfaces. Basic knowledge of object-oriented programming, including the anatomy of a class and the mechanics of inheritance, is assumed.

Introduction
Most PHP programmers know that the Zend Engine II provides extended support for object-oriented features. Three of these features – argument hinting, abstract classes, and interfaces – revolve around checking and defining class types. In this article we will investigate how these features can help with code design and bug prevention.

Class Types
PHP has 12 built-in types, including scalar types like integer and float, complex types (object and array), and special types (resource and NULL). Because it supports classes and objects, PHP also lets you define types of your own. In fact, every time you define a class you also create a type.

Here’s a simple class:
class Question {

function answer( $response_s ) {
// …
}

}
?>

By defining the Question class you have also defined the Question type. An object instantiated from the Question class belongs to the Question type, as does an object instantiated from a child class of Question.

Here is a class that extends the Question class:

class ResourceQuestion extends Question {
// …

function addResourceURL( $url_s ) {
// …
}

}

$question = new ResourceQuestion();
?>

The $question object has a complex identity. It is an instance of the ResourceQuestion type, but it is also an instance of the Question type, because ResourceQuestion extends the Question class.
So Why are Class Types Important?
Once you know an object’s type, you know its characteristics and capabilities. By telling me that the object assigned to $question belongs to the Question type, you are also telling me that it has an answer() method I can call. If you tell me that $question is also a ResourceQuestion object, you are also telling me that it has both an answer() and a setResourceURL() method. Armed with this information about $question, I can make sensible choices when I work with it.

Testing and Enforcing Type
PHP 5 introduces the instanceof operator, which you can use to check the type of an object variable. instanceof sits between two operands; the first, on its left, is the object variable to test; the second, on its right, is the type you are checking the object against. So to confirm that $question is a Question object you would use this syntax:

if ( $question instanceof Question ) {
print “\$question is type Question\n”;
}

You are most likely to care about class and primitive types when dealing with method and function arguments. Can you trust a client coder not to pass garbage to your code? How might unexpected data affect your script?

Let’s expand the Question class. This is part of a (brutally) simplified quiz library. Each Question object requires a Marker object, which is responsible for checking a user’s response against a marking condition. For the purposes of this example, the Question class acquires a Marker object as an argument to its constructor.

class Question {
private $marker;
public $prompt = “”;

function __construct( $prompt_s, $marker ) {
$this->prompt = $prompt_s;
$this->marker = $marker;
}

}

?>

The code that calls __construct() may be beyond our control, so what happens if the wrong kind of object is passed into the $marker argument? The answer is ‘nothing’, and that is the problem. You store the Marker object in a property, ready for use later in a method called answer(). If the wrong object is passed to the constructor you won’t discover the error until answer() is called:

class Question {
private $marker;
public $prompt = “”;

function __construct( $prompt_s, $marker ) {
$this->prompt = $prompt_s;
$this->marker = $marker; // bug occurs here
}

function answer( $response_s ) {
$this->marker->mark( $response_s ); // effect of bug here
}
}

?>

This, then, is a situation in which checking type may save you problems later on. We don’t want the wrong type lurking in our class, waiting to ambush us down the line. You could check the $marker argument manually:

function __construct( $prompt_s, $marker ) {
if ( ! ( $marker instanceof Marker ) ) {
die( “Expected Marker object” );
}

$this->prompt = $prompt_s;
$this->marker = $marker; // type guaranteed
}

However, manually checking the type of every object argument would soon bulk up your script. In practice most of us would simply rely on a naming scheme and documentation to signal expected argument types.

PHP 5 comes to the rescue with class type hinting. By preceding an argument with a type name in a method declaration you can ask the PHP engine to enforce that type:

function __construct( $prompt_s, Marker $marker ) {
$this->prompt = $prompt_s;
$this->marker = $marker;
}

By putting ‘Marker’ in front of the $marker argument variable, we enforce the type at runtime. This means that any type other than a Marker object passed into $marker will cause a fatal error:

Fatal error: Argument 2 must be an object of class Marker in…

So when client code invokes answer(), we are safer in assuming that the Question::$marker property contains a Marker object.

Working with Class Types: Abstract Classes
You have seen that user-defined types are useful in that they guarantee an interface. In fact you can take this further and divorce interface from implementation.

Here’s an implementation of the Question and Marker classes:

class Question {
private $marker;
public $prompt = “”;
public $score = 0;
public $response = “”;

function __construct( $prompt_s, Marker $marker ) {
$this->prompt = $prompt_s;
$this->marker = $marker;
}

function answer( $response_s ) {
$this->score = 0;
$this->response = $response_s;
if ( $this->marker->mark( $response_s ) ) {
$this->score = 1;
}
}
}

class Marker {
protected $condition;
function __construct( $condition_s ) {
$this->condition = $condition_s;
}

function mark( $response_s ) {
return ( $this->condition == $response_s );
}
}
?>

This example enhances the Question class to maintain a score of one or zero. The Marker class stores a marking condition. When it is called upon to mark its Question it simply compares the $condition string with the user input passed to mark(). If the two strings match, the method returns true. Here’s some quick code to test the classes in action:

$q = new Question( “how many beans make 5″,
new Marker( ‘five’ ) );
$responses = array( “five”, “six” );

foreach ( $responses as $response ) {
$q->answer( $response );
print “response: $response scores {$q->score}\n”;
}

// output:
// response: five scores 1
// response: six scores 0

You can use diagrams to illustrate class relationships. The most common way of doing this is with the Unified Modeling Language (UML). This diagram uses the UML to represent the relationship between the Question and Marker classes.
However, the marking logic in the Marker class is very crude. What happens when your requirements become more complex? The quiz administrator is likely to request more flexibility in authoring marking conditions. Perhaps she needs to pose questions like ‘Name the access control keywords’, only awarding a score if all items are included in a comma separated list.

You can amend the Marker class to handle both exact matches and list item matches. It will need some way of distinguishing between types of condition. Here’s an example that uses constant flags, though you could also embed some kind of token in the condition text:

class Marker {
protected $condition;
protected $condWords;

const MATCH = 1;
const CLIST = 2;
private $type = MATCH;

function __construct( $condition_s, $type=1 ) {
$this->type = $type;
if ( $type == self::CLIST ) {
$this->condWords =
preg_split( “/\s*,\s*/”, $condition_s );
} else {
$this->condition = $condition_s;
}
}

function mark( $response_s ) {
if ( $this->type == self::CLIST ) {
// implement list marking
return true;
} else {
return ( $this->condition == $response_s );
}
}
}

The Marker class uses two constants, Marker::MATCH and Marker::CLIST, to keep track of the kinds of marking it might be called upon to do. If the Marker::$type property contains the value defined in the Marker::MATCH constant, then the Marker::mark() method checks a response string for an exact match. If Marker::$type contains the value set in the Marker::CLIST constant, then the object breaks the response string into tokens and tests each one.

You acquire a value for the Marker::$type flag in the constructor. The $type argument in the constructor method definition defines a default value, which allows a user to omit a type argument and have the Marker object operate in match mode.

The example omits the marking logic for now, in order to save space, and to keep the focus on the design of the code. Notice the similar patterns in the constructor and the mark() method? You might just get away with this code until the client realizes that she needs regular expression marking – oh, and arithmetic evaluation of answers. At this stage the Marker class becomes horribly bloated. Not only will it grow in size, but also you must maintain two parallel conditional statements. The first, in the constructor, manages the initial compilation of the condition string, if needed; and the second, in the mark() method, handles the evaluation of the user’s response. The need to keep parallel conditional statements in line with one another can make code hard to maintain.

When you see two conditional statements that mirror one another in a class it is often a sign that you should consider separating these alternate implementations from your interface. You can do this using an abstract class.

You declare an abstract class using the abstract keyword in the class declaration.

abstract class MyClass {
// …
}
?>

Once you have done this to a class it is no longer possible to instantiate an object from it. Abstract classes are meant to be subclassed. They can contain methods and properties in the same way as normal classes, but they can also contain abstract methods. In method declarations the abstract keyword should precede other modifiers. Abstract methods should have no method body, they are a declaration of interface only.

abstract class MyClass {
abstract function aMethod( $an_arg );
}

This code redesignates the Marker class as an abstract:

abstract class Marker {
protected $condition;
function __construct( $condition_s ) {
$this->condition = $condition_s;
$this->handleCondition( $condition_s );
}

/* make the protected condition callable */
public function getCondition() {
return $this->condition;
}

abstract protected function handleCondition( $condition_s );
abstract function mark( $response_s );
}

?>

The code uses the abstract keyword both to modify the Marker class and to modify the methods handleCondition() and mark(). The constructor stores the raw condition string (passed to the $condition_s argument) in a property and then invokes the abstract handleCondition() method, leaving child classes to handle the details of any further processing.

Any class that extends an abstract superclass must provide implementations for the parent’s abstract methods or must itself be declared abstract. If you fail to do this, the PHP engine will throw a fatal error when the constructor is called:

class WrongMarker extends Marker {
}

//Fatal error: Cannot instantiate abstract class WrongMarker in..

In implementing abstract methods, you must define the same number of arguments, reproduce any type hinting in the argument list, and ensure that the implementing method’s access level (public, protected or private) is no stricter than that defined in the abstract parent. In short you should match the abstract method declaration all but absolutely.

So, abstract classes guarantee an implementation for their methods. Here are two concrete classes that extend Marker.

class MatchMarker extends Marker {
protected function handleCondition( $condition_s ) {
// no implementation needed
}

function mark( $response_s ) {
return ( $this->condition == $response_s );
}
}

class ListMarker extends Marker {
protected $condWords = array();

protected function handleCondition( $condition_s ) {
$this->condWords = preg_split( “/\s*,\s*/”, $condition_s );
}

function mark( $response_s ) {
$respWords = preg_split( “/\s*,\s*/”, $response_s );
$commonTerms = array_intersect( $this->condWords, $respWords );
if ( count( $commonTerms ) == count( $this->condWords ) ) {
return true;
}
return false;
}
}
?>

By splitting the differing implementations into their own classes you banish the complicated conditional statements and type flags that threatened to overrun the previous Marker class. Of course, your code will still need to decide which class to use for which condition string, but this can be handled by a central test of some kind.

The MatchMarker class applies the basic equivalence test we have already seen. The ListMarker class also applies crude rules. The class expects both the condition string and the user response as comma delimited lists of terms, it uses a regular expression to forgive a bit of white space, but that’s it. The user’s input must contain at least the same number of terms as the condition list, and every response term must match a term in the condition list in order for the question to be marked as correct. This code is not flexible enough for the real world, but it serves its purpose.

Here’s some simple client code to show our classes in action:

$questions[] = new Question(“How many data types does PHP have?”, new MatchMarker(“12″) );
$questions[] = new Question(“Name the access control keywords”, new ListMarker(“private, public, protected”) );
$answers = array( “12″, “private, public, protected” );

foreach( $questions as $q ) {
$q->answer( array_shift( $answers ) );
print “prompt: {$q->prompt}\n”;
print “response: {$q->response}\n”;
print “score: {$q->score}\n\n”;
}

// output:
// prompt: How many data types does PHP have?
// response: 12
// score: 1
//
// prompt: Name the access control keywords
// response: private, public, protected
// score: 1

By splitting the marking implementation into separate classes you defer the decision as to which class to choose for which condition string. The client code example glosses this and the code chooses between the MatchMarker and ListMarker classes arbitrarily. Choosing between alternative implementations of an abstract superclass is a common issue in object-oriented code. A common solution is to delegate this task to a factory class or method designed to generate an implementing object.

Structurally, our classes now look like this:
Throughout these additions to the Marker family we have not changed the Question class in any way. The Question class expects to work with objects of type Marker, an expectation enforced with a class type hint in the constructor. Even though we have created two new classes, the fact that they extend Marker makes the changes entirely transparent to the Question class.

This trick, the use of specialized classes that share a common general interface, is known as class switching or polymorphism. By hiding the varying details of implementation from client code you keep interdependence between classes to a minimum, which in turn contributes to modular and reusable code.

The introduction of class type hinting and abstract classes in PHP 5 provides greater certainty at runtime when you work with objects. It is possible to emulate abstract classes using PHP 4. You can use a naming convention, or define abstract methods that contain die() statements, like this:

class Marker {
// …

function handleCondition( $condition_s ) {
die( “handleCondition is abstract” );
}

function mark( $response_s ) {
die( “handleCondition is abstract” );
}
}

?>

By poisoning your abstract methods in this way, you strongly encourage child classes to override them. The problem with this approach is that you must wait for a method to be invoked before its abstract nature is enforced. PHP 5 enforces abstract classes when the script is first parsed, so a failure to implement an abstract method is picked up right away.

Working with Class Types: Interfaces
We have seen that an object can belong to more than one type. An object that is an instance of a child class is also an instance of each parent class in the inheritance hierarchy.

A class can only extend a single parent, so, in PHP 4, an object can belong to only one type family. PHP 5, however, supports interfaces: class-like structures that can be used to place an object in more than one type family at a time, and thereby guarantee that it will support more than one set of methods.

Interfaces are declared with the interface keyword. They are similar in nature to abstract classes, with the exception that they must include no implementation at all. An interface is just that, it can contain only properties and abstract methods.

Here is an interface for outputting XML data.

interface XMLable {
public abstract function toXML( );
}
?>

A class can implement an interface using the implements keyword in conjunction with the interface name. Place this clause in the class declaration after the extends clause.

class MyClass extends ParentClass implements anInterface {
//…
}

Any class that implements an interface must provide an implementation for all the methods the interface defines, or itself be declared abstract. A class can implement any number of interfaces by adding interface names to the implements clause:

class MyClass implements anInterface, anotherInterface {
//…
}

Here is an edited version of the Question class that implements XMLable:

class Question implements XMLable {
// skipping methods and properties

function toXML( ) {
return
<<

{$this->prompt} {$this->response}
{$this->marker->getCondition()}

XMLFRAGMENT;
}
}

A Question object will now be of both type Question and type XMLable. In the toXML() implementation you can see that we build up an XML string containing data from the Question object. You would probably use an extension such as DOM or SimpleXML in a real world implementation, but let’s emphasize clarity over flexibility here.

Now imagine a class unrelated to the Question class. Perhaps a User class that stores a name and email address. We can round off this example by having User (which happens to extend a class called Individual) implement XMLable.

class Individual {
public $name = “”;
public $email = 0;

function __construct( $name_s, $email_s ) {
$this->name = $name_s;
$this->email = $email_s;
}
}

class User extends Individual implements XMLable {

function getLastLogin() {
// …
}

function toXML() {
return
<<

{$this->name}
{$this->email}

XMLFRAGMENT;
}
}

The User class has nothing in common with the Question object except that both implement the XMLable interface.
This means that a third party class can work with both Question and User objects, by accepting them as XMLable objects, rather than by their main type. Here’s a class that does just that:

class ObjectDump {
private $xmlStr;
private $objects = array();

function addXMLable( XMLable $object ) {
$this->objects[] = $object;
}

function output() {
$xmlStr = “\n”;
foreach($this->objects as $output) {
$xmlStr .= $output->toXML();
}
$xmlStr .= “
\n”;
return $xmlStr;
}

function __toString() {
return $this->output();
}
}

Put everything together, and add some test data:

$dumper = new ObjectDump();
$user = new User(“Harry”, “harry@example.com” );
$dumper->addXMLable($user);

$question1 = new Question(“How many datatypes does PHP have?”, new MatchMarker(“12″));
$question1->answer(“12″);
$dumper->addXMLable($question1);

$question2 = new Question(“Name the access control keywords”, new ListMarker(“public,private,protected”));
$question2->answer(“private, public, protected”);
$dumper->addXMLable($question2);

print $dumper;
The ObjectDump class accepts XMLable objects, using a class type hint in the addXMLable() method to enforce this. No matter how different the various objects it is passed may be, the ObjectDump class knows that each will implement an toXML() method, and that’s all that matters to it. The ObjectDump class takes advantage of this knowledge in the output() method, which loops through all the XMLable objects it has aggregated, combining the output from each object’s toXML() into a single XML string. Of course, all we know of each of these objects is that they have the method in question. Class type hinting can enforce object arguments, but return types are not enforced. Interfaces should be well documented to help programmers provide sane implementations in their classes.

Like abstract classes, interfaces describe the characteristics that client code can expect to find working with an object. The PHP language itself works with interfaces, defining the built-in Iterator and IteratorAggregate interfaces. Implement these, and you will be required to implement a set of methods needed by an iterator on the one hand, and by a collection class suitable for iteration on the other.

When the PHP engine encounters an object of type IteratorAggregate in a foreach statement, it uses the implemented methods it, and the Iterator object it generates, are bound to have in order to traverse the collection.

An interface is useful in this context for three reasons:

Functionality is defined. The PHP engine knows it can invoke valid() and current() methods (among others) in any class that implements Iterator.
Interfaces do not interfere with normal inheritance. Your class can extend another and still implement Iterator.
As implementer you are free to decide how a collection should be traversed. Want to implement a filter of some kind? Go ahead, it’s up to you.
Summary
PHP is pretty relaxed about type, whether built-in or user-defined. You are free to assign any type to a variable, and most of the time you can pass any type as a method or function argument. This flexibility can and should be used. By constraining type with hinting in some instances, however, you can make your classes safer for client code.

Abstract classes and interfaces can be used to separate interface from implementation, eliminating tangles of conditional code, and grouping related functionality together.

Type hints complement abstract classes and interfaces. Abstract methods that include hints in their argument lists define an interface that client code can depend upon. On the other hand, there is no hinting for primitive types, and none for values returned by methods, so you are not freed from the need to monitor the types that end up in your variables.

About the Author
Matt Zandstra is a writer and consultant specializing in server programming and training. With his business partner, Max Guglielmino, he runs Corrosive, a technical agency that provides open source/open standards training and plans, designs and builds Internet applications

Matt is the author of SAMS Teach Yourself PHP in 24 Hours. His recent article on PHP 5′s Reflection API appeared in January’s Linux Magazine. He is currently working on a book about object-oriented PHP.