Object Orientation

 < Day Day Up > 

Before PHP 5, the object orientation in PHP was little more than syntactic sugar it looked nice but was little more than a fancy way of working, without offering any advantages. However, from v5 onward OOP is a powerful tool in the right hands. So, if you take the time to learn it fully, your code will benefit.

If you have used Java before, you will be at home with PHP because nearly everything from Java is in PHP, and with a very similar implementation. This chapter is aimed at people with no knowledge of object-oriented programming (OOP), so if you are already experienced, much of this will be review.

Introduction to OOP

Object-oriented programming is a system of expressing entities in your code as classes and objects. A class is a definition of an entity. For instance, you might define a car class or a pencil class. An object is an instance of a class. For instance, with your car class, you could create 10 car objects. As you define your car class, you can give it variables for storing car-related variables (color, model, and so on) and also car-specific functions (brake(), changeGear(), and so on). When you create an instance of a car, that object gets its own individual set of variables and functions that are not shared with other cars.

Defining a class is done with the class keyword and a list of functions and variables. You can then create instances of the class with the new operator, which returns a new object in the class. Here is how that looks in PHP:

 <?php   class car {     public function brake() {       echo "Car is braking...\n";     }     public function changeGear($gear) {       echo "Car is changing gear to $gear\n";     }   } ?> 

Here we have our car class with two functions, brake() and changeGear(). Note the way the functions are written: The first letter is lowercase, with the first letter of subsequent words uppercased. This is known as camel caps or studly caps, and it is simply a coding convention that helps increase readability.

Second, note the word public before the function keyword. PHP implements a full PPP system, which means you have private functions and variables, public functions and variables, and protected functions and variables. Each do different things, and you need a firm grasp of the differences between them to understand OOP (we discuss them in the section "Access Modifiers").

Moving on, we need to create an instance of that car to use its functions:

 $viper = new car; $viper->changeGear(1); $viper->changeGear(2); $viper->brake(); 

That outputs the following:

 Car is changing gear to 1 Car is changing gear to 2 Car is braking... 

Object Variables and $this

Consider this code:

 $viper = new car; $concorde = new car; $viper->changeGear(1); $viper->changeGear(2); $concorde->brake(); 

Although the code is very different, the output is identical because we have no way to distinguish between cars right now. We need to create a function, setName(), that gives each car a name. That means we need to store the name inside the car and print it when calling the other functions.

Adding the variable to the class is easy add this line beneath the class car line:

 public $name; 

Again, notice that public is there; otherwise, you can ignore it. Put this setName() function immediately below the $name line:

 public function setName($newname) {   $this->name = $newname;   echo "Car name changed to $newname\n"; } 

The first line is standard, but the second line introduces the $this variable. Each instance of a class has its own set of variables, so PHP uses the $this variable to refer to whichever object had this function called upon it. If you call $concorde->brake(), $this is $concorde; if you call $viper->brake(), $this is $viper.

The way to set object variables is very specific. You do not use $name = ... or $this->$name = ... that first one sets a new local variable called $name, and the second one looks up the value of the local variable name and uses it as a variable-variable. That is, if $name was wombat, it would set $this->wombat. Remember, unless you want to use variable-variables, PHP variables only ever have one dollar sign!

With the variable set, we can modify the other two functions to print the name so we can distinguish between the cars. The final script is shown in Listing 31.10.

Listing 31.10. Multiple Cars, Distinguished by Name
 <?php   class car {     public $name;     public function setName($newname) {       $this->name = $newname;       echo "Car name changed to $newname\n";     }     public function brake() {       echo "Car $this->name is braking...\n";     }     public function changeGear($gear) {       echo "Car $this->name is changing gear to $gear\n";     }   }   $viper = new car;   $concorde = new car;   $viper->setName("Viper");   $concorde->setName("Concorde");   $viper->changeGear(1);   $viper->changeGear(2);   $concorde->brake(); ?> 

This time the output distinguishes between the cars.

Constructors and Destructors

Although having a function to set the name of cars is helpful, it should be obvious that every car needs a name. Rather than using setName() to set the initial value for the name, it makes more sense to use it only if, for some reason, we need to rename a car. Instead, because all cars need a name, we can force people to pass in the name when they are creating the car.

This is done through the constructor function, which is a magic function PHP calls whenever it creates an object of any class. If you have no constructor, like our current script, PHP skips this step. Constructors are used to set up initial values for objects. If you were creating a Human object, for example, it might set its age to 0 (just born), their birthday to today, and so on.

Because the constructor is a magic function (note: magic function is the actual term used to describe the constructor and others of its type), you must use a fixed name for it: __construct(). Note the two underscores at the beginning, which are a sure sign of a magic function.

If we want to set our car name during object creation, here is how the constructor should look (put this after the public $name line):

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

If we add that into the car class, save the script, and try running it, we will see that PHP now outputs warnings that we did not provide an initial name for our two cars. The constructor effectively replaces the setName() function for what we are doing; thus, we can rewrite the whole block of code at the bottom like this:

 $viper = new car("Viper"); $concorde = new car("Concorde"); $viper->changeGear(1); $viper->changeGear(2); $concorde->brake(); 

Along with constructors come destructors, which work at the opposite end of objects and are called when your object is being destroyed. Object destruction takes place either explicitly (you use the unset() function) or implicitly (the script ends). Either way, PHP calls the __destruct() function for you, and you can do whatever you want with it, such as closing any file handles you opened in the constructor.

We can amend our car class to include a destructor by adding this code beneath the __construct() function:

 public function __destruct() {   echo "Car $this->name going to the scrap heap...\n"; } 

Save your script and run it again; you should see the destructor being called for each car at the end of the script when PHP cleans up the objects.

Class Inheritance

PHP allows you to use one class as the base for another in what is known as class inheritance. Right now we have a car class, but what if we were to add a truck class and a bus class? We could just copy the changeGear() and brake() classes into each of them, but it makes maintenance much harder. If we find a bug in the brake() class later, for example, we'll need to remember to change it in various other places. Instead, we should create a class called vehicle that has all these shared functions and then have the car, TRuck, and bus classes that all inherit from vehicle.

When you inherit one class from another, it brings with it all the variables and functions that are declared as public, which is all of them so far. We can inherit a car class from a vehicle class by using the extends keyword in the class definition, like this:

 class car extends vehicle { 

Then, by changing the car class over to a vehicle class, we can extend all three classes with the complete script shown in Listing 31.11.

Listing 31.11. Multiple Vehicles, All Subclassed
 <?php   class vehicle {     public $name;     public function __construct($name) {       $this->name = $name;     }     public function __destruct() {       echo "$this->name going to the scrap heap...\n";     }     public function setName($newname) {       $this->name = $newname;       echo "Name changed to $newname\n";     }     public function brake() {       echo "$this->name is braking...\n";     }     public function changeGear($gear) {       echo "$this->name is changing gear to $gear\n";     }   }   class car extends vehicle { }   class truck extends vehicle { }   class bus extends vehicle { }   $viper = new car("Viper");   $caterpillar = new truck("Caterpillar");   $viper->changeGear(1);   $caterpillar->brake(); ?> 

Because the class definitions for car, TRuck, and bus are all empty, they are identical to vehicle classes in all but name. However, having them separate means we can add individual functionality, such as a setFare() function for buses.

Although you can only inherit from one class at a time, you can inherit from an inherited class. That is, our car class inherits from vehicle, but we could create new classes that in turn inherit from car. Various terms are used to describe inheritance, with the most common being a parent/child relationship. In our example, car is the child class of vehicle, or, to put it another way, vehicle is the parent class of car. If we were to extend car further with classes like coupe or sedan, vehicle would be the grandparent of coupe.

Another common word for this is subclassing. So, car is a subclass of vehicle, coupe is a subclass of car, and so on. The opposite of a subclass is a superclass. In this case, then, vehicle is the superclass of car.

Access Modifiers

There is a lot more to PHP OOP than we have room to cover here, but access modifiers are so critical to a full understanding that they simply cannot be excluded.

We have already seen that public functions and variables are inherited by subclasses. Another property of public functions and variables is that they can be accessed by code outside the class. We call the brake() and changeGear() functions from the main body of the code.

Instead of public functions, we could use private functions, which do the opposite of everything public ones do. If the brake() function were to be declared private, it could not be called as it is in the example because private functions can be called only from within another class function. Similarly, private variables can be set only from within a class function. When inheriting, private variables are not accessible to any new functions introduced by the subclass. In our example, we have $name as public; changing that to private would still allow the car function to change the name through setName() because setName() is a vehicle function, not a car function.

The third alternative is protected, which is a slightly less strict version of private. Protected works like private in every way except inheriting. Protected variables are accessible to functions introduced by subclasses.

One of the basic tenets of OOP is encapsulation Classes should be encapsulated so programmers outside don't need to know how its internals work. If you have a class that implements a setName() function, programmers working with it should need to know only which parameters it takes and what its return value is. Although we could just do away with the setName() function and tell programmers to change the $name variable directly, it forces them to have explicit knowledge about how the object works.

Here is a list of functions that could be added to the vehicle class, along with the access method and explanation where needed:

  • accelerate() Public.

  • setspeed() Private/protected because programmers should not be able to arbitrarily define the speed of the car. Instead, they should use accelerate() or decelerate().

  • soundHorn() Public.

  • crash() Public because this is an external event happening to the car that triggers other events.

  • inflateAirbag() Private/protected because this should happen only as a result of something else for example, someone calling crash().

If worse comes to worst and you simply cannot grasp private, protected, and public (even after having purchased a comprehensive PHP book), you can simply declare all your functions and variables as public. It is not preferable, but it works.

     < Day Day Up > 


    Red Hat Fedora 4 Unleashed
    Red Hat Fedora 4 Unleashed
    ISBN: 0672327929
    EAN: 2147483647
    Year: 2006
    Pages: 361

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net