<<

. 40
( 132 .)



>>

abstract class TextBox implements Drawable
{
Chapter 7: Writing Organized and Readable Code 213

private $_text;

public function __construct($text)
{
$this->_text = $text;
}
private function style()
{
return “font-family:™Helvetica Neue™,Helvetica,sans-serif;”;
}
final protected function text()
{
return <<<EOT
<font style=”{$this->style()}”>{$this->_text}</font>
EOT;
}
}

This is a class that defines the way text will be displayed by later, non-abstract
classes. A couple of new keywords pop up here that need some explanation.
Public, protected, and private define who has access to a property or a
method. In this class, you can see that the $_text property is private. That means
that only the methods of the TextBox class can read or change the contents of that
property, not even classes that inherit from TextBox. The same applies to the
style() method.
The __construct() method, on the other hand, is public. That means anyone
can call it. This is a special method that gets called automatically when you create
an object, using the keyword new, like so:

$object = new MyClass;

In prior versions of PHP, the constructor method had to have the same name as
the class. In our first example of what a class looks like, for instance, the
TextBox() is the constructor method. Now we can use the generic name __con-
struct() instead. This not only makes maintenance easier, but also solves some
issues with inheritance in earlier versions.
In between private and public is protected. A protected property or method
can be used directly by the class in which it™s declared and any child of that class,
but not by the general public (that is, code outside of the classes). So, in our exam-
ple here, a class that extends TextBox can™t call the style() method, but it can call
text().
What it can™t do is declare its own version of text(), though. That™s because of
the other keyword we use in its declaration, final. Final means what it sounds
214 Part II: Working with PHP

like it means: the end of the road for this method name. For protected or public
methods that aren™t declared to be final, you can do things like this:

class ParentClass
{
public function sayHello()
{
print $this->Hello();
}
protected function Hello()
{
return “Hello!\n”;
}
}
class ChildClass extends ParentClass
{
protected function Hello()
{
return “Howdy!\n”;
}
}
$p = new ParentClass;
$p->sayHello(); // prints out “Hello!\n”
$c = new ChildClass;
$c->sayHello(); // prints out “Howdy!\n”

However, if we declare the Hello() method of the ParentClass class to be
final, instead of printing out Howdy!, you get:

PHP Fatal error: Cannot override final method parentclass::hello()
in /my/pathname/test.php on line 13

So in our example, TextBox is reserving to itself the definition of text(). This
means that we have some degree of confidence that we can change, say, the style
definitions used to format text and have it be reflected in all the classes that are
descended from TextBox.
The other thing to note about TextBox (which is a busy little class for something
that isn™t even real) is this:

abstract class TextBox implements Drawable

But doesn™t the Drawable interface require a draw() method? No draw()
method in TextBox? Typo?
Nope. Instead, by declaring that it implements Drawable without doing anything
about it, TextBox is forcing any class that inherits it to supply its own draw()
Chapter 7: Writing Organized and Readable Code 215

method, doing whatever is appropriate for that particular class, like the TitleBox
does in the next section:

INHERITANCE
class TitleBox extends TextBox
{
public function draw($return=false)
{
$output = “<h3>{$this->text()}</h3>”;
if ($return)
return $output;
else
print $output;
}
}

Okay, so we™ve actually talked about inheritance before this. But now you can
see it in action. TitleBox is a regular old class that you can use to create regular
old objects. And as you can see in Figure 7-1, it doesn™t have to do very much ” just
define the draw() method required by the Drawable interface, which TitleBox
gets from its parent class, TextBox. If we put all of the pieces together, and add one
last step ” the creation of an object that we can use ” we can even make words
appear on a Web page (see Figure 7-1):

$title = new TitleBox(“Greetings!”);
$title->draw();




Figure 7-1: A TitleBox example


And here™s a slightly fancier example, again building on the code we™ve seen up
until now, only this time in color!
216 Part II: Working with PHP

class AlertBox extends TextBox implements Color, Rectangle
{
protected $_color;

public function __construct($text=™oops™,$color = ˜yellow™)
{
// notice that we could be setting height and width
// in the constructor, but instead
// this class has them hard-coded
// (i.e. all alert boxes are the same size)

$this->_color = $color;
parent::__construct($text);
}

public function height()
{
return 100;
}

public function width()
{
return 200;
}

public function color()
{
return $this->_color;
}

public function draw($return=false)
{
$output = <<<EOT
<table height=”{$this->height()}” width=”{$this->width()}”
border=”1”>
<tr>
<td bgcolor=”{$this->color()}” align=”center”>{$this->text()}</td>
</tr>
</table>
EOT;
if ($return)
return $output;
else
print $output;
}
Chapter 7: Writing Organized and Readable Code 217

}
$alert = new AlertBox(“Warning! Object Alert!”);
$alert->draw();

Notice the height() and width() methods. These are good examples of meth-
ods that answer questions, rather than perform actions. An AlertBox doesn™t even
have a width or height property; instead, the methods return hard-coded values.
But code that uses an AlertBox object doesn™t have to care at all about any of that.
It knows that it can call $object->height() to find out how tall it is and
$object->width() to find out how wide, and that™s all it needs.
Figure 7-2 shows you what it looks like in action.




Figure 7-2: An AlertBox example


Where this all gets good is in the combination of features, of course. On the CD,
there™s a more complete example using the code we™ve seen in this chapter, in the
/oop directory. One part of what you™ll find in there is a Page class that draws an
entire HTML page built up out of smaller components that are themselves instances
of the kinds of classes we™ve been looking at. You just line them up when you cre-
ate your Page object and tell the Page to draw:

$page = new Page($title,$logo,$alert,$ad,$biglogo);
$page->draw();

The Page class takes care of making sure that everything you hand it can be
drawn:

class Page implements Drawable
{
protected $_things = array();

public function __construct()
218 Part II: Working with PHP

{
$args = func_get_args();
foreach ($args as $i => $arg)
{
if ($arg instanceof Drawable)
$this->_things[] = $arg;
else
error_log(“Rejecting Page item #{$i} - not drawable:
“.var_export($arg,TRUE));
}
}

Then it calls its own draw() method to display them. You can even create a new
subclass of Page, something like SubPage or BoxSet that arranges its objects in a
particular way, and then hand an instance of that subclass to your Page object like
any other Drawable object. You can see the possibilities that might have.

Object cloning
In prior versions of PHP, making a copy of an object was nothing special:

$a = new MyClass();
$b = $a;

Voila, $b was a copy of $a. But returning a reference to a particular object was
more of a chore:

function &returnObject()
{
$a =& new MyClass();
return $a;
}
$b =& $a;

Now, it™s the other way around. All object variables are references. If you create
a new instance of MyClass in $a and assign $a to $b, you still have only one
MyClass object out there. You™ve just got two different variables referencing it.
Normally, that™s what you want ” it makes it a lot easier to pass objects in and out
of methods and function calls, for one thing. But sometimes you need the old
behavior ” you want to end up with two different instances of MyClass, one in $a
and the other in $b. For that, you have the __clone() method.

$a = new MyClass();
$b = $a->__clone();
Chapter 7: Writing Organized and Readable Code 219

Every class can just leave cloning to the built-in __clone() method, available
with every object at no extra cost. Or you can write your own __clone() method
to do things like create new separate database connections, erase temporary storage
variables, reset counters, and so on.

Destructors
PHP now lets you declare not only generic constructor methods, using the name

<<

. 40
( 132 .)



>>