Tuesday, July 14, 2009

Beginning PHP and Oracle From Novice to Professional by W. Jason Gilmore and Bob Bryla Chapter 6

While for many languages object orientation is simply a matter of course, it took several years before such features were incorporated into PHP. Yet the early forays into adding object-oriented
features to the language were considered by many to be a poor attempt at best. Although the very basic premises of object-oriented programming (OOP) were offered in version 4, several deficiencies exist, including the following:

• An unorthodox object-referencing methodology

• No means for setting the scope (public, private, protected, abstract) of fields and methods

• No standard convention for naming constructors

• Absence of object destructors

• Lack of an object-cloning feature

• Lack of support for interfaces

Thankfully, version 5 eliminated all of the aforementioned hindrances, offering substantial improvements over the original implementation, as well as a bevy of new OOP features. This chapter and the following aim to introduce these new features and enhanced functionality. Before doing so, however, this chapter briefly discusses the advantages of the OOP development model.

■Note While this and the following chapter serve to provide you with an extensive introduction to PHP’s OOP
features, a thorough treatment of their ramifications for the PHP developer is actually worthy of an entire book. Conveniently, Matt Zandstra’s PHP 5 Objects, Patterns, and Practice (Apress, 2004) covers the topic in considerable detail, accompanied by a fascinating introduction to implementing design patterns with PHP and an overview of key development tools such as Phing, PEAR, and phpDocumentor. The second edition of this book will be published
in 2007.

The Benefits of OOP

The birth of object-oriented programming represented a major paradigm shift in development strategy, refocusing attention on an application’s data rather than its logic. To put it another way, OOP shifts the focus from a program’s procedural events toward the real-life entities it ultimately models. The result is an application that closely resembles the world around us.
This section examines three of OOP’s foundational concepts: encapsulation, inheritance, and polymorphism. Together, these three ideals form the basis for the most powerful programming model yet devised.

117

Encapsulation

Programmers enjoy taking things apart and learning how all of the little pieces work together. Although gratifying, attaining such in-depth knowledge of an item’s inner workings isn’t a requirement. For example, millions of people use a computer every day, yet few know how it actually works. The same idea applies to automobiles, microwaves, and any number of other items. We can get away with such ignorance through the use of interfaces. For example, you know that turning the radio dial allows you to change radio stations; never mind the fact that what you’re actually doing is telling the radio to listen to the signal transmitted at a particular frequency, a feat accomplished using a demodulator. Failing to understand this process does not prevent you from using the radio because the interface takes care to hide such details. The practice of separating the user from the true inner workings of an application through well-known interfaces is known as encapsulation.
Object-oriented programming promotes the same notion of hiding the inner workings of the application by publishing well-defined interfaces from which each application component can be accessed. Rather than get bogged down in the gory details, OOP-minded developers design each application component so that it is independent from the others, which not only encourages reuse but also enables the developer to assemble components like a puzzle rather than tightly lash, or couple, them together. These components are known as objects, and objects are created from
a template known as a class, which specifies what sorts of data the object might contain and the behavior one would expect. This strategy offers several advantages:

• The developer can change the application implementation without affecting the object user because the user’s only interaction with the object is via its interface.
• The potential for user error is reduced because of the control exercised over the user’s inter- action with the application.

Inheritance

The many objects constituting our environment can be modeled using a fairly well-defined set of rules. Take, for example, the concept of an employee. All employees share a common set of charac- teristics: name, employee ID, and wage, for instance. However, there are many different types of employees: clerks, supervisors, cashiers, and chief executive officers, among others, each of which likely possesses some superset of those characteristics defined by the generic employee definition. In object-oriented terms, these various employee types inherit the general employee definition, including all of the characteristics and behaviors that contribute to this definition. In turn, each of these specific employee types could be inherited by yet another more specific type. For example, the Clerk type might be inherited by a day clerk and a night clerk, each of which inherits all traits speci- fied by both the employee definition and the clerk definition. Building on this idea, you could then later create a Human class, and then make the Employee class a subclass of Human. The effect would be that the Employee class and all of its derived classes (Clerk, Cashier, Executive, etc.) would immedi- ately inherit all characteristics and behaviors defined by Human.
The object-oriented development methodology places great stock in the concept of inheritance.
This strategy promotes code reusability because it assumes that one will be able to use well-designed classes (i.e., classes that are sufficiently abstract to allow for reuse) within numerous applications.

Polymorphism

Polymorphism, a term originating from the Greek language that means “having multiple forms,” defines OOP’s ability to redefine, or morph, a class’s characteristic or behavior depending upon the context in which it is used.

Returning to the example, suppose that a behavior titled clockIn was included within the employee definition. For employees of class Clerk, this behavior might involve actually using a time clock to timestamp a card. For other types of employees, Programmer for instance, clocking in might involve signing on to the corporate network. Although both classes derive this behavior from the Employee class, the actual implementation of each is dependent upon the context in which “clocking in” is implemented. This is the power of polymorphism.
These three key OOP concepts, encapsulation, inheritance, and polymorphism, are further introduced as they apply to PHP through this chapter and the next.

Key OOP Concepts

This section introduces key object-oriented implementation concepts, including PHP-specific examples.

Classes

Our everyday environment consists of countless entities: plants, people, vehicles, food...we could go on for hours just listing them. Each entity is defined by a particular set of characteristics and behaviors that ultimately serves to define the entity for what it is. For example, a vehicle might be defined as having characteristics such as color, number of tires, make, model, and capacity, and having behav- iors such as stop, go, turn, and honk horn. In the vocabulary of OOP, such an embodiment of an entity’s defining attributes and behaviors is known as a class.
Classes are intended to represent those real-life items that you’d like to manipulate within an application. For example, if you want to create an application for managing a public library, you’d probably want to include classes representing books, magazines, employees, special events, patrons, and anything else that would require oversight. Each of these entities embodies a certain set of char- acteristics and behaviors, better known in OOP as fields and methods, respectively, that define the entity as what it is. PHP’s generalized class creation syntax follows:
class Class_Name
{
// Field declarations defined here
// Method declarations defined here
}

Listing 6-1 depicts a class representing employees.

Listing 6-1. Class Creation

class Employee
{
private $name; private $title; protected $wage;

protected function clockIn() {
echo "Member $this->name clocked in at ".date("h:i:s");
}

protected function clockOut() {
echo "Member $this->name clocked out at ".date("h:i:s");
}
}

Titled Employee, this class defines three fields, name, title, and wage, in addition to two methods, clockIn and clockOut. Don’t worry if you’re not familiar with some of the grammar and syntax; it will become clear later in the chapter.

■Note While no official PHP code conventions exist, consider following the PHP Extension and Application Repository
guidelines when creating your classes. You can learn more about these conventions at http://pear.php.net/. These conventions are used throughout the book.

Objects

A class provides a basis from which you can create specific instances of the entity the class models, better known as objects. For example, an employee management application may include an Employee class. You can then call upon this class to create and maintain specific instances, Sally and Jim,
for example.

■Note The practice of creating objects based on predefined classes is often referred to as class instantiation.

Objects are created using the new keyword, like this:

$employee = new Employee();

Once the object is created, all of the characteristics and behaviors defined within the class are made available to the newly instantiated object. Exactly how this is accomplished is revealed in the following sections.

Fields

Fields are attributes that are intended to describe some aspect of a class. They are quite similar to standard PHP variables, except for a few minor differences, which you’ll learn about in this section. You’ll also learn how to declare and invoke fields and how to restrict access, using field scopes.

Declaring Fields

The rules regarding field declaration are quite similar to those in place for variable declaration; essen- tially, there are none. Because PHP is a loosely typed language, fields don’t even necessarily need to be declared; they can simply be created and assigned simultaneously by a class object, although you’ll rarely want to do that. Instead, common practice is to declare fields at the beginning of the class. Optionally, you can assign them initial values at this time. An example follows:

class Employee
{
public $name = "John";
private $wage;
}

In this example, the two fields, name and wage, are prefaced with a scope descriptor (public or
private), a common practice when declaring fields. Once declared, each field can be used under the terms accorded to it by the scope descriptor. If you don’t know what role scope plays in class fields, don’t worry, that topic is covered later in this chapter.

Invoking Fields

Fields are referred to using the -> operator and, unlike variables, are not prefaced with a dollar sign. Furthermore, because a field’s value typically is specific to a given object, it is correlated to that object like this:

$object->field

For example, the Employee class includes the fields name, title, and wage. If you create an object named $employee of type Employee, you would refer to these fields like this:
$employee->name
$employee->title
$employee->wage

When you refer to a field from within the class in which it is defined, it is still prefaced with the
-> operator, although instead of correlating it to the class name, you use the $this keyword. $this implies that you’re referring to the field residing in the same class in which the field is being accessed or manipulated. Therefore, if you were to create a method for setting the name field in the Employee class, it might look like this:

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

Field Scopes

PHP supports five class field scopes: public, private, protected, final, and static. The first four are introduced in this section, and the static scope is introduced in the later section, “Static Class Members.”

Public

You can declare fields in the public scope by prefacing the field with the keyword public. An example follows:
class Employee
{
public $name;
// Other field and method declarations follow...
}

Public fields can then be manipulated and accessed directly by a corresponding object, like so:

$employee = new Employee();
$employee->name = "Mary Swanson";
$name = $employee->name;
echo "New employee: $name";

Executing this code produces the following:

New employee: Mary Swanson

Although this might seem like a logical means for maintaining class fields, public fields are actually generally considered taboo to OOP, and for good reason. The reason for shunning such an imple- mentation is that such direct access robs the class of a convenient means for enforcing any sort of data validation. For example, nothing would prevent the user from assigning name like so:

$employee->name = "12345";

This is certainly not the kind of input you are expecting. To prevent such mishaps from occurring, two solutions are available. One solution involves encapsulating the data within the object, making it available only via a series of interfaces, known as public methods. Data encapsulated in this way is said to be private in scope. The second recommended solution involves the use of properties and is actually quite similar to the first solution, although it is a tad more convenient in most cases. Private
scoping is introduced next, and the section on properties soon follows.

■Note As of PHP 6, you can use var in place of public. Before PHP 6, doing so raised a warning. However, you
should be sure to use var for compatibility reasons should you be creating software that might be used on disparate server installations.

Private

Private fields are only accessible from within the class in which they are defined. An example follows:

class Employee
{
private $name;
private $telephone;
}

Fields designated as private are not directly accessible by an instantiated object, nor are they
available to subclasses. If you want to make these fields available to subclasses, consider using the protected scope instead, introduced next. Instead, private fields must be accessed via publicly exposed interfaces, which satisfies one of OOP’s main tenets introduced at the beginning of this chapter: encapsulation. Consider the following example, in which a private field is manipulated by a public method:

class Employee
{
private $name;
public function setName($name) {
$this->name = $name;
}
}

$staff = new Employee;
$staff->setName("Mary");

Encapsulating the management of such fields within a method enables the developer to main- tain tight control over how that field is set. For example, you could add to the setName() method’s capabilities to validate that the name is set to solely alphabetical characters and to ensure that it isn’t blank. This strategy is much more reliable than leaving it to the end user to provide valid information.

Protected

Just like functions often require variables intended for use only within the function, classes can include fields used for solely internal purposes. Such fields are deemed protected and are prefaced accordingly. An example follows:

class Employee
{
protected $wage;
}

Protected fields are also made available to inherited classes for access and manipulation, a trait not shared by private fields. Any attempt by an object to access a protected field will result in a fatal error. Therefore, if you plan on extending the class, you should use protected fields in lieu of private fields.

Final

Marking a field as final prevents it from being overridden by a subclass, a matter discussed in further detail in the next chapter. A finalized field is declared like so:

class Employee
{
final $ssn;
}

You can also declare methods as final; the procedure for doing so is described in the later
section “Methods.”

Properties

Properties are a particularly convincing example of the powerful features OOP has to offer, ensuring protection of fields by forcing access and manipulation to take place through methods, yet allowing the data to be accessed as if it were a public field. These methods, known as accessors and mutators, or more informally as getters and setters, are automatically triggered whenever the field is accessed or manipulated, respectively.
Unfortunately, PHP does not offer the property functionality that you might be used to if you’re familiar with other OOP languages such as C++ and Java. Therefore, you’ll need to make do with using public methods to imitate such functionality. For example, you might create getter and setter methods for the property name by declaring two functions, getName() and setName(), respectively, and embedding the appropriate syntax within each. An example of this strategy is presented at the conclusion of this section.
PHP version 5 and newer does offer some semblance of support for properties, done by over- loading the __set and __get methods. These methods are invoked if you attempt to reference a member variable that does not exist within the class definition. Properties can be used for a variety of purposes, such as to invoke an error message, or even to extend the class by actually creating new variables on the fly. Both __get and __set are introduced in this section.

Setting Properties

The mutator, or setter method, is responsible for both hiding property assignment implementation and validating class data before assigning it to a class field. Its prototype follows:

boolean __set([string property name],[mixed value_to_assign])

It takes as input a property name and a corresponding value, returning TRUE if the method is successfully executed, and FALSE otherwise. An example follows:

class Employee
{
var $name;
function __set($propName, $propValue)
{
echo "Nonexistent variable: \$$propName!";
}
}

$employee = new Employee ();
$employee->name = "Mario";
$employee->title = "Executive Chef";

This results in the following output:

Nonexistent variable: $title!

Of course, you could use this method to actually extend the class with new properties, like this:

class Employee
{
var $name;
function __set($propName, $propValue)
{
$this->$propName = $propValue;
}
}

$employee = new Employee();
$employee->name = "Mario";
$employee->title = "Executive Chef";
echo "Name: ".$employee->name;
echo "<br />";
echo "Title: ".$employee->title;

This produces the following:

Name: Mario
Title: Executive Chef

Getting Properties

The accessor, or mutator method, is responsible for encapsulating the code required for retrieving a class variable. Its prototype follows:

boolean __get([string property name])

It takes as input one parameter, the name of the property whose value you’d like to retrieve. It should return the value TRUE on successful execution, and FALSE otherwise. An example follows:

class Employee
{
var $name; var $city; protected $wage;

function __get($propName)
{
echo "__get called!<br />";
$vars = array("name","city");
if (in_array($propName, $vars))
{

return $this->$propName;
} else {
return "No such variable!";
}
}

}

$employee = new Employee();
$employee->name = "Mario";

echo $employee->name."<br />";
echo $employee->age;

This returns the following:

Mario
__get called!
No such variable!

Creating Custom Getters and Setters

Frankly, although there are some benefits to the __set() and __get() methods, they really aren’t sufficient for managing properties in a complex object-oriented application. Because PHP doesn’t offer support for the creation of properties in the fashion that Java or C# does, you need to imple- ment your own methodology. Consider creating two methods for each private field, like so:
<?php
class Employee
{
private $name;
// Getter
public function getName() {
return $this->name;
}
// Setter
public function setName($name) {
$this->name = $name;
}
}
?>

Although such a strategy doesn’t offer the same convenience as using properties, it does encap- sulate management and retrieval tasks using a standardized naming convention. Of course, you should add additional validation functionality to the setter; however, this simple example should suffice to drive the point home.

Constants

You can define constants, or values that are not intended to change, within a class. These values will remain unchanged throughout the lifetime of any object instantiated from that class. Class constants are created like so:

const NAME = 'VALUE';

For example, suppose you create a math-related class that contains a number of methods defining mathematical functions, in addition to numerous constants:

class math_functions
{
const PI = '3.14159265'; const E = '2.7182818284'; const EULER = '0.5772156649';
// define other constants and methods here...
}

Class constants can then be called like this:

echo math_functions::PI;

Methods

A method is quite similar to a function, except that it is intended to define the behavior of a particular class. Like a function, a method can accept arguments as input and can return a value to the caller. Methods are also invoked like functions, except that the method is prefaced with the name of the object invoking the method, like this:

$object->method_name();

In this section you’ll learn all about methods, including method declaration, method invocation, and scope.

Declaring Methods

Methods are created in exactly the same fashion as functions, using identical syntax. The only differ- ence between methods and normal functions is that the method declaration is typically prefaced with a scope descriptor. The generalized syntax follows:
scope function functionName()
{
// Function body goes here
}

For example, a public method titled calculateSalary() might look like this:

public function calculateSalary()
{
return $this->wage * $this->hours;
}

In this example, the method is directly invoking two class fields, wage and hours, using the $this
keyword. It calculates a salary by multiplying the two field values together and returns the result just like a function might. Note, however, that a method isn’t confined to working solely with class fields; it’s perfectly valid to pass in arguments in the same way you can with a function.

■Tip In the case of public methods, you can forgo explicitly declaring the scope and just declare the method like
you would a function (without any scope).

Invoking Methods

Methods are invoked in almost exactly the same fashion as functions. Continuing with the previous example, the calculateSalary() method would be invoked like so:

$employee = new Employee("Janie");
$salary = $employee->calculateSalary();

Method Scopes

PHP supports six method scopes: public, private, protected, abstract, final, and static. The first five scopes are introduced in this section. The sixth, static, is introduced in the later section “Static Class Members.”

Public

Public methods can be accessed from anywhere at any time. You declare a public method by prefacing it with the keyword public or by forgoing any prefacing whatsoever. The following example demon- strates both declaration practices, in addition to demonstrating how public methods can be called from outside the class:
<?php
class Visitors
{
public function greetVisitor()
{
echo "Hello<br />";
}

function sayGoodbye()
{
echo "Goodbye<br />";
}
}

Visitors::greetVisitor();
$visitor = new Visitors();
$visitor->sayGoodbye();
?>

The following is the result:

Hello
Goodbye

Private

Methods marked as private are available for use only within the originating class and cannot be called by the instantiated object, nor by any of the originating class’s subclasses. Methods solely intended to be helpers for other methods located within the class should be marked as private. For example, consider a method, called validateCardNumber(), used to determine the syntactical validity of a patron’s library card number. Although this method would certainly prove useful for satisfying a number of tasks, such as creating patrons and self-checkout, the function has no use when executed alone. Therefore, validateCardNumber() should be marked as private, like this:

private function validateCardNumber($number)
{
if (! ereg('^([0-9]{4})-([0-9]{3})-([0-9]{2})') ) return FALSE;
else return TRUE;
}

Attempts to call this method from an instantiated object result in a fatal error.

Protected

Class methods marked as protected are available only to the originating class and its subclasses. Such methods might be used for helping the class or subclass perform internal computations. For example, before retrieving information about a particular staff member, you might want to verify the employee identification number (EIN) passed in as an argument to the class instantiator. You would then verify this EIN for syntactical correctness using the verifyEIN() method. Because this method is intended for use only by other methods within the class and could potentially be useful to classes derived from Employee, it should be declared as protected:
<?php
class Employee
{
private $ein;
function __construct($ein)
{
if ($this->verifyEIN($ein)) {

echo "EIN verified. Finish";
}

}
protected function verifyEIN($ein)
{
return TRUE;
}
}
$employee = new Employee("123-45-6789");
?>

Attempts to call verifyEIN() from outside of the class will result in a fatal error because of its
protected scope status.

Abstract

Abstract methods are special in that they are declared only within a parent class but are implemented in child classes. Only classes declared as abstract can contain abstract methods. You might declare an abstract method if you want to define an application programming interface (API) that can later be used as a model for implementation. A developer would know that his particular implementation of that method should work provided that it meets all requirements as defined by the abstract method. Abstract methods are declared like this:

abstract function methodName();

Suppose that you want to create an abstract Employee class, which would then serve as the base class for a variety of employee types (manager, clerk, cashier, etc.):

abstract class Employee
{
abstract function hire(); abstract function fire(); abstract function promote(); abstract demote();
}

This class could then be extended by the respective employee classes, such as Manager, Clerk,
and Cashier. Chapter 7 expands upon this concept and looks much more deeply at abstract classes.

Final

Marking a method as final prevents it from being overridden by a subclass. A finalized method is declared like this:
class Employee
{
...
final function getName() {
...
}
}

Attempts to later override a finalized method result in a fatal error. PHP supports six method
scopes: public, private, protected, abstract, final, and static.

■Note The topics of class inheritance and the overriding of methods and fields are discussed in the next chapter.

Type Hinting

Type hinting is a feature introduced with the PHP 5 release. Type hinting ensures that the object being passed to the method is indeed a member of the expected class. For example, it makes sense that only objects of class Employee should be passed to the takeLunchbreak() method. Therefore, you can preface the method definition’s sole input parameter $employee with Employee, enforcing this rule. An example follows:
private function takeLunchbreak(Employee $employee)
{
...
}

Keep in mind that type hinting only works for objects and arrays. You can’t offer hints for types
such as integers, floats, or strings.

Constructors and Destructors

Often, you’ll want to execute a number of tasks when creating and destroying objects. For example, you might want to immediately assign several fields of a newly instantiated object. However, if you have to do so manually, you’ll almost certainly forget to execute all of the required tasks. Object- oriented programming goes a long way toward removing the possibility for such errors by offering

special methods, called constructors and destructors, that automate the object creation and destruc- tion processes.

Constructors

You often want to initialize certain fields and even trigger the execution of methods found when an object is newly instantiated. There’s nothing wrong with doing so immediately after instantiation, but it would be easier if this were done for you automatically. Such a mechanism exists in OOP, known as a constructor. Quite simply, a constructor is defined as a block of code that automatically executes at the time of object instantiation. OOP constructors offer a number of advantages:

• Constructors can accept parameters, which are assigned to specific object fields at creation time.
• Constructors can call class methods or other functions.

• Class constructors can call on other constructors, including those from the class parent.

This section reviews how all of these advantages work with PHP 5’s improved constructor functionality.

■Note PHP 4 also offered class constructors, but it used a different more cumbersome syntax than that used in
version 5. Version 4 constructors were simply class methods of the same name as the class they represented. Such a convention made it tedious to rename a class. The new constructor-naming convention resolves these issues. For reasons of compatibility, however, if a class is found to not contain a constructor satisfying the new naming conven- tion, that class will then be searched for a method bearing the same name as the class; if located, this method is considered the constructor.

PHP recognizes constructors by the name __construct. The general syntax for constructor declaration follows:

function __construct([argument1, argument2, ..., argumentN])
{
// Class initialization code
}

As an example, suppose you want to immediately populate certain book fields with information
specific to a supplied ISBN. For example, you might want to know the title and author of a book, in addition to how many copies the library owns and how many are presently available for loan. This code might look like this:

<?php
class Book
{
private $title; private $isbn; private $copies;

public function _construct($isbn)
{
$this->setIsbn($isbn);
$this->getTitle();
$this->getNumberCopies();
}

public function setIsbn($isbn)
{
$this->isbn = $isbn;
}

public function getTitle() {
$this->title = "Beginning Python";
print "Title: ".$this->title."<br />";
}

public function getNumberCopies() {
$this->copies = "5";
print "Number copies available: ".$this->copies."<br />";
}
}

$book = new book("159059519X");
?>

This results in the following:

Title: Beginning Python
Number copies available: 5

Of course, a real-life implementation would likely involve somewhat more intelligent get methods (e.g., methods that query a database), but the point is made. Instantiating the book object results in the automatic invocation of the constructor, which in turn calls the setIsbn(), getTitle(), and getNumberCopies() methods. If you know that such methods should be called whenever a new object is instantiated, you’re far better off automating the calls via the constructor than attempting to manually call them yourself.
Additionally, if you would like to make sure that these methods are called only via the constructor, you should set their scope to private, ensuring that they cannot be directly called by the object or by a subclass.

Invoking Parent Constructors

PHP does not automatically call the parent constructor; you must call it explicitly using the parent
keyword. An example follows:

<?php
class Employee
{
protected $name;
protected $title;

function __construct()
{
echo "<p>Staff constructor called!</p>";
}
}

class Manager extends Employee
{
function __construct()
{
parent::__construct();
echo "<p>Manager constructor called!</p>";
}
}

$employee = new Manager();
?>

This results in the following:

Employee constructor called! Manager constructor called!

Neglecting to include the call to parent::__construct() results in the invocation of only the
Manager constructor, like this:

Manager constructor called!

Invoking Unrelated Constructors

You can invoke class constructors that don’t have any relation to the instantiated object simply by prefacing __constructor with the class name, like so:

classname::__construct()

As an example, assume that the Manager and Employee classes used in the previous example bear no hierarchical relationship; instead, they are simply two classes located within the same library. The Employee constructor could still be invoked within Manager’s constructor, like this:

Employee::__construct()

Calling the Employee constructor like this results in the same outcome as that shown in the example.

■Note You may be wondering why the extremely useful constructor-overloading feature, available in many OOP
languages, has not been discussed. The answer is simple: PHP does not support this feature.

Destructors

Although objects were automatically destroyed upon script completion in PHP 4, it wasn’t possible to customize this cleanup process. With the introduction of destructors in PHP 5, this constraint is no more. Destructors are created like any other method but must be titled __destruct(). An example follows:

<?php
class Book
{
private $title; private $isbn; private $copies;

function __construct($isbn)
{
echo "<p>Book class instance created.</p>";
}

function __destruct()
{
echo "<p>Book class instance destroyed.</p>";
}
}

$book = new Book("1893115852");
?>

Here’s the result:

Book class instance created. Book class instance destroyed.

When the script is complete, PHP will destroy any objects that reside in memory. Therefore, if the instantiated class and any information created as a result of the instantiation reside in memory, you’re not required to explicitly declare a destructor. However, if less volatile data is created (say, stored in a database) as a result of the instantiation and should be destroyed at the time of object destruction, you’ll need to create a custom destructor.

Static Class Members

Sometimes it’s useful to create fields and methods that are not invoked by any particular object but rather are pertinent to and are shared by all class instances. For example, suppose that you are writing a class that tracks the number of Web page visitors. You wouldn’t want the visitor count to reset to zero every time the class is instantiated, and therefore you would set the field to be of the static scope:
<?php
class Visitor
{
private static $visitors = 0;

function __construct()
{
self::$visitors++;
}

static function getVisitors()
{
return self::$visitors;
}

}
/* Instantiate the Visitor class. */
$visits = new Visitor();

echo Visitor::getVisitors()."<br />";
/* Instantiate another Visitor class. */
$visits2 = new Visitor();

echo Visitor::getVisitors()."<br />";

?>

The results are as follows:

1
2

Because the $visitors field was declared as static, any changes made to its value (in this case via the class constructor) are reflected across all instantiated objects. Also note that static fields and methods are referred to using the self keyword and class name, rather than via the this and arrow operators. This is because referring to static fields using the means allowed for their “regular” siblings is not possible and will result in a syntax error if attempted.

■Note You can’t use $this within a class to refer to a field declared as static.

The instanceof Keyword

The instanceof keyword was introduced with PHP 5. With it you can determine whether an object is an instance of a class, is a subclass of a class, or implements a particular interface, and do something accordingly. For example, suppose you want to learn whether an object called manager is derived from the class Employee:
$manager = new Employee();
...
if ($manager instanceof Employee) echo "Yes";

There are two points worth noting here. First, the class name is not surrounded by any sort of delimiters (quotes). Including them will result in a syntax error. Second, if this comparison fails, the script will abort execution. The instanceof keyword is particularly useful when you’re working with a number of objects simultaneously. For example, you might be repeatedly calling a particular func- tion but want to tweak that function’s behavior in accordance with a given type of object. You might use a case statement and the instanceof keyword to manage behavior in this fashion.

Helper Functions

A number of functions are available to help the developer manage and use class libraries. These functions are introduced in this section.

Determining Whether a Class Exists

The class_exists() function returns TRUE if the class specified by class_name exists within the currently executing script context, and returns FALSE otherwise. Its prototype follows:

boolean class_exists(string class_name)

Determining Object Context

The get_class() function returns the name of the class to which object belongs and returns FALSE if
object is not an object. Its prototype follows:

string get_class(object object)

Learning About Class Methods

The get_class_methods() function returns an array containing all method names defined by the class class_name. Its prototype follows:

array get_class_methods(mixed class_name)

Learning About Class Fields

The get_class_vars() function returns an associative array containing the names of all fields and their corresponding values defined within the class specified by class_name. Its prototype follows:

array get_class_vars(string class_name)

Learning About Declared Classes

The function get_declared_classes() returns an array containing the names of all classes defined within the currently executing script. The output of this function will vary according to how your PHP distribution is configured. For instance, executing get_declared_classes() on a test server produces a list of 97 classes. Its prototype follows:

array get_declared_classes(void)

Learning About Object Fields

The function get_object_vars() returns an associative array containing the defined fields available to object and their corresponding values. Those fields that don’t possess a value will be assigned NULL within the associative array. Its prototype follows:

array get_object_vars(object object)

Determining an Object’s Parent Class

The get_parent_class() function returns the name of the parent of the class to which object belongs. If object’s class is a base class, that class name will be returned. Its prototype follows:

string get_parent_class(mixed object)

Determining Interface Existence

The interface_exists() function determines whether an interface exists, returning TRUE if it does, and FALSE otherwise. Its prototype follows:

boolean interface_exists(string interface_name [, boolean autoload])

Determining Object Type

The is_a() function returns TRUE if object belongs to a class of type class_name or if it belongs to a class that is a child of class_name. If object bears no relation to the class_name type, FALSE is returned. Its prototype follows:

boolean is_a(object object, string class_name)

Determining Object Subclass Type

The is_subclass_of() function returns TRUE if object belongs to a class inherited from class_name, and returns FALSE otherwise. Its prototype follows:

boolean is_subclass_of(object object, string class_name)

Determining Method Existence

The method_exists() function returns TRUE if a method named method_name is available to object, and returns FALSE otherwise. Its prototype follows:

boolean method_exists(object object, string method_name)

Autoloading Objects

For organizational reasons, it’s common practice to place each class in a separate file. Returning to the library scenario, suppose the management application calls for classes representing books, employees, events, and patrons. Tasked with this project, you might create a directory named classes and place the following files in it: Books.class.php, Employees.class.php, Events.class.php, and Patrons.class.php. While this does indeed facilitate class management, it also requires that each separate file be made available to any script requiring it, typically through the require_once() state- ment. Therefore, a script requiring all four classes would require that the following statements be inserted at the beginning:

require_once("classes/Books.class.php"); require_once("classes/Employees.class.php"); require_once("classes/Events.class.php"); require_once("classes/Patrons.class.php");

Managing class inclusion in this manner can become rather tedious and adds an extra step to the already often complicated development process. To eliminate this additional task, the concept of autoloading objects was introduced in PHP 5. Autoloading allows you to define a special _autoload function that is automatically called whenever a class is referenced that hasn’t yet been defined in the script. You can eliminate the need to manually include each class file by defining the following function:

function __autoload($class) {
require_once("classes/$class.class.php");
}

Defining this function eliminates the need for the require_once() statements because when
a class is invoked for the first time, __autoload() will be called, loading the class according to the commands defined in __autoload(). This function can be placed in a global application configura- tion file, meaning only that function will need to be made available to the script.

■Note The require_once() function and its siblings were introduced in Chapter 3.

Summary

This chapter introduced object-oriented programming fundamentals, followed by an overview of PHP’s basic object-oriented features, devoting special attention to those enhancements and additions that were made available with the PHP 5 release.
The next chapter expands upon this introductory information, covering topics such as inheritance,
interfaces, abstract classes, and more.

0 comments: