PHP, MySQL, JavaScript & HTML5 All-in-One For Dummies (2013)

Book IV: PHP

Chapter 4: Object-Oriented Programming

In This Chapter

arrow.png Understanding object-oriented programming

arrow.png Planning an object-oriented script

arrow.png Defining and writing classes

arrow.png Dealing with errors by using exceptions

arrow.png Copying, comparing, and destroying objects

Object-oriented programming (OOP) is an approach to programming that uses objects and classes. It’s in widespread use today, with many universities teaching object-oriented programming in beginning programming classes. Currently, Java and C++ are prevalent languages used for object-oriented programming.

Object-oriented programming, with a limited feature set, is possible in PHP 4. With PHP 5, the object-oriented capabilities of PHP were greatly improved, with both more speed and added features. The information and sample scripts in this chapter are written for PHP 5. Features that aren’t available in PHP 4 are noted.

This chapter introduces object-oriented programming with a specific focus on how to use OOP concepts as they apply to PHP.

Introducing Object-Oriented Programming

Object-oriented programming, sometimes shortened to OOP, isn’t just a matter of using different syntax. It’s a different way of analyzing programming problems. The application is designed by modeling the programming problem. For example, a programmer designing an application to support a company’s sales department might look at the programming project in terms of the relationships between customers and sales and credit lines — in other words, in terms of the design of the sales department itself.

In object-oriented programming, the elements of a script are objects. The objects represent the elements of the problem your script is meant to solve. For example, if the script is related to a used-car lot, the objects are probably cars and customers. Or if the script is related to outer space, the objects would probably be stars and planets.

Object-oriented programming developed new concepts and new terminology to represent those concepts. Understanding the terminology is the road to understanding object-oriented programming, and we explain that terminology to you here.

Objects and classes

The basic elements of object-oriented programs are objects. It’s easiest to understand objects as physical objects. For example, a car is an object. A car has properties (also called attributes), such as color, model, engine, and tires. A car has things it can do, too, such as move forward, move backward, park, roll over, and play dead (well, ours does anyway).

In general, objects are nouns. A person is an object. So are animals, houses, offices, garbage cans, coats, clouds, planets, and buttons. However, objects are not just physical objects. Like nouns, objects often are more conceptual. For example, a bank account isn’t something you can hold in your hand, but it can be considered an object. So can a computer account or a mortgage. A file is often an object. So is a database. E-mail messages, addresses, songs, TV shows, meetings, and dates can all be objects. Objects in web applications might be catalogs, catalog items, shopping carts, customers, orders, or customer lists.

class is the PHP code that serves as the template, or the pattern, that is used to create an object. The class defines the properties, the attributes, of the object. It also defines the things the object can do — its responsibilities. For example, you write a class that defines a car as four wheels and an engine, and the class lists the things a car can do, such as move forward and park. Then, given that class, you can write a statement similar to the following that creates a car object:

$myCar = new Car();

The object $myCar is created from the definition in the class Car. Your new car has four wheels and an engine and can move forward and park, as defined in the class Car. When you use your car object $myCar, you might find that it's missing a few important things, such as a door, or a steering wheel, or a reverse gear. That's because you left an important item out of the class Car when you wrote it.

From a more technical point of view, an object is a complex, user-defined data type. The process of creating an object from a class is called instantiation. An object is an instance of a class. For instance, $myCar is an instance of the class Car.

As the person who writes a class, you know how things work inside the class. However, the person who uses an object created from the class doesn’t need to know how an object accomplishes its responsibilities. Most people have no clue how a telephone object works, but they can use it to make a phone call. The person who built the telephone knows what’s happening inside it. When there’s new technology, the phone builder can open a phone and improve it. As long as he doesn’t change the interface — the keypad and buttons — it doesn’t affect the use of the phone at all.

Properties

Objects have properties, also sometimes called attributes. A car may be red, green, or covered in polka dots — a color property. Properties — such as color, size, or model for a car — are stored inside the object. Properties are set up in the class as variables. For example, the color attribute is stored in the object in a variable, given a descriptive name such as $color. Thus, the car object $myCar might contain $color = red.

The variables that store properties can have default values, can be given values when the object is created, or values can be added or modified later. For example, a $myCar object is created red, but when it's painted later, the $color property is changed to chartreuse.

Methods

The things objects can do are sometimes referred to as responsibilities. For example, a Car object can move forward, stop, back up, and park. Each thing an object can do — each responsibility — is programmed into the class and called a method.

In PHP, methods use the same syntax as functions. Although the code looks like the code for a function, the distinction is that methods are inside a class. It can’t be called independently of an object. PHP won’t allow it. This type of function can perform its task only when called with an object.

When creating methods, give them names that are descriptive of what they do. For instance, a customerOrder class might have methods such as displayOrder, getTotalCost, computeSalesTax, and cancelOrder. Methods, like other PHP entities, can be named with any valid name, but they're often named with camel caps, by convention, as shown here.

The methods are the interface between the object and the rest of the world. The object needs methods for all its responsibilities. Objects should interact with the outside world only through their methods. For example, suppose your object is a catalogItem that is for sale. One of its properties is $price. You don't want $price to be easily changed by a simple statement, such as

$price = 10;

Instead, you want a method, called changePrice, that is the only way the price can be edited. The method includes checks to be sure that only legitimate users can use it to change the price.

A good object should contain all it needs to perform its responsibilities, but not a lot of extraneous data. It shouldn't perform actions that are another object's responsibility. The car object should travel and should have everything it needs to perform its responsibilities, such as gas, oil, tires, engine, and so on. The car object shouldn't cook and doesn't need to have salt or frying pans. Nor should the cook object carry the kids to soccer practice.

Inheritance

Objects should contain only the properties and methods they need. No more. No less. One way to accomplish that is to share properties and methods between classes by using inheritance. For example, suppose you have two rose objects: one with white roses and one with red roses. You could write two classes: a redRose class and a whiteRose class. However, a lot of the information is the same for both objects. Both are bushes, both are thorny, and both bloom in June. Inheritance enables you to eliminate the duplication.

You can write one class called Rose. You can store the common information in this class, such as $plant = bush, $stem = thorns, and $blooms = June. Then you can write subclasses for the two rose types. The Rose class is called the master class or the parent class. redRose and whiteRoseare the subclasses, which are referred to as child classes (or the kids, as a favorite professor fondly referred to them).

Child classes inherit all the properties and methods from the parent class. But they can also have their own individual properties, such as $color = white for the whiteRose class and $color = red for the redRose class.

A child class can contain a method with the same name as a method in a parent class. In that case, the method in the child class takes precedence for a child object. You can specify the method in the parent class for a child object if you want, but if you don’t, the child class method is used.

remember.eps Some languages allow a child class to inherit from more than one parent class, called multiple inheritance. PHP doesn’t allow multiple inheritance. A class can inherit from only one parent class.

Developing an Object-Oriented Script

Object-oriented scripts require a lot of planning. You need to plan your objects and their properties and what they can do. Your objects need to cover all their responsibilities without encroaching on the responsibilities of other objects. For complicated projects, you might have to do some model building and testing before you can feel reasonably confident that your project plan includes all the objects it needs.

Developing object-oriented scripts includes the following procedures, which the next sections cover in more detail:

1. Choose the objects.

2. Choose the properties and methods for each object.

3. Create the object and put it to work.

Choosing objects

Your first task is to develop the list of objects needed for your programming project. If you’re working alone and your project is small, the objects might be obvious. However, if you’re working on a large, complex project, selecting the list of objects can be more difficult. For example, if your project is developing the software that manages all the tasks in a bank, your list of possible objects is large: account, teller, money, checkbook, wastebasket, guard, vault, alarm system, customer, loan, interest, and so on. But, do you need all those objects? What is your script going to do with the wastebasket in the front lobby? Or the guard? Well, perhaps your script needs to schedule shifts for the guards.

When you’re planning object-oriented programs, the best strategy for identifying your objects is to list all the objects you can think of — that is, all the nouns that might have anything at all to do with your project. Sometimes programmers can take all the nouns out of the project proposal documentation to develop a pretty comprehensive list of possible objects.

After you create a long list of possible objects, your next task is to cross off as many as possible. You should eliminate any duplicates, objects that have overlapping responsibilities, and objects that are unrelated to your project. For example, if your project relates to building a car, your car project probably needs to have objects for every part in the car. On the other hand, if your project involves traffic control in a parking garage, you probably need only a car object that you can move around; the car’s parts don’t matter for this project.

Selecting properties and methods for each object

When you have a comprehensive list of objects, you can begin to develop the list of properties for each object. Ask yourself what you need to know about each object. For example, for a car repair project, you probably need to know things like when the car was last serviced, its repair history, any accidents, details about the parts, and so on. For a project involving parking garage traffic, you probably need to know only the car’s size. How much room does the car take up in the parking garage?

You need to define the responsibilities of each object, and each object needs to be independent. It needs methods for actions that handle all of its responsibilities. For example, if one of your objects is a bank account, you need to know what a bank account needs to do. Well, first, it needs to be created, so you can define an openNewAccount method. It needs to accept deposits and disburse withdrawals. It needs to keep track of the balance. It needs to report the balance when asked. It might need to add interest to the account periodically. Such activities come to mind quickly.

However, a little more thought, or perhaps testing, can reveal activities that you overlooked. For example, the account stores information about its owner, such as name and address. Did you remember to include a method to update that information when the customer moves? It might seem trivial compared to moving the money around, but it won’t seem trivial if you can’t do it.

Creating and using an object

After you decide on the design of an object, you can create and then use the object. The steps for creating and using an object are as follows:

1. Write the class statement.

The class statement is a PHP statement that is the blueprint for the object. The class statement has a statement block that contains PHP code for all the properties and methods that the object has.

2. Include the class in the script where you want to use the object.

You can write the class statement in the script itself. However, it's more common to save the class statement in a separate file and use an include statement to include the class at the beginning of the script that needs to use the object.

3. Create an object in the script.

You use a PHP statement to create an object based on the class. This is called instantiation.

4. Use the new object.

After you create a new object, you can use it to perform actions. You can use any method that is inside the class statement block.

The rest of this chapter provides the details needed to complete these steps.

Defining a Class

After you’ve determined the objects, properties, and methods your project requires, you’re ready to define classes. The class is the template (pattern) for the object.

Writing a class statement

You write the class statement to define the properties and methods for the class. The class statement has the following general format:

class className

{

    Add statements that define the properties

    Add all the methods

}

remember.eps You can use any valid PHP identifier for the class name, except the name stdClass. PHP uses the name stdClass internally, so you can't use this name.

All the property settings and method definitions are enclosed in the opening and closing curly braces. If you want a class to be a subclass that inherits properties and methods, use a statement similar to the following:

class whiteRose extends Rose

{

    Add the property statements

    Add the methods

}

The object created from this class has access to all the properties and methods of both the whiteRose child class and the Rose class. The Rose class, however, doesn't have access to properties or methods in the child class, whiteRose. Imagine, the child owns everything the parent owns, but the parent owns nothing of the child's. What an idea.

The next few sections show you how to set properties and define methods within the class statement. For a more comprehensive example of a complete class statement, see the section, Putting it all together, later in this chapter.

Setting properties

When you’re defining a class, you declare all the properties at the top of the class, as follows:

class Car

{

   private $color;

   private $tires;

   private $gas;

   Method statements

}

tip.eps PHP doesn’t require you to declare variables. In the other PHP scripts discussed in this book, variables aren’t declared; they’re just used. You can do the same thing in a class. However, it’s much better to declare the properties in a class. By including declarations, classes are much easier to understand. It’s poor programming practice to leave this out.

Each property declaration begins with a keyword that specifies how the property can be accessed. The three keywords are

check public: The property can be accessed from outside the class, either by the script or from another class.

check private: No access is granted from outside the class, either by the script or from another class.

check protected: No access is granted from outside the class except from a class that's a child of the class with the protected property or method.

remember.eps Classes should be written so that methods are used to access properties. By declaring a property to be private, you make sure that the property can’t be accessed directly from the script.

If you want to set default values for the properties, you can, but the values allowed are restricted. You can declare a simple value, but not a computed one, as detailed in the following examples:

check The following variable declarations are allowed as default values:

private $color = "black";

private $gas = 10;

private $tires = 4;

check The following variable declarations are not allowed as default values:

private $color = "blue"." black";

private $gas = 10 - 3;

private $tires = 2 * 2;

An array is allowed in the variable declaration, as long as the values are simple, as follows:

private $doors = array("front","back");

To set or change a variable’s value when you create an object, use the constructor (described in the Writing the constructor section, later in this chapter) or a method you write for this purpose.

Accessing properties using $this

Inside a class, $this is a special variable that refers to the properties of the same class. $this can't be used outside of a class. It's designed to be used in statements inside a class to access variables inside the same class.

The format for using $this is the following:

$this->varname

For example, in a CustomerOrder class that has a property $totalCost, you would access $totalCost in the following way:

$this->totalCost

Using $this refers to $totalCost inside the class. You can use $this as shown in any of the following statements:

$this->totalCost = 200.25;

if($this->totalCost > 1000)

$product[$this->size] = $price

As you can see, you use $this->varname in all the same ways you would use $varname.

Notice that a dollar sign ($) appears before this but not before gas. Don't use a dollar sign before totalCost — as in $this->$totalCost — because it changes your statement's meaning. You might or might not get an error message, but it isn't referring to the variable $totalCost inside the current class.

Adding methods

Methods define what an object can do and are written in the class in the same format you'd use to write a function. For example, your CustomerOrder might need a method that adds an item onto the total cost of the order. You can have a variable called total that contains the current total cost. You can write a method that adds the price of an item to the total cost. You could add such a method to your class, as follows:

class CustomerOrder

{

  private $total = 0;

  function addItem($amount)

  {

     $this->total = $this->total + $amount;

     echo "$amount was added; current total is $this->total";

  }

}

This looks just like any other function, but it’s a method because it’s inside a class. You can find details about writing functions in Chapter 2 in this minibook.

Like functions, methods accept values passed to them. The values passed need to be the correct data type to be used in the function. (See Chapter 1 in this minibook for a discussion of data types.) For instance, in the preceding example, $amount needs to be a number. Your method should include a check to make sure that the value is a number. For instance, you might write the method as follows:

class CustomerOrder

{

  private $total = 0.0;

  function addItem($amount)

  {

     if(is_numeric($amount)

     {

       $this->total = $this->total + $amount;

       echo "$amount added; current total is $this->total";

     }

     else

     (

       echo "value passed is not a number.";

     }

  }

}

If the value passed is an integer, a float, or a string that is a number, the amount is added. If not, the error message is displayed. The sum in $total is a float because it is assigned a number with a decimal point in it. When the amount passed in is added to $sum, it is automatically converted to a float by PHP.

When you write methods, PHP allows you to specify that the value passed must be an array or a particular object. Specifying what to expect is called type hinting. If the value passed is not the specified type, an error message is displayed. You don’t need to add statements in the method to check for array or object data types. For example, you can specify that an array is passed to a function, as follows:

Class AddingMachine

{

   private $total = 0;

   addNumbers(array $numbers)

   {

      for($i=0;$i<=sizeof($numbers);$i++)

      {

         $this->total = $this->total + $numbers[$i];

      }

   }

}

If you attempt to pass a value to this method that is not an array, an error message similar to the following is displayed.

Catchable fatal error: Argument 1 passed to AddingMachine::addNumbers() must be an array, integer given,...

This error states that an integer was passed, instead of the required array. The error is fatal, so the script stops at this point. You can also specify that the value passed must be a specific object, as follows:

class ShoppingCart

{

   private $items = array();

   private $n_items = 0;

   function addItem( Item $item )

   {

      $this->items[] = $item;

      $this->n_items = $this->n_items + 1;

   }

}

The ShoppingCart class stores the items in the shopping cart as an array of Item objects. The method addItem is defined to expect an object that was created from the class Item. If a value is passed to the addItem method that is not an Item object, an error message is displayed, and the script stops.

remember.eps Methods can be declared public, private, or protected, just as properties can. Public is the default access method if no keyword is specified.

PHP provides some special methods with names that begin with __ (two underscores). PHP handles these methods differently internally. This chapter discusses three of these methods: construct, destruct, and clone. Don't begin the names of any of your own methods with two underscores unless you're taking advantage of a PHP special method.

Understanding public and private properties and methods

Properties and methods can be public or private. Public means that methods or properties inside the class can be accessed by the script that is using the class or from another class. For example, the following class has a public property and a public method:

class Car

{

  public $gas = 0;

  function addGas($amount)

  {

     $this->gas = $this->gas + $amount;

     echo "$amount gallons added to gas tank";

  }

}

The public property in this class can be accessed by a statement in the script outside the class, as follows:

$mycar = new Car;

$gas_amount = $mycar->gas;

After these statements are run, $gas_amount contains the value stored in $car inside the object. The property can also be modified from outside the class, as follows:

$mycar->gas = 20;

Allowing script statements outside the class to directly access the properties of an object is poor programming practice. All interaction between the object and the script or other classes should take place using methods. The example class has a method to add gas to the car. All gas should be added to the car by using the addGas method, which is also public, using statements similar to the following:

$new_car = new Car;

$new_car->addGas(5);

You can prevent access to properties by making them private, as follows:

private $gas = 0;

With the property specified as private, a statement in the script that attempts to access the property directly, as follows:

$myCar->gas = 20;

gets the following error message:

Fatal error: Cannot access private property car::$gas in c:\testclass.php on line 17

Now, the only way gas can be added to the car is by using the addGas method. Because the addGas method is part of the class statement, it can access the private property.

In the same way, you can make methods private or protected. In this case, you want the outside world to use the addGas method. However, you might want to be sure that people buy the gas that is added. You don't want any stolen gas in the car. You can write the following class:

class Car

{

  private $gas = 0;

  private function addGas($amount)

  {

     $this->gas = $this->gas + $amount;

     echo "$amount gallons added to gas tank";

  }

  function buyGas($amount)

  {

     $this->addGas($amount);

  }

}

With this class, the only way gas can be added to the car from the outside is with the buyGas method. The buyGas method uses the addGas method to add gas to the car, but the addGas method can't be used outside the class because it's private. If a statement outside the class attempts to useaddGas, as follows, a fatal error is displayed, as it was for the private property:

$new_car = new Car;

$new_car->addGas(5);

However, a statement outside the class can now add gas to the car by using the buyGas method, as follows:

$new_car = new Car;

$new_car->buyGas(5);

You see the following output:

5 gallons added to gas tank

tip.eps It’s good programming practice to hide as much of your class as possible. Make all properties private. You should make methods public only if they absolutely need to be public.

Writing the constructor

The constructor is a special method, added with PHP 5, that is executed when an object is created using the class as a pattern. A constructor isn’t required, and you don’t need to use a constructor if you don’t want to set any property values or perform any actions when the object is created. Only one constructor is allowed.

The constructor has a special name so that PHP knows to execute the method when an object is created. Constructors are named __construct (two underscores). A constructor method looks similar to the following:

function __construct()

{

    $this->total = 0;   # starts with a 0 total

}

This constructor defines the new CustomerOrder. When the order is created, the total cost is 0.

technicalstuff.eps Prior to PHP 5, constructors had the same name as the class. You might run across classes written in this older style. PHP 5 and later scripts look first for a method called __construct() to use as the constructor. If it doesn't find one, it looks for a method that has the same name as the class and uses that method for the constructor. Thus, older classes still run under PHP 5 and 6.

Putting it all together

Your class can have as few or as many properties and methods as it needs. The methods can be simple or complicated, but the goal of object-oriented programming is to make the methods as simple as is reasonable. Rather than cram everything into one method, it’s better to write several smaller methods and have one method call another as needed.

The following is a simple class:

class MessageHandler

{

  private $message;

  function __construct($message)

  {

     $this->message = $message;

  }

  function displayMessage()

  {

     echo $this->message."\n";

  }

}

The class has one property — $message — that stores a message. The message is stored in the constructor.

The class has one method — displayMessage. Echoing the stored message is the only thing the messageHandler object can do.

Suppose you want to add a method that changes the message to lowercase and then automatically displays the message. The best way to write that expanded class is as follows:

class MessageHandler

{

  private $message;

  function __construct($message)

  {

     $this->message = $message;

  }

  function displayMessage()

  {

     echo $this->message."\n";

  }

  function lowerCaseMessage()

  {

     $this->message = strtolower($this->message);

     $this->displayMessage();

  }

}

Note the lowerCaseMessage() method. Because the class already has a method to display the message, this new lowerCaseMessage() method uses the existing displayMessage() method rather than repeating the echo statement.

tip.eps Any time you write a method and find yourself writing code that you’ve already written in a different method in the same class, you need to redesign the methods. In general, you shouldn’t have any duplicate code in the same class.

The example in Listing 4-1 is a complicated class that can be used to create an HTML form. To simplify the example, the form contains only text input fields.

Listing 4-1: A Script That Contains a Class for a Form Object

<?php

/* Class name:  Form

* Description: A class that creates a simple HTML form

*              containing only text input fields. The

*              class has 3 methods.

*/

class Form

{

  private $fields = array();  # contains field names and labels

  private $actionValue;     # name of script to process form

  private $submit = "Submit Form"; # value on submit button

  private $Nfields = 0; # number of fields added to the form

/* Constructor: User passes in the name of the script where

* form data is to be sent ($actionValue) and the value to

* display on the submit button.

*/

  function __construct($actionValue,$submit)

  {

     $this->actionValue = $actionValue;

     $this->submit = $submit;

  }

/* Display form function. Displays the form.

*/

  function displayForm()

  {

     echo "\n<form action='{$this->actionValue}'

                   method='POST'>\n";

     for($j=1;$j<=sizeof($this->fields);$j++)

     {

       echo "<p style='clear: left; margin: 0; padding: 0;

                padding-top: 5px'>\n";

       echo "<label style='float: left; width: 20%'>

                {$this->fields[$j-1]['label']}: </label>\n";

       echo "<input style='width: 200px' type='text'

                name='{$this->fields[$j-1]['name']}'></p>\n";

     }

     echo "<input type='submit' value='{$this->submit}'

              style='margin-left: 25%; margin-top: 10px'>\n";

     echo "</form>";

  }

/* Function that adds a field to the form. The user needs to

* send the name of the field and a label to be displayed.

*/

   function addField($name,$label)

  {

    $this->fields[$this->Nfields]['name'] = $name;

    $this->fields[$this->Nfields]['label'] = $label;

    $this->Nfields = $this->Nfields + 1;

  }

}

?>

This class contains four properties and three methods. The properties are as follows:

check $fields: An array that holds the fields as they are added by the user. The fields in the form are displayed from this array.

check $actionValue: The name of the script that the form is sent to. This variable is used in the action attribute when the form tag is displayed.

check $submit: The text that the user wants displayed on the Submit button. This variable's value, Submit Form by default, is used when the Submit button is displayed.

check $Nfields: The number of fields that have been added to the form so far.

The methods in this class are as follows:

check __construct: The constructor, which sets the values of $actionValue and $submit from information passed in by the user.

check addField: Adds the name and label for the field to the $fields array. If the user added fields for first name and last name to the form, the array might look as follows:

$fields[1][name]=first_name

$fields[1][label]=First Name

$fields[2][name]=last_name

$fields[2][label]=Last Name

and so on

check displayForm: Displays the form. It echoes the HTML needed for the form and uses the values from the stored variables for the name of the field and the label that the user sees by the field.

The next section describes how to use a class, including the Form class shown in Listing 4-1.

Using a Class in a Script

The class code needs to be in the script that uses the class. Most commonly, the class is stored in a separate include file and is included in any script that uses the class.

To use an object, you first create the object from the class. Then that object can perform any methods that the class includes. Creating an object is called instantiating the object. Just as you can use a pattern to create many similar but individual dresses, you can use a class to create many similar but individual objects. To create an object, use statements that have the following format:

$objectname = new classname(value,value,...);

Some valid statements that create objects are

$Joe = new Person("male");

$car_Joe = new Car("red");

$car_Sam = new Car("green");

$customer1 = new Customer("Smith","Joe",$custID);

The object is stored in the variable name, and the constructor method is executed. You can then use any method in the class with statements of the following format:

$Joe->goToWork();

$car_Joe->park("illegal");

$car_Sam->paintCar("blue");

$name = $customer1->getName();

Different objects created from the same class are independent individuals. Sam’s car gets painted blue, but Joe’s car is still red. Joe gets a parking ticket, but it doesn’t affect Sam.

The script shown in Listing 4-2 shows how to use the Form class that was created in the preceding section and shown in Listing 4-1.

Listing 4-2: A Script That Creates a Form

<?php

/* Script name: buildForm

* Description: Uses the form to create a simple HTML form

*/

require_once("Form.class");

echo "<html><head><title>Phone form</title></head><body>";

$phone_form = new Form("process.php","Submit Phone");

$phone_form->addField("first_name","First Name");

$phone_form->addField("last_name","Last Name");

$phone_form->addField("phone","Phone");

echo "<h3>Please fill out the following form:</h3>";

$phone_form->displayForm();

echo "</body></html>";

?>

First, the script includes the file containing the Form class in the script. The class is stored in the file Form.class. The script creates a new form object called $phone_form. Three fields are added with the addField method. The form is displayed with the displayForm method. Notice that some additional HTML code is output in this script. That HTML could have been added to the displayForm method just as easily.

The script creates a form with three fields, using the Form class. Figure 4-1 shows the resulting web page.

9781118213704-fg040401.tif

Figure 4-1: The form displayed by the script in Listing 4-2.

Using Abstract Methods in Abstract Classes and Interfaces

You can use abstract methods that specify the information to be passed, but do not contain any code, and we tell you how to do that in the following sections. Abstract methods were added in PHP 5. You can use abstract methods in abstract classes or in interfaces. An abstract class contains both abstract methods and nonabstract methods. An interface contains only abstract methods.

Using an abstract class

Any class that has an abstract method must be declared an abstract class. The function of an abstract class is to serve as a parent for a child class. You cannot create an object from an abstract class.

An abstract class specifies the methods for a child class. The child class must implement the abstract methods that are defined in the parent class, although each child class can implement the abstract method differently, with different code. If an abstract method specified in the parent class is not included in a child class, a fatal error occurs.

An abstract method specifies the values to pass, called the signature. The child implementation of the abstract method must use the same signature. The child must define the method with the same or weaker visibility. For example, if the abstract method is declared protected, the child implementation of the method must be declared protected or public.

The following code shows the use of an abstract class. An abstract class named Message is defined. Then two child classes are defined.

abstract class Message

{

  protected message_content;

  function __construct($text)

  {

     $this->message_content = $text;

  }

  abstract public function displayMessage($color);

}

class GiantMessage extends Message

{

  public function displayMessage($color)

  {

     echo "<h1 style='color: $color'>

            This->message_content</h1>";

  }

}

class BigMessage extends Message

{

  public function displayMessage($color)

  {

     echo "<h2 style='color: $color'>

            This->message_content</h2>";

  }

}

The abstract class message includes an abstract method named displayMessage. This abstract method is implemented in the two child classes — GiantMessage and BigMessage. In GiantMessage, the message content is displayed with an <h1> tag in the color passed to the method. InBigMessage, the message is displaying with an <h2> tag in the color passed. Thus, both child classes implement the abstract method, but they implement it differently.

If a child class doesn’t implement the abstract class, an informative error message is displayed, stating exactly how many abstract classes are not implemented and their names. The error is fatal, so the script stops at that point.

You can implement an interface at the same time you extend a class, including an abstract class. Using interfaces is described in the next section.

Using interfaces

An interface contains only abstract methods. The function of an interface is to enforce a pattern on a class by specifying the methods that must be implemented in the class. You cannot create an object from an interface.

An interface can't have the same name as a class used in your script. All methods specified in an interface must be public. Don't use the keyword abstract for methods in an interface. When a class implements an interface, all the methods in the interface must be implemented in the class. If a method is not implemented, a fatal error occurs.

You implement an interface in a class with the following format:

class classname implements interfacename

You can implement more than one interface in a class, as follows:

class classname implements interfacename1interfacename2,...

Multiple interfaces implemented by a single class may not contain methods with the same name.

The following example shows the use of both inheritance and an interface:

interface Moveable

{

   function moveForward($distance);

}

class Car

{

   protected $gas = 0;

   function __construct($amt)

   {

      $this->gas = $amt;

      echo "<p>At creation, Car contains $this->gas

               gallons of gas</p>";

   }

}

class Sedan extends Car implements Moveable

{

   private $mileage = 18;

   public function moveForward($distance)

   {

      $this->gas = $this->gas -

                   round(($distance/$this->mileage),2);

      echo "<p>After moving forward $distance miles,

            Sedan contains $this->gas gallons of gas.</p>";

   }

}

The class Sedan is a child of the class Car, which is not an abstract class, and also implements the interface Moveable. You can use the preceding code with the following statements:

$my_car = new Sedan(20);

$my_car->moveForward(50);

The following displays in the browser window:

At creation, Car contains 20 gallons of gas

After moving forward 50 miles, Sedan contains 17.22 gallons of gas

The first statement displays when the object $my_car is created. Because the Sedan class doesn't have a constructor, the constructor in the Car class runs and produces the first line of output. The second statement displays when the moveForward method is used.

Preventing Changes to a Class or Method

You might want a class to be used exactly as you have written it. You can prevent the creation of a child class that changes the implementation of methods with the final keyword, as follows:

final class classname

When a class is defined as final, a child class can't be created. You can also define a method as final, as follows:

final public moveForward()

If a child class includes a method with the same name as a final method in the parent class, an error message is displayed, similar to the following:

Fatal error: Cannot override final method Car::moveForward()

In this case, the parent class Car includes a method moveForward that is defined as final. The child class Sedan extends Car. However, the Sedan class defines a method moveForward, a method with the same name as a final method in the parent Car class. This isn't allowed.

Handling Errors with Exceptions

PHP provides an error-handling class called Exception. You can use this class to handle undesirable things that happen in your script. When the undesirable thing that you define happens, code in your method creates an exception object. In object-oriented talk, this is called throwing an exception. Then, when you use the class, you check whether an exception is thrown and perform specified actions.

You can throw an exception in a method with the following statement:

throw new Exception("message");

This statement creates an Exception object and stores a message in the object. The Exception object has a getMessage method that you can use to retrieve the message you stored.

In your class definition, you include code in your methods to create an Exception when certain conditions occur. For example, the addGas method in the following Car class checks whether the amount of gas exceeds the amount that the car gas tank can hold, as follows:

class Car

{

   private $gas = 0;

   function addGas($amount)

   {

      $this->gas = $this->gas + $amount;

      echo "<p>$amount gallons of gas were added</p>";

      if($this->gas > 50)

      {

         throw new Exception("Gas is overflowing");

      }

   }

}

If the amount of gas in the gas tank is more than 50 gallons, the method throws an exception. The gas tank doesn’t hold that much gas.

When you use the class, you test for an exception, as follows:

$my_car = new Car();

try

{

   $my_car->addGas(10);

   $my_car->addGas(45);

}

catch(Exception $e)

{

   echo $e->getMessage();

   exit();

}

The preceding script contains a try block and a catch block:

check try: In the try block, you include any statements that you think might trigger an exception. In this script, adding too much gas can trigger an exception, so you add any addGas method calls inside a try block.

check catch: In the catch block, you catch the Exception object and call it $e. Then you execute the statements in the catch block. One of the statements is a call to a method called getMessage in the Exception class. The getMessage function returns the message that you stored, and your statement echoes the returned message. The statements then echo the end-of-line characters so the message is displayed correctly. The script stops on the exit statement.

If no exception is thrown, the catch block has nothing to catch, and it is ignored. The script proceeds to the statements after the catch block. In this case, if the amount of gas doesn't exceed 50 gallons, the catch block is ignored, and the script proceeds to the statements after the catchblock.

If you run the preceding script, the following is displayed by the browser:

10 gallons of gas were added

45 gallons of gas were added

Gas is overflowing

The second addGas method call raised the amount of gas over 50 gallons, so an exception was thrown. The catch block displayed the overflow message and stopped the script.

Copying Objects

PHP provides a method you can use to copy an object. The method is __clone, with two underscores. You can write your own __clone method in a class if you want to specify statements to run when the object is copied. If you don't write your own, PHP uses its default __clone method that copies all the properties as is. As shown by the two underscores beginning its name, the clone method is a different type of method, and thus is called differently, as shown in the following example.

You could write the following class:

class Car

{

  private $gas = 0;

  private $color = "red";

  function addGas($amount)

  {

     $this->gas = $this->gas + $amount;

     echo "$amount gallons added to gas tank";

  }

  function __clone()

  {

     $this->gas = 5;

  }

}

Using this class, you can create an object and copy it, as follows:

$firstCar = new Car;

$firstCar->addGas(10);

$secondCar = clone $firstCar;

After these statements, you have two cars:

check $firstCar: This car is red and contains ten gallons of gas. The ten gallons were added with the addGas method.

check $secondCar: This car is red, but contains five gallons of gas. The duplicate car is created using the __clone method in the Car class. This method sets gas to 5 and doesn't set $color at all.

If you didn't have a __clone method in the Car class, PHP would use a default __clone method that would copy all the properties, making $secondCar both red and containing ten gallons of gas.

Comparing Objects

At their simplest, objects are data types. You can compare objects with the equal operator, which is two equal signs (==), or with the identical operator, which is three equal signs (===). Using the equal operator, two objects are equal if they are created from the same class and have the same properties and values. However, using the identical operator, two objects are identical only if they refer to the same instance of the same class.

The following two objects are equal, but not identical, because they are two instances of the class Car:

$my_car = new Car();

$my_car2 = new Car();

Thus, the following statement would echo equal:

If($my_car == $my_car2)

{

  echo "equal";

}

But, the following statement would not echo equal:

If($my_car === $my_car2)

{

  echo "equal";

}

The following two objects are equal, but not identical, because clone creates a new instance of the object Car:

$my_car = new Car();

$my_car2 = clone $my_car;

The following two objects are both equal and identical:

$my_car = new Car();

$my_car2 = $my_car;

Getting Information about Objects and Classes

PHP provides several functions that you can use to get information about objects and classes:

check You can check whether a class exists with the following:

class_exists("classname");

check You can test whether a property exists in a specific class with the following:

property_exists("classname","propertyname");

check You can find out the properties, with their defaults, and the methods defined in a class with the following statements:

get_class_vars("classname");

get_class_methods("classname");

The get_class_ functions return an array. The properties array contains the property name as the key and the default as the value. The methods array contains numeric keys and the names of the methods as values. If a property or method is private, the function will not return its name unless it is executed from inside the class.

check You can test whether an object, its parents, or their implemented interfaces were created by a specified class using the instanceof operator, added in PHP 5, as follows:

if($objectname instanceof "classname")

check You can find out the current values of the properties of an object with the following function:

get_object_vars($objectname);

The function returns an array containing the current values of the properties, with the property names as keys.

Destroying Objects

You can destroy an object with the following statement:

unset($objName);

For example, you can create and destroy an object of the Car class with the following statements:

$myCar = new Car;

unset($myCar);

After $myCar is unset, the object no longer exists at all.

PHP provides a method that is automatically run when an object is destroyed. You add this method to your class and call it __destruct (with two underscores). For example, the following class contains a __destruct method:

class Bridge

{

  function __destruct()

  {

    echo "The bridge is destroyed";

  }

}

If you use the following statements, the object is created and destroyed:

$bigBridge = new Bridge;

unset($bigBridge);

The output from these statements is

The bridge is destroyed

The output is echoed by the __destruct method when the object is unset.

The __destruct method isn't required. It's just available for you to use if you want to execute some statements when the object is destroyed. For example, you might want to close some files or copy some information to your database.