Throughout this book, we were mainly using procedural code to build the example application. However, the PDO API is fully object-oriented, and in the last chapter we imitated real-life entities in the database by using classes. This appendix is for those programmers who are not familiar with PHP5's object-oriented extensions. We will introduce you to the basics of OOP, as many developers coming from earlier versions of PHP have no experience of this type of programming. However, this is only a short introduction; if you want to master OOP, you should refer to some of the books devoted to this topic.
Object-oriented programming (OOP) is a relatively new concept, although its roots date back to 1960s. In OOP, the software works with objects that model real-life entities (such as books and authors in the Chapter 7). Whereas procedural programming involves a series of instructions, an application in OOP involves a set of objects that interact with each other.
An object can be viewed as a container for several variables, called properties, and for functions that act on these variables. These functions are called methods. Every object belongs to a class. In PHP, every object can belong to only one class (although some other OOP languages allow multiple inheritance), but there can be many objects, or instances, belonging to a single class. A class is a syntactic construct that allows you to describe what properties and methods the objects belonging to this class will have.
There is an analogy with species and living organisms—for example, a Dog (a species, or a class) is a generalization of all living dogs. A generalized dog has such properties as weight and age, and a method such as bark, and a real-life dog, say Lessie, which belongs to the dog species, could be described as an instance of the Dog
class.
Let's see how we would model this in PHP5:
class Dog { public $weight; public $age; function bark() { print "woof!"; } } $lessie = new Dog(); $lessie->weight = 15; $lessie->age = 3; $lessie->bark();
In this small snippet of code, we defined a class called Dog
. In PHP5, a class definition starts with the reserved word class
followed by the class's name (A class's name can contain the same characters as a function's name.) All the class's properties and methods, collectively called members, are defined inside the {…}
block.
As you can see, we are using the keyword, public
, when we declare properties and methods. In PHP4 we would have used the var
keyword instead, but this keyword is deprecated in PHP5. Besides the public
keyword, we could have used the protected
keyword or the private
keyword, but more on this later.
As you can see in the second part of the code, we create the object with the new
keyword:
$lessie = new Dog();
This line creates a new object belonging to the Dog
class and assigns it to the $lessie
variable. This is a very important step, since this is the only way to create objects. After the PHP processes it, the $lessie
variable becomes initialized and we can access the properties and methods declared in the Dog
class so that we act on the object called Lessie
. We would now like to have two dogs in our application, and the second one will be called K9
. To achieve that, we would have to write something like this:
$k9 = new Dog(); $k9->age = 5; $k9->weight = 18;
Now, we can access both the $k9
and $lessie
variables, if we would like to interface with each of our dogs.
In other words, before we can communicate with an instance, it first has to be created with the new
keyword.
After the variable has been initialized, we can access its properties and methods. As you can see in the code, this is achieved with the ->
construct, which is used with both properties and methods. Note that when accessing a class’s properties, we don’t have to write the dollar sign after the -> (but we have to use it when declaring the properties inside the class definition).
The methods are declared with the function
keyword followed by the method’s name and a list of parameters. In fact, a class’s methods are declared in a similar way to that for an ordinary function, but there is one major difference. Inside the declaration of a method, there always exists implicit variable, called $this
, which allows you to access the object’s properties. Let’s see how we could create a getInfo()
method to return some additional information about our dogs:
<?php
class Dog
{
public $weight;
public $age;
function bark()
{
print "woof!";
}
function getInfo()
{
return 'Weight: ' . $this->weight . ' kg, age: ' . $this->age .
' years';
}
}
$lessie = new Dog();
$lessie->weight = 15;
$lessie->age = 3;
$k9 = new Dog();
$k9->age = 5;
$k9->weight = 18;
echo 'Lessie: ', $lessie->getInfo(), "\n";
echo 'K9: ', $k9->getInfo(), "\n";
This code would display the following output:
Lessie: Weight: 15 kg, age: 3 years K9: Weight: 18 kg, age: 5 years
Every class also has a special function (which may be implicit or explicitly declared) called a constructor. The constructor is always called when PHP encounters the new
keyword, and its purpose is to perform some initialization tasks. Let's extend the Dog
class so that it has a $name
property. We will also change the code so as to initialize the name, weight
, and age
properties inside the constructor rather than in the main application:
<?php class Dog { public $weight; public $age; public $name; function __construct($name, $age, $weight) { $this->name = $name; $this->weight = $weight; $this->age = $age; } function bark() { print "woof!"; } function getInfo() { return 'Name: ' . $this->name . ', weight: ' . $this->weight . ' kg, age: ' . $this->age . ' years'; } } $lessie = new Dog('Lessie', 3, 15); $k9 = new Dog('K9', 5, 18); echo $lessie->getInfo(), "\n"; echo $k9->getInfo(), "\n";
This application would display the following:
Name: Lessie, weight: 15 kg, age: 3 years Name: K9, weight: 18 kg, age: 5 years
Here's a brief summary of what we did. We first declared the $name
property and then the constructor for our Dog
class. The constructors are declared as function with the special name of __construct
(the word constructor
prepended with two underscores('_'). Our constructor accepts three parameters—name, age
, and weight
, whose values are assigned to the object's properties. The order in which we assign values to the properties does not matter. Note that we always have to use the $this
variable to denote the properties of the object. By doing this, we can differentiate the local variables $name, $age
, and $weight
(passed as parameters) from the object's own properties, which have the same names, inside the constructor.
We also changed the getInfo()
method so that it returns the name of the dog as well. We can now instantiate objects by passing the name, the age, and the weight to the constructor. Since these properties get assigned in the constructor, we don't have to do this in the main part of the code.
It should be also noted that you can assign default values to properties in the class definition. This will ensure that every object of that class will have the default values automatically assigned. For example, we can do the following:
class Dog
{
public $weight;
public $age;
public $name;
public $hasCollar = true;
function __construct($name, $age, $weight)
{
$this->name = $name;
$this->weight = $weight;
$this->age = $age;
}
function bark()
{
print "woof!";
}
function getInfo()
{
return
'Name: ' . $this->name .
', weight: ' . $this->weight .
' kg, age: ' . $this->age .
' years, has collar: ' . ($this->hasCollar ? 'yes' : 'no');
}
}
If you run the application with this Dog
class definition, then you will see the following output:
Name: Lessie, weight: 15 kg, age: 3 years, has collar: yes Name: K9, weight: 18 kg, age: 5 years, has collar: yes
As you can now see, the default property value for hasCollar
has propagated to every newly created instance (of course, it can be later changed for each object).
There is an opposite concept to constructors, called destructors. As its name suggests, destructors are used to perform cleanup tasks (classic examples of such tasks are deleting temporary files, closing database connections, etc). In PHP5, destructor on an object is called, when there are no more references to that object (for example, by setting the variable that holds the reference to the object to null or when the application terminates), then the destructor will be called.
Destructor is a method: __destruct()
. If you add that method to the class, then it will be called when the object is freed. Let’s add the destructor to the Dog class:
class Dog { public $weight; public $age; public $name; public $hasCollar = true; function __construct($name, $age, $weight) { $this->name = $name; $this->weight = $weight; $this->age = $age; } function bark() { print "woof!"; } function getInfo() { return 'Name: ' . $this->name . ', weight: ' . $this->weight . ' kg, age: ' . $this->age . ' years, has collar: ’ . ($this->hasCollar ? 'yes’ : 'no’); } function __destruct() { print "Freeing $this->name\n"; } }
Now, if you run the code again, it will give the following output:
Name: Lessie, weight: 15 kg, age: 3 years, has collar: yes Name: K9, weight: 18 kg, age: 5 years, has collar: yes Freeing K9 Freeing Lessie
Note that the order in which PHP5 calls the destructors is not defined. Also, in a destructor, the code may not access other objects unless they are referenced by the object being freed. In other words, the destructor should only cleanup those resources that were created by that object.