Programming PHPProgramming PHPSearch this book

6.4. Declaring a Class

To design your program or code library in an object-oriented fashion, you'll need to define your own classes, using the class keyword. A class definition includes the class name and the properties and methods of the class. Class names are case-insensitive and must conform to the rules for PHP identifiers. The class name stdClass is reserved. Here's the syntax for a class definition:

class classname [ extends baseclass ]
{
    [ var $property [ = value ]; ... ]

    [ function functionname (args) {
          // code 
      }
      ...
    ]
}

6.4.1. Declaring Methods

A method is a function defined inside a class. Although PHP imposes no special restrictions, most methods act only on data within the object in which the method resides. Method names beginning with two underscores (__) may be used in the future by PHP (and are currently used for the object serialization methods _ _sleep( ) and _ _wakeup( ), described later in this chapter), so it's recommended that you do not begin your method names with this sequence.

Within a method, the $this variable contains a reference to the object on which the method was called. For instance, if you call $rasmus->birthday( ), inside the birthday( ) method, $this holds the same value as $rasmus. Methods use the $this variable to access the properties of the current object and to call other methods on that object.

Here's a simple class definition of the Person class that shows the $this variable in action:

class Person {
    var $name;

    function get_name ( ) {
        return $this->name;
    }

    function set_name ($new_name) {
        $this->name = $new_name;
    }
}

As you can see, the get_name( ) and set_name( ) methods use $this to access and set the $name property of the current object.

There are no keywords or special syntax for declaring a static method. A static method simply doesn't use $this, because the method is called on a class and not on an object. For example:

class HTML_Stuff {
  function start_table( ) {
    echo "<table border='1'>\n";
  }
  function end_table ( ) {
    echo "</table>\n";
  }
}
HTML_Stuff->start_table( );
// print HTML table rows and columns
HTML_Stuff->end_table( );

6.4.2. Declaring Properties

In the previous definition of the Person class, we explicitly declared the $name property. Property declarations are optional and are simply a courtesy to whoever maintains your program. It's good PHP style to declare your properties, but you can add new properties at any time.

Here's a version of the Person class that has an undeclared $name property:

class Person {
    function get_name ( ) 
    {
        return $this->name;    }

    function set_name ($new_name) {
        $this->name = $new_name;
    }
}

You can assign default values to properties, but those default values must be simple constants:

var $name = 'J Doe';       // works
var $age  = 0;             // works
var $day  = 60*60*24;      // doesn't work

6.4.3. Inheritance

To inherit the properties and methods from another class, use the extends keyword in the class definition, followed by the name of the base class:

class Person {
  var $name, $address, $age;
}

class Employee extends Person {
  var $position, $salary;
}

The Employee class contains the $position and $salary properties, as well as the $name, $address, and $age properties inherited from the Person class.

I f a derived class has a property or method with the same name as one in its parent class, the property or method in the derived class takes precedence over, or overrides, the property or method in the parent class. Referencing the property returns the value of the property on the child, while referencing the method calls the method on the child.

To access an overridden method, use the parent::method( ) notation:

parent::birthday();          // call parent class's birthday( ) method

A common mistake is to hardcode the name of the parent class into calls to overridden methods:

Creature::birthday( );        // when Creature is the parent class

This is a mistake because it distributes knowledge of the parent class's name all over the derived class. Using parent:: centralizes the knowledge of the parent class in the extends clause.

6.4.4. Constructors

You may also provide a list of arguments following the class name when instantiating an object:

$person = new Person('Fred', 35);

These arguments are passed to the class's constructor, a special function that initializes the properties of the class.

A constructor is a function with the same name as the class in which it is defined. Here's a constructor for the Person class:

class Person {
    function Person ($name, $age) {
        $this->name = $name;
        $this->age  = $age;
    }
}

PHP does not provide for an automatic chain of constructors; that is, if you instantiate an object of a derived class, only the constructor in the derived class is automatically called. For the constructor of the parent class to be called, the constructor in the derived class must explicitly call the constructor. In this example, the Employee class constructor calls the Person constructor:

class Person {
  var $name, $address, $age;

  function Person($name, $address, $age) {
    $this->name = $name;
    $this->address = $address;
    $this->age = $age;
  }
}

class Employee extends Person {
  var $position, $salary;

  function Employee($name, $address, $age, $position, $salary) {
    $this->Person($name, $address, $age);
    $this->position = $position;
    $this->salary = $salary;
  }
}

6.4.5. References

When you assign an object to another variable, you create a copy:

$fred = new Person;
$copy = $fred;
$fred->name("Fred");
print $copy->name();      // does not print "Fred"

You now have two Person objects, $fred and $copy, with independent property values. This is also the case when you assign the results of a call to a constructor, as shown here:

$fred = new Person;

The object created by the Person constructor is copied, and the copy is stored in $fred. This means that $this in the constructor and $fred actually refer to two different objects. If the constructor creates an alias to $this through a reference, it won't create an alias to $fred. For example:

$people = array();
class Person {
    function Person () {
      global $people;
      $people[] =& $this;
    }
}
$fred = new Person;
$fred->name = "Fred";
$barney =& new Person;
$barney->name = "Barney";
var_dump($people);
array(2) {
   [0]=>
   &object(person)(0) {
   }
   [1]=>
   &object(person)(1) {
     ["name"]=>
     string(6) "Barney"
   }
}

$fred is a copy of the object that the constructor stored in $people[0], while $barney is an alias for the object that the constructor stored in $people[1]. When we change the properties of $fred, we're not changing the object that is in $people[0]. However, when we change the properties of $barney, we are changing the object in $people[1].

To prevent copying on assignment, assign by reference:

$obj =& new Class;

This code makes $obj an alias for the new object, which was $this in the constructor. If the constructor stores a reference to $this, it keeps a reference to $obj.

The documentation for a class should say whether you need to use =& with its constructor. In most cases, this isn't necessary.



Library Navigation Links

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