home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Book HomePHP CookbookSearch this book

Chapter 7. Classes and Objects

7.1. Introduction

At first, PHP wasn't an object-oriented (OO) language. As it evolved, more and more object-oriented features appeared. First, you could define classes, but there were no constructors. Then, constructors appeared, but there were no destructors. Slowly but surely, as more people began to push the limits of PHP's syntax, additional features were added to satisfy the demand.

However, if you're the type of person who wishes PHP to be a true OO language, you'll probably be disappointed. At its heart, PHP is a procedural language. It isn't Java. But, if you're the type of person who wants to use some OO features in your code, PHP is probably right for you.

A class is a package containing two things: data and methods to access and modify that data. The data portion consists of variables; they're known as properties. The other part of a class is a set of functions that can alter a class' properties; they're called methods.

When we define a class, we don't define an object that can be accessed and manipulated. Instead, we define a template for an object. From this blueprint, we create malleable objects through a process known as instantiation . A program can have multiple objects of the same class, just as a person can have more than one book or many pieces of fruit.

Classes also live in a defined hierarchy. At the top of the chain, there is a generic class. In PHP, this class is named stdClass, for "standard class." Each class down the line is more specialized than its parent. For example, a parent class could be a building. Buildings can be further divided into residential and commercial. Residential buildings can be further subdivided into houses and apartment buildings, and so forth.

Both houses and apartment buildings have the same set of properties as all residential buildings, just as residential and commercial buildings share some things in common. When classes are used to express these parent-child relationships, the child class inherits the properties and methods defined in the parent class. This allows you to reuse the code from the parent class and requires you to write code only to adapt the new child to its specialized circumstances. This is called inheritance and is one of the major advantages of classes over functions. The process of defining a child class from a parent is known as subclassing or extending.

Objects play another role in PHP outside their traditional OO position. Since PHP can't use more than one namespace, the ability for a class to package multiple properties into a single object is extremely helpful. It allows clearly demarcated separate areas for variables.

Classes in PHP are easy to define and create:

class guest_book {
    var $comments;
    var $last_visitor;

    function update($comment, $visitor) {
        ...
    }

}

The class keyword defines an class, just as function defines a function. Properties are declared using the var keyword. Method declaration is identical to how functions are defined.

The new keyword instantiates an object:

$gb = new guest_book;

Object instantiation is covered in more detail in Recipe 7.2.

Inside a class, you can optionally declare properties using var. There's no requirement to do so, but it is a useful way to reveal all the class' variables. Since PHP doesn't force you to predeclare all your variables, it's possible to create one inside a class without PHP throwing an error or otherwise letting you know. This can cause the list of variables at the top of a class definition to be misleading, because it's not the same as the list of variables actually in the class.

Besides declaring a property, you can also assign it a value:

var $last_visitor = 'Donnan';

You can assign constant values only using this construct:

var $last_visitor = 'Donnan';         // okay
var $last_visitor = 9;                // okay
var $last_visitor = array('Jesse');   // okay
var $last_visitor = pick_visitor( );   // bad
var $last_visitor = 'Chris' . '9';    // bad

If you try to assign something else, PHP dies with a parse error.

To assign a non-constant value to a variable, do it from a method inside the class.

var $last_visitor;

function update($comment, $visitor) {
    if (!empty($comment)) {
        array_unshift($this->comments, $comment);
        $this->last_visitor = $visitor;
    }
}

If the visitor left a comment, you add it to the top of the array of comments and set that person as the latest visitor to the guest book. The variable $this is a special variable that refers to the current object. So, to access the $size property of an object from inside that object, refer to $this->size.

To assign nonconstant values to variables upon instantiation, assign them in the class constructor. The class constructor is a method automatically called when a new object is created, and it has the same name as your class:

class guest_book {
    var $comments;
    var $last_visitor;

    function guest_book($user) {
        $dbh  =  mysql_connect('localhost', 'username', 'password');
        $db   =  mysql_select_db('sites');
        $user =  mysql_real_escape_string($user);
        $sql  = "SELECT comments, last_visitor FROM guest_books WHERE user='$user'";
        $r    =  mysql_query($sql);

        if ($obj  = mysql_fetch_object($r)) {
            $this->comments = $obj->comments;
            $this->last_visitor = $obj->last_visitor;
        }
    }
}

$gb = new guest_book('stewart');

Constructors are covered in Recipe 7.3. Note that mysql_real_escape_string() is new as of PHP 4.3; for earlier versions, use mysql_escape_string().

Be careful not to mistakenly type $this->$size. This is legal, but it's not the same as $this->size. Instead, it accesses the property of the object whose name is the value stored in the $size variable. More often then not, $size is undefined, so $this->$size appears empty. For more on variable property names, see Recipe 6.6.

Besides using -> to access a method or member variable, you can also use ::. This syntax can access static methods in a class. These methods are identical for every instance of an class, because they can't rely on instance-specific data. For example:

class convert {
    // convert from Celsius to Fahrenheit
    function c2f($degrees) {
        return (1.8 * $degrees) + 32;
    }
}

$f = convert::c2f(100); // 212

To implement inheritance by extending an existing class, use the extends keyword:

class xhtml extends xml {

}

Child classes inherit parent methods and can optionally choose to implement their own specific versions:

class DB {
    var $result;

    function getResult() {
        return $this->result;
    }

    function query($sql) {
        error_log("query() must be overridden by a database-specific child");
        return false;
    }
}

class MySQL extends DB {
    function query($sql) {
        $this->result =  mysql_query($sql);
    }
}

The MySQL class above inherits the getResult( ) method unchanged from the parent DB class, but has its own MySQL-specific query( ) method.

Preface the method name with parent :: to explicitly call a parent method:

function escape($sql) {
    $safe_sql = mysql_real_escape_string($sql); // escape special characters
    $safe_sql = parent::escape($safe_sql); // parent method adds '' around $sql
    return $safe_sql;
}

Recipe 7.8 covers accessing overridden methods.

The underlying engine powering PHP is named Zend. PHP 4 uses Zend Engine 1; PHP 5 will use an updated version — Zend Engine 2 (ZE2). ZE2 has an entirely new object model that allows PHP to support many new object-oriented features: constructors and destructors, private methods, exception handling, cloning, and nested classes. In this chapter, we mention when there's a difference in syntax or features between PHP 4 and what's supported by ZE2, so you can plan for the future.



Library Navigation Links

Copyright © 2003 O'Reilly & Associates. All rights reserved.