Advanced ClassesThus far, I have discussed in large part things that existed to one extent or another in PHP 4. In this and following sections, I'll introduce some of those new features to the PHP 5 object model that separate it from PHP 4.
Abstract Classes and
|
NOTEAbstract classes can be extended without implementing all the abstract methods defined within. That is to say, a child class must also be declared as abstract if it does not implement all abstract methods of its parent(s). |
Unlike
abstract
classes, which provide a means to express abstract concepts in programming, interfaces are designed to assure functionality within a class. Specifically, interfaces are a means to define a set of methods a class claiming to implement that interface must have. To use interfaces, they must be declared with the
interface
keyword as shown
<?php
interface printable {
public function printme();
}
?>
Interfaces, to be useful, must be implemented by one or more classes. In Listing 13.16 I have defined the printable interface, which dictates that any class implementing this interface must implement the printme() method. To create a class that implements an interface such as this, in the class definition the implements keyword is used, followed by a list of interfaces implemented (see Listing 13.17):
<?php
class Integer implements printable {
private $value;
public function getValue() {
return (int)$this->value;
}
public function printme() {
echo (int)$this->value;
}
}
?>
In Listing 13.17, I have modified the original Integer class from Listing 13.15 to implement the printable interface defined in Listing 13.16. As a class that implements this interface, it has effectively ensured that the Integer class will provide those methods defined by the interface.
Now that I have defined a class that implements an interface, I can use that fact within my code to ensure that any functions or methods which require certain functionality from a class will have it available from the class, without checking for the specific class name using type hinting or the instanceof operator. Rather, you can use these techniques to specify the printable interface as shown in Listing 13.18:
<?php
interface printable {
public function printme();
}
abstract class Number {
private $value;
abstract public function value();
public function reset() {
$this->value = NULL;
}
}
class Integer extends Number implements printable {
private $value;
function __construct($value) {
$this->value = $value;
}
public function getValue() {
return (int)$this->value;
}
public function printme() {
echo (int)$this->value;
}
}
/* Create a function which requires the printable interface. */
function printNumber(printable $myObject) {
/* If this function is called, we can be
certain that it has a printme() method */
$myObject->printme();
}
$inst = new Integer(10);
printNumber($inst);
?>
In Listing 13.18, interfaces have been used to ensure that the printNumber() function will always receive an object that has a printme() method. Another useful feature is that a single class can implement multiple different interfaces. An example is shown in Listing 13.19:
<?php
interface printable {
public function printme();
}
interface Inumber {
public function reset();
}
class Integer implements printable, Inumber {
private $value;
function __construct($value) {
$this->value = $value;
}
public function printme() {
echo (int)$this->value;
}
public function reset() {
$this->value = NULL;
}
public function value() {
return (int)$this->value;
}
}
function resetNumber(Inumber $obj) {
$obj->reset();
}
function printNumber(printable $obj) {
$obj->printme();
}
$inst = new Integer(10);
printNumber($inst);
resetNumber($inst);
?>
The concept of a final class or method is used to provide the developer a means of control over inheritance. Classes or methods declared as final cannot be extended and/or overloaded by child classes. To ensure that a particular class or method is never overloaded, simply add the final keyword to the method or class definition, as shown in Listing 13.20:
<?php
final class NoExtending {
public function myFunction() {
/* Function logic */
}
}
class restrictedExtending {
final public function anotherFunc() {
/* Function logic */
}
}
class myChild extends restrictedExtending {
public function thirdFunction() {
/* Function logic */
}
}
?>
In Listing 13.20, three individual classes have been defined. The first of these classes, the NoExtending class, cannot ever be the parent of a child class because the entire class itself has been declared final . On the other hand, although the restrictedExtending class can be extended, the anotherFunc() method within it may never be overloaded by a child class. As you can see, the final keyword is useful to ensure that things are done in a particular way within your object structures while still allowing people to implement their own subclasses.