PHP Objects, Patterns and Practice (3rd edition)

(Barry) #1

CHAPTER 4 ■ ADVANCED FEATURES


PHP Fatal error: Class ErroredWriter contains 1 abstract method and
must therefore be declared abstract or implement the remaining methods
(ShopProductWriter::write) in...


So any class that extends an abstract class must implement all abstract methods or itself be declared
abstract. An extending class is responsible for more than simply implementing an abstract method. In
doing so, it must reproduce the method signature. This means that the access control of the
implementing method cannot be stricter than that of the abstract method. The implementing method
should also require the same number of arguments as the abstract method, reproducing any class type
hinting.
Here are two implementations of ShopProductWriter():


class XmlProductWriter extends ShopProductWriter{
public function write() {
$str = '<?xml version="1.0" encoding="UTF-8"?>'."\n";
$str .= "\n";
foreach ( $this->products as $shopProduct ) {
$str .= "\t<product title=\"{$shopProduct->getTitle()}\">\n";
$str .= "\t\t

\n";
$str .= "\t\t{$shopProduct->getSummaryLine()}\n";
$str .= "\t\t
\n";
$str .= "\t\n";
}
$str .= "\n";
print $str;
}
}


class TextProductWriter extends ShopProductWriter{
public function write() {
$str = "PRODUCTS:\n";
foreach ( $this->products as $shopProduct ) {
$str .= $shopProduct->getSummaryLine()."\n";
}
print $str;
}
}


I create two classes, each with its own implementation of the write() method. The first outputs
XML and the second outputs text. A method that requires a ShopProductWriter object will not know
which of these two classes it is receiving but can be absolutely certain that a write() method is
implemented. Note that I don’t test the type of $products before treating it as an array. This is because
this property is initialized as an empty array in the ShopProductWriter.
Abstract classes were often approximated in PHP 4 by creating methods that contain warnings or
even die() statements. This forces a derived class to implement the abstract methods or risk having
them invoked.


class AbstractClass {
function abstractFunction() {
die( "AbstractClass::abstractFunction() is abstract\n" );
}
}

Free download pdf