
Advanced PHP Programming
.pdf
38Chapter 2 Object-Oriented Programming Through Design Patterns
function goodbye($name)
{
return “Goodbye $name!\n”;
}
function age($birthday) { $ts = strtotime($birthday);
if($ts === -1) { return “Unknown”;
}
else {
$diff = time() - $ts;
return floor($diff/(24*60*60*365));
}
}
$name = “george”; $bday = “10 Oct 1973”;
echo hello($name);
echo “You are “.age($bday).” years old.\n”; echo goodbye($name);
? >
Introduction to OO Programming
It is important to note that in procedural programming, the functions and the data are separated from one another. In OO programming, data and the functions to manipulate the data are tied together in objects. Objects contain both data (called attributes or properties) and functions to manipulate that data (called methods).
An object is defined by the class of which it is an instance. A class defines the attributes that an object has, as well as the methods it may employ.You create an object by instantiating a class. Instantiation creates a new object, initializes all its attributes, and calls its constructor, which is a function that performs any setup operations. A class constructor in PHP5 should be named _ _constructor() so that the engine knows how to identify it.The following example creates a simple class named User, instantiates it, and calls its two methods:
<?php
class User { public $name; public $birthday;
public function _ _construct($name, $birthday)
{
$this->name = $name; $this->birthday = $birthday;
}
public function hello()
{

Introduction to OO Programming |
39 |
return “Hello $this->name!\n”;
}
public function goodbye()
{
return “Goodbye $this->name!\n”;
}
public function age() {
$ts = strtotime($this->birthday); if($ts === -1) {
return “Unknown”;
}
else {
$diff = time() - $ts;
return floor($diff/(24*60*60*365)) ;
}
}
}
$user = new User(‘george’, ‘10 Oct 1973’); echo $user->hello();
echo “You are “.$user->age().” years old.\n”; echo $user->goodbye();
?>
Running this causes the following to appear:
Hello george!
You are 29 years old.
Goodbye george!
The constructor in this example is extremely basic; it only initializes two attributes, name and birthday.The methods are also simple. Notice that $this is automatically created inside the class methods, and it represents the User object.To access a property or method, you use the -> notation.
On the surface, an object doesn’t seem too different from an associative array and a collection of functions that act on it.There are some important additional properties, though, as described in the following sections:
nInheritance—Inheritance is the ability to derive new classes from existing ones and inherit or override their attributes and methods.
nEncapsulation—Encapsulation is the ability to hide data from users of the class.
nSpecial Methods—As shown earlier in this section, classes allow for constructors that can perform setup work (such as initializing attributes) whenever a new object is created.They have other event callbacks that are triggered on other common events as well: on copy, on destruction, and so on.

40 Chapter 2 Object-Oriented Programming Through Design Patterns
nPolymorphism—When two classes implement the same external methods, they should be able to be used interchangeably in functions. Because fully understanding polymorphism requires a larger knowledge base than you currently have, we’ll put off discussion of it until later in this chapter, in the section “Polymorphism.”
Inheritance
You use inheritance when you want to create a new class that has properties or behaviors similar to those of an existing class.To provide inheritance, PHP supports the ability for a class to extend an existing class.When you extend a class, the new class inherits all the properties and methods of the parent (with a couple exceptions, as described later in this chapter).You can both add new methods and properties and override the exiting ones. An inheritance relationship is defined with the word extends. Let’s extend User to make a new class representing users with administrative privileges.We will augment the class by selecting the user’s password from an NDBM file and providing a comparison function to compare the user’s password with the password the user supplies:
class AdminUser extends User{ public $password;
public function _ _construct($name, $birthday)
{
parent::_ _construct($name, $birthday);
$db = dba_popen(“/data/etc/auth.pw”, “r”, “ndbm”); $this->password = dba_fetch($db, $name); dba_close($db);
}
public function authenticate($suppliedPassword)
{
if($this->password === $suppliedPassword) { return true;
}
else {
return false;
}
}
}
Although it is quite short, AdminUser automatically inherits all the methods from User, so you can call hello(), goodbye(), and age(). Notice that you must manually call the constructor of the parent class as parent::_ _constructor(); PHP5 does not automatically call parent constructors. parent is as keyword that resolves to a class’s parent class.

Introduction to OO Programming |
41 |
Encapsulation
Users coming from a procedural language or PHP4 might wonder what all the public stuff floating around is.Version 5 of PHP provides data-hiding capabilities with public, protected, and private data attributes and methods.These are commonly referred to as PPP (for public, protected, private) and carry the standard semantics:
nPublic—A public variable or method can be accessed directly by any user of the class.
nProtected—A protected variable or method cannot be accessed by users of the class but can be accessed inside a subclass that inherits from the class.
nPrivate—A private variable or method can only be accessed internally from the class in which it is defined.This means that a private variable or method cannot be called from a child that extends the class.
Encapsulation allows you to define a public interface that regulates the ways in which users can interact with a class.You can refactor, or alter, methods that aren’t public, without worrying about breaking code that depends on the class.You can refactor private methods with impunity.The refactoring of protected methods requires more care, to avoid breaking the classes’ subclasses.
Encapsulation is not necessary in PHP (if it is omitted, methods and properties are assumed to be public), but it should be used when possible. Even in a single-programmer environment, and especially in team environments, the temptation to avoid the public interface of an object and take a shortcut by using supposedly internal methods is very high.This quickly leads to unmaintainable code, though, because instead of a simple public interface having to be consistent, all the methods in a class are unable to be refactored for fear of causing a bug in a class that uses that method. Using PPP binds you to this agreement and ensures that only public methods are used by external code, regardless of the temptation to shortcut.
Static (or Class) Attributes and Methods
In addition, methods and properties in PHP can also be declared static. A static method is bound to a class, rather than an instance of the class (a.k.a., an object). Static methods are called using the syntax ClassName::method(). Inside static methods, $this is not available.
A static property is a class variable that is associated with the class, rather than with an instance of the class.This means that when it is changed, its change is reflected in all instances of the class. Static properties are declared with the static keyword and are accessed via the syntax ClassName::$property.The following example illustrates how static properties work:
class TestClass {
public static $counter;
}
$counter = TestClass::$counter;

42 Chapter 2 Object-Oriented Programming Through Design Patterns
If you need to access a static property inside a class, you can also use the magic keywords self and parent, which resolve to the current class and the parent of the current class, respectively. Using self and parent allows you to avoid having to explicitly reference the class by name. Here is a simple example that uses a static property to assign a unique integer ID to every instance of the class:
class TestClass {
public static $counter = 0; public $id;
public function _ _construct()
{
$this->id = self::$counter++;
}
}
Special Methods
Classes in PHP reserve certain method names as special callbacks to handle certain events.You have already seen _ _construct(), which is automatically called when an object is instantiated. Five other special callbacks are used by classes: _ _get(),
_ _set(), and _ _call() influence the way that class properties and methods are called, and they are covered later in this chapter.The other two are _ _destruct() and
_ _clone().
_ _destruct() is the callback for object destruction. Destructors are useful for closing resources (such as file handles or database connections) that a class creates. In PHP, variables are reference counted.When a variable’s reference count drops to 0, the variable is removed from the system by the garbage collector. If this variable is an object, its
_ _destruct() method is called.
The following small wrapper of the PHP file utilities showcases destructors:
class IO {
public $fh = false;
public function _ _construct($filename, $flags)
{
$this->fh = fopen($filename, $flags);
}
public function _ _destruct()
{
if($this->fh) { fclose($this->fh);
}
}
public function read($length)
{

Introduction to OO Programming |
43 |
if($this->fh) {
return fread($this->fh, $length);
}
}
/* ... */
}
In most cases, creating a destructor is not necessary because PHP cleans up resources at the end of a request. For long-running scripts or scripts that open a large number of files, aggressive resource cleanup is important.
In PHP4, objects are all passed by value.This meant that if you performed the following in PHP4:
$obj = new TestClass;
$copy = $obj;
you would actually create three copies of the class: one in the constructor, one during the assignment of the return value from the constructor to $copy, and one when you assign $copy to $obj.These semantics are completely different from the semantics in most other OO languages, so they have been abandoned in PHP5.
In PHP5, when you create an object, you are returned a handle to that object, which is similar in concept to a reference in C++.When you execute the preceding code under PHP5, you only create a single instance of the object; no copies are made.
To actually copy an object in PHP5, you need to use the built-in _ _clone() method. In the preceding example, to make $copy an actual copy of $obj (and not just another reference to a single object), you need to do this:
$obj = new TestClass;
$copy = $obj->_ _clone();
For some classes, the built-in deep-copy _ _clone() method may not be adequate for your needs, so PHP allows you to override it. Inside the _ _clone() method, you not only have $this, which represents the new object, but also $that, which is the object being cloned. For example, in the TestClass class defined previously in this chapter, if you use the default _ _clone() method, you will copy its id property. Instead, you should rewrite the class as follows:
class TestClass {
public static $counter = 0; public $id;
public $other;
public function _ _construct()
{
$this->id = self::$counter++;
}
public function _ _clone()

44 Chapter 2 Object-Oriented Programming Through Design Patterns
{
$this->other = $that->other;
$this->id = self::$counter++;
}
}
A Brief Introduction to Design Patterns
You have likely heard of design patterns, but you might not know what they are. Design patterns are generalized solutions to classes of problems that software developers encounter frequently.
If you’ve programmed for a long time, you have most likely needed to adapt a library to be accessible via an alternative API.You’re not alone.This is a common problem, and although there is not a general solution that solves all such problems, people have recognized this type of problem and its varying solutions as being recurrent.The fundamental idea of design patterns is that problems and their corresponding solutions tend to follow repeatable patterns.
Design patterns suffer greatly from being overhyped. For years I dismissed design patterns without real consideration. My problems were unique and complex, I thought— they would not fit a mold.This was really short-sighted of me.
Design patterns provide a vocabulary for identification and classification of problems. In Egyptian mythology, deities and other entities had secret names, and if you could discover those names, you could control the deities’ and entities’ power. Design problems are very similar in nature. If you can discern a problem’s true nature and associate it with a known set of analogous (solved) problems, you are most of the way to solving it.
To claim that a single chapter on design patterns is in any way complete would be ridiculous.The following sections explore a few patterns, mainly as a vehicle for showcasing some of the advanced OO techniques available in PHP.
The Adaptor Pattern
The Adaptor pattern is used to provide access to an object via a specific interface. In a purely OO language, the Adaptor pattern specifically addresses providing an alternative API to an object; but in PHP we most often see this pattern as providing an alternative interface to a set of procedural routines.
Providing the ability to interface with a class via a specific API can be helpful for two main reasons:
nIf multiple classes providing similar services implement the same API, you can switch between them at runtime.This is known as polymorphism.This is derived from Latin: Poly means “many,” and morph means “form.”
nA predefined framework for acting on a set of objects may be difficult to change. When incorporating a third-party class that does not comply with the API used by the framework, it is often easiest to use an Adaptor to provide access via the

A Brief Introduction to Design Patterns |
45 |
expected API.
The most common use of adaptors in PHP is not for providing an alternative interface to one class via another (because there is a limited amount of commercial PHP code, and open code can have its interface changed directly). PHP has its roots in being a procedural language; therefore, most of the built-in PHP functions are procedural in nature. When functions need to be accessed sequentially (for example, when you’re making a database query, you need to use mysql_pconnect(), mysql_select_db(), mysql_query(), and mysql_fetch()), a resource is commonly used to hold the connection data, and you pass that into all your functions.Wrapping this entire process in a class can help hide much of the repetitive work and error handling that need to be done.
The idea is to wrap an object interface around the two principal MySQL extension resources: the connection resource and the result resource.The goal is not to write a true abstraction but to simply provide enough wrapper code that you can access all the MySQL extension functions in an OO way and add a bit of additional convenience. Here is a first attempt at such a wrapper class:
class DB_Mysql { |
|
protected $user; |
|
protected $pass; |
|
protected $dbhost; |
|
protected $dbname; |
|
protected $dbh; |
// Database connection handle |
public function _ _construct($user, $pass, $dbhost, $dbname) { $this->user = $user;
$this->pass = $pass; $this->dbhost = $dbhost; $this->dbname = $dbname;
}
protected function connect() {
$this->dbh = mysql_pconnect($this->dbhost, $this->user, $this->pass); if(!is_resource($this->dbh)) {
throw new Exception;
}
if(!mysql_select_db($this->dbname, $this->dbh)) { throw new Exception;
}
}
public function execute($query) { if(!$this->dbh) {
$this->connect();
}
$ret = mysql_query($query, $this->dbh); if(!$ret) {
throw new Exception;

46 Chapter 2 Object-Oriented Programming Through Design Patterns
}
else if(!is_resource($ret)) { return TRUE;
}else {
$stmt = new DB_MysqlStatement($this->dbh, $query); $stmt->result = $ret;
return $stmt;
}
}
}
To use this interface, you just create a new DB_Mysql object and instantiate it with the login credentials for the MySQL database you are logging in to (username, password, hostname, and database name):
$dbh = new DB_Mysql(“testuser”, “testpass”, “localhost”, “testdb”);
$query = “SELECT * FROM users WHERE name = ‘“.mysql_escape_string($name).”‘“;
$stmt = $dbh->execute($query);
This code returns a DB_MysqlStatement object, which is a wrapper you implement around the MySQL return value resource:
class DB_MysqlStatement { protected $result; public $query; protected $dbh;
public function _ _construct($dbh, $query) { $this->query = $query;
$this->dbh = $dbh; if(!is_resource($dbh)) {
throw new Exception(“Not a valid database connection”);
}
}
public function fetch_row() { if(!$this->result) {
throw new Exception(“Query not executed”);
}
return mysql_fetch_row($this->result);
}
public function fetch_assoc() {
return mysql_fetch_assoc($this->result);
}
public function fetchall_assoc() { $retval = array();
while($row = $this->fetch_assoc()) { $retval[] = $row;
}
return $retval;
}
}

A Brief Introduction to Design Patterns |
47 |
To then extract rows from the query as you would by using mysql_fetch_assoc(), you can use this:
while($row = $stmt->fetch_assoc()) {
// process row
}
The following are a few things to note about this implementation:
nIt avoids having to manually call connect() and mysql_select_db().
nIt throws exceptions on error. Exceptions are a new feature in PHP5.We won’t discuss them much here, so you can safely ignore them for now, but the second
half of Chapter 3,“Error Handling,” is dedicated to that topic.
nIt has not bought much convenience.You still have to escape all your data, which is annoying, and there is no way to easily reuse queries.
To address this third issue, you can augment the interface to allow for the wrapper to automatically escape any data you pass it.The easiest way to accomplish this is by providing an emulation of a prepared query.When you execute a query against a database, the raw SQL you pass in must be parsed into a form that the database understands internally. This step involves a certain amount of overhead, so many database systems attempt to cache these results. A user can prepare a query, which causes the database to parse the query and return some sort of resource that is tied to the parsed query representation. A feature that often goes hand-in-hand with this is bind SQL. Bind SQL allows you to parse a query with placeholders for where your variable data will go.Then you can bind parameters to the parsed version of the query prior to execution. On many database systems (notably Oracle), there is a significant performance benefit to using bind SQL.
Versions of MySQL prior to 4.1 do not provide a separate interface for users to prepare queries prior to execution or allow bind SQL. For us, though, passing all the variable data into the process separately provides a convenient place to intercept the variables and escape them before they are inserted into the query. An interface to the new MySQL 4.1 functionality is provided through Georg Richter’s mysqli extension.
To accomplish this, you need to modify DB_Mysql to include a prepare method and DB_MysqlStatement to include bind and execute methods:
class DB_Mysql { /* ... */
public function prepare($query) { if(!$this->dbh) {
$this->connect();
}
return new DB_MysqlStatement($this->dbh, $query);
}
}
class DB_MysqlStatement { public $result;