Basic Object-Oriented Programming in PHP
Basic Object-Oriented Programming in PHP
Prev: Chapter-3--Advanced-Database-Concepts
4. Basic Object-Oriented Programming
In This Chapter
OOP Theory
Defining a Class
Creating an Object
The $this Attribute
Creating Constructors
Creating Destructors
Designing Classes with UML
Better Documentation with phpDocumentor
Review and Pursue
Although PHP is still not as strong in its OOP feature set as other languages, object-oriented programming in PHP has a lot going for it. And while
it is possible to have a good career without learning and using OOP, you should familiarize yourself with the concept. At the very least, being able
to use both OOP and procedural programming allows you to better choose the right approach for each individual project.
In this chapter, and the next (Chapter 5, “Advanced OOP”), I will explain not only the syntax of OOP in PHP 5 and later, but the key underlying
OOP theories as well. In this chapter, I will use somewhat mundane examples, but in subsequent chapters, practical, real-world code will be
used. Through multiple examples and plenty of explanation, I hope in this book to fully demonstrate not just how you do object-oriented
programming in PHP but also when and why.
OOP Theory
The first thing that you must understand about OOP is that it presents not just new syntax but a new way of thinking about a problem. By far the
most common mistake beginning OOP programmers make is to inappropriately apply OOP theory. PHP will tell you when you make a syntactical
mistake, but you’ll need to learn how to avoid theoretical mistakes as well. To explain...
All programming comes down to taking actions with data: a user enters data in an HTML form; the PHP code validates it, emails it, and stores it
in a database; and so forth. These are simply verbs (actions) and nouns (data). With procedural programming, the focus is on the verbs: do this,
then this, then this. In OOP, the focus is on the nouns: with what types of things will the application work? In both approaches, you need to
identify both the nouns and the verbs required; the difference is in the focus of the application’s design.
The two most important terms for OOP are class and object. A class is a generalized definition of a thing. Think of classes as blueprints. An
object is a specific implementation of that thing. Think of objects as the house built using the blueprint as a guide. To program using OOP, you
design your classes and then implement them as objects in your programs when needed.
One of the tenets of OOP is modularity: breaking applications into specific subparts. Web sites do many, many things: interact with databases,
handle forms, send emails, generate HTML, etc. Each of these things can be a module, which is to say a class. By separating unrelated (albeit
interacting) elements, you can develop code independently, make maintenance and updates less messy, and simplify debugging.
Related to modularity is abstraction: classes should be defined broadly. This is a common and understandable beginner’s mistake. As an
example, instead of designing a class for interacting with a MySQL database, you should make one that interacts with a nonspecific database.
From there, using inheritance and overriding, you would define a more particular class for MySQL. This class would look and act like the general
database class, but some of its functionality would be customized.
Another principle of OOP is encapsulation: separating out and hiding how something is accomplished. A properly designed class can do
everything you need it to do without your ever knowing how it’s being done. Coupled with encapsulation is access control or visibility, which
dictates how available components of the class are.
Those are the main concepts behind OOP. You’ll see how they play out in the many OOP examples in this book. But before getting into the code,
I’ll talk about OOP’s dark side.
First of all, know that OOP is not a better way to program, just a different way. In some cases, it may be better and in some cases worse.
As for the technical negatives of OOP, use of objects can be less efficient than a procedural approach. The performance difference between
using an object or not may be imperceptible in some cases, but you should be aware of this potential side effect.
A second issue that arises is what I have already pointed out: misuse and overuse of objects. Whereas bad procedural programming can be a
hurdle to later fix, bad OOP can be a nightmare. However, the information taught over the next several chapters should prevent that from being
the case for you.
Defining a Class
OOP programming begins with classes, a class being an abstract definition of a thing: what information must be stored and what functionality
must be possible with that information? A User class would be able to store information such as the user’s name, ID, email address, and so
forth. The functionality of a User could be login, logout, change password, and more.
Syntactically, a class definition begins with the word class , followed by the name of the class. The class name cannot be a reserved word and
is often written in uppercase, as a convention. After the class name, the class definition is placed within curly braces:
class ClassName {
}
Classes contain variables and functions, which are referred to as attributes (or properties) and methods, respectively (you’ll see other terms,
too). Collectively, a class’s attributes and methods are called its members.
class ClassName {
function functionName(
functionName() {
// Function code.
}
}
The methods you define within a class are defined just like functions outside of a class. They can take arguments, have default values, return
values, and so on.
Attributes within classes are a little different than variables outside of classes. First, all attributes must be prefixed with a keyword indicating the
variable’s visibility. The options are public , private , and protected . Unfortunately, these values won’t mean anything to you until you
understand inheritance (in Chapter 5), so until then, just use public :
class ClassName {
$var1,
public $var1, $var2
$var2;;
function functionName(
functionName() {
// Function code.
}
}
As shown here, a class’s attributes are listed before any method definitions.
The second distinction between attributes and normal variables is that if an attribute is initialized with a set value, that value must be a literal
value and not the result of an expression:
Note that you don’t have to initialize the attributes with a value. And, aside from declaring variables, all of a class’s other code goes within its
methods. You cannot execute statements outside of a class method:
class BadClass {
public $num = 2;
$square;
public $square;
$num;
$square = $num * $num; // No!
}
With all of this in mind, let’s create an easy, almost useless class just to make sure it’s all working fine and dandy. Naturally, I’ll use a Hello, world!
example (it’s either that or foo and bar). To make it a little more interesting, this class will be able to say Hello, world! in different languages.
To define a class
1. Create a new PHP document in your text editor or IDE, to be named [Link] (Script 4.1):
class HelloWorld {
Using the syntax outlined earlier, start with the keyword class , followed by the name of the class, followed by the opening curly brace (which
could go on the next line, if you prefer).
For the class name, I use the “uppercase camel” capitalization: initial letters are capitalized, as are the first letters of new words. This is a pseudo-
standardized convention in many OOP languages.
Script 4.1. This simple class will allow you to say Hello, world! through the magic of objects! (Okay, so it’s completely unnecessary, but it’s a fine
introductory demonstration.)
Click here to view code image
1 <?php # Script 4.1 - [Link]
2 /* This page defines the HelloWorld class.
3 * The class says "Hello, world!" in different languages.
4 */
5 class HelloWorld {
6
7 // This method prints a greeting.
8 // It takes one argument: the language to use.
9 // Default language is English.
10 function sayHello($language = 'English') {
11
12 // Put the greeting within P tags:
13 echo '<p>';
14
15 // Print a message specific to a language:
16 switch ($language) {
17 case 'Dutch':
18 echo 'Hallo, wereld!';
19 break;
20 case 'French':
21 echo 'Bonjour, monde!';
22 break;
23 case 'German':
24 echo 'Hallo, Welt!';
25 break;
26 case 'Italian':
27 echo 'Ciao, mondo!';
28 break;
29 case 'Spanish':
30 echo '¡Hola, mundo!';
31 break;
32 case 'English':
33 default:
34 echo 'Hello, world!';
35 break;
36 } // End of switch.
37
38 // Close the HTML paragraph:
39 echo '</p>';
40
41 } // End of sayHello() method.
42
43 } // End of HelloWorld class.
This class currently contains no attributes (variables), as those would have been declared before the methods. This method is called
sayHello() . It takes one argument: the language for the greeting.
For the methods, I normally use the “lowercase camel” convention: start with lowercase letters, separating words with an uppercase letter. This
is another common convention, although not one as consistently followed as that for the class name itself.
The method will print Hello, world! in one of several languages. The message will be wrapped within HTML paragraph tags, begun here.
$language)
switch ($language ) {
'Dutch':
case 'Dutch':
echo 'Hallo, wereld!';
wereld!';
break;
break;
case 'French':
'French':
echo 'Bonjour, monde!';
monde!';
break;
break;
'German':
case 'German':
echo 'Hallo, Welt!';
Welt!';
break;
break;
'Italian':
case 'Italian':
echo 'Ciao, mondo!';
mondo!';
break;
break;
'Spanish':
case 'Spanish':
echo '¡Hola, mundo!';
mundo!';
break;
break;
'English':
case 'English':
default:
default:
echo 'Hello, world!';
world!';
break;
break;
} // End of switch.
The switch prints different messages based upon the chosen language. English is the default language, both in the switch and as the value
of the $language argument (see Step 3). Obviously you can easily expand this switch to include more languages, like non-Western ones.
You’ve now created your first class. This isn’t, to be clear, a good use of OOP, but it starts the process and you’ll learn better implementations of
the concept in due time.
Note that I’m not using a closing PHP tag, which is my policy for PHP scripts to be included by other files.
Tip
Class methods can also have a visibility, by preceding the function definition with the appropriate keyword. If not stated, all
methods have an assumed definition of
functionName(
public function functionName() {...
Tip
The class stdClass is already in use internally by PHP and cannot be declared in your own code.
Creating an Object
Using OOP is a two-step process. The first—defining a class—you just did when you wrote the HelloWorld class. The second step is to make
use of that class by creating an object (or a class instance).
Going back to my User class analogy, an instance of this class may be for the user with a username of janedoe. The user’s attributes might be
that username, a user ID of 2459, and an email address of jane@[Link]. This is one instance of the User class. A second instance,
john_doe, has that username, a user ID of 439, and an email address of [Link]@[Link]. These are separate objects derived from the
same class. They are the same in general, but different in specificity.
Creating an object is remarkably easy in PHP once you’ve defined your class. It requires the keyword new :
ClassName(
$object = new ClassName ();
Now the variable $object exists and is of type ClassName (instead of type string or array). More technically put, $object is an instance of
ClassName .
$object-
$object->methodName
methodName(();
If a method takes arguments, you provide those within parentheses, as in any function call:
$object-
$object->propertyName
propertyName;;
Note that you would not use the property variable’s dollar sign, which is a common cause of parse errors:
(As you’ll also see in the next chapter, the ability to reference an object’s method or property in this manner depends upon the member’s
visibility.)
Once you’ve finished with an object, you can delete it as you would any variable:
unset(
unset($object)
$object);
Simple enough! Let’s go ahead and quickly make use of the HelloWorld class.
To create an object
1. Create a new PHP document in your text editor or IDE, to be named hello_object.php , beginning with the standard HTML (Script 4.2):
The class definition file itself contains no HTML, as it’s not meant to be used on its own. This PHP page will include all of the code necessary to
make a valid HTML page.
Script 4.2. In this page, PHP uses the defined class in order to say Hello, world! in several different languages.
Click here to view code image
1 <!doctype html>
2 lang=
<html lang="en
en"">
3 head>
<head>
4 charset=
<meta charset ="utf-8
utf-8"
">
5 <title>
title>Hello,
Hello, World!
World!</title
</title>>
6 rel=
<link rel="stylesheet
stylesheet" " href
href=
="[Link]
[Link]"
">
7 </head
</head>
>
8 body>
<body>
9 <?php # Script 4.2 - hello_object
hello_object..php
10 /* This page uses the HelloWorld class.
11 * This page just says "Hello, world!".
12 */
13
14 // Include the class definition:
15 require(
require('[Link]'
'[Link]'));
16
17 // Create the object:
18 HelloWorld(
$obj = new HelloWorld();
19
20 // Call the sayHello() method:
21 $obj-
$obj->sayHello
sayHello(();
22
23 // Say hello in different languages:
24 $obj-
$obj->sayHello(
sayHello('Italian')
'Italian');
25 $obj-
$obj->sayHello
sayHello(('Dutch'
'Dutch'));
26 $obj-
$obj->sayHello
sayHello(('French'
'French'));
27
28 // Delete the object:
29 unset(
unset($obj
$obj)
);
30 ?>
31 </body
</body>
>
32 </html
</html>
>
require(
require('[Link]'
'[Link]')
);
In order to create an instance of a class, the PHP script must have access to that class definition . As the definition is stored in a separate file,
that file must be included here. By using require() (as opposed to include() ), the script will stop executing with a fatal error if the file
could not be included (and there is no point in continuing without this file).
You’ll see an error like this if you go to create an object whose class definition cannot be found.
HelloWorld(
$obj = new HelloWorld ();
This one line of code is all there is to it! You can give the object variable any valid name you’d like, of course.
$obj-
$obj->sayHello
sayHello(
();
This line of code will call the sayHello() method, which is part of the $obj object. Since the method is not being given any arguments, the
greeting will be in the default language of English.
$obj-
$obj->sayHello
sayHello(
('Italian'
'Italian'));
$obj-
$obj->sayHello
sayHello(
('Dutch'
'Dutch')
);
$obj-
$obj->sayHello
sayHello(
('French'
'French'));
An object’s methods can be called multiple times, like any other function. Different arguments are provided to vary the result.
unset(
unset($obj
$obj)
);
?>
</body
</body>
>
</html
</html>
>
You don’t technically have to delete the object—it will be deleted as soon as the script ends. Still, I think it’s better programming form to tidy up
like this.
7. Save the file as hello_object.php and place it in your Web directory, along with [Link] .
You don’t have to place both documents in the same directory, but if they are stored separately, you will need to change the require() line
accordingly.
Note that you should run hello_ [Link] , not [Link] , in your Web browser.
Tip
Class names are not case-sensitive. However, object names, like any variable in PHP, are case-sensitive.
Tip
Because function names in PHP are not case-sensitive, the same is true for method names in classes.
The HelloWorld class does succeed in a couple of ways, though. It does demonstrate some of the syntax. And it is reusable: if
you have a project that needs to say Hello, world! dozens of times, this one object will do it. And if you need to change it to Hello,
World! (with a capital “W”), edit just the one file and you’re golden. To that end, however, it’d be better for the method to return the
string, rather than just print it, so the string could be used in more ways.
Finally, this class kind of reflects the notion of encapsulation: you can use the object to say Hello, world! in multiple languages
without any knowledge of how the class does that.
Are variables
Must be declared as public , private , or protected (I’ll use only public in this chapter)
If initialized, must be given a static value (not the result of an expression)
Those are the rules for defining a class’s attributes, but using those attributes requires one more piece of information. As already explained,
through the object, you can access attributes via the object notation operator ( -> ):
$object->propertyName;
The issue is that within the class itself (i.e., within a class’s methods), you must use an alternative syntax to access the class’s attributes. You
cannot do just this:
class BadClass {
public $var;
function do() {
// This won't work:
print $var;
}
}
The do() method cannot access $var in that manner. The solution is a special variable called $this . The $this variable in a class always
refers to the current instance (i.e., the object involved) of that class. Within a method, you can refer to the instance of a class and its attributes by
using the $this-> attributeName syntax.
Rather than over-explaining this concept, I’ll go right into another example that puts this new knowledge into action. This next, much more
practical, example will define a class representing a rectangle.
class Rectangle {
public $width = 0;
public $height = 0;
This class has two attributes: one for the rectangle’s width and another for its height. Both are initialized to 0.
The setSize() method takes two arguments, corresponding to the width and height. Both have default values of 0, just to be safe.
Within the method, the class’s attributes are given values using the numbers to be provided when this method is called (assigned to $w and
$h ). Using $this->width and $this->height refers to this class’s $width and $height attributes.
Script 4.3. This class is much more practical than the HelloWorld example. It contains two attributes—for storing the rectangle’s width and
height—and four methods.
Click here to view code image
1 <?php # Script 4.3 - [Link]
2 /* This page defines the Rectangle class.
3 * The class contains two attributes: width and height.
4 * The class contains four methods:
5 * - setSize()
6 * - getArea()
7 * - getPerimeter()
8 * - isSquare()
9 */
10
11 class Rectangle {
12
13 // Declare the attributes:
14 public $width = 0;
15 public $height = 0;
16
17 // Method to set the dimensions:
18 function setSize($w = 0, $h = 0) {
19 $this->width = $w;
20 $this->height = $h;
21 }
22
23 // Method to calculate and return the area.
24 function getArea() {
25 return ($this->width * $this->height);
26 }
27
28 // Method to calculate and return the perimeter.
29 function getPerimeter() {
30 return ( ($this->width + $this->height) * 2 );
31 }
32
33 // Method to determine if the rectange
34 // is also a square.
35 function isSquare() {
36 if ($this->width == $this->height) {
37 return true; // Square
38 } else {
39 return false; // Not a square
40 }
41 }
42
43 } // End of Rectangle class.
function getArea() {
return ($this->width * $this->height);
}
This method doesn’t need to take any arguments, because it can access the class’s attributes via $this . Calculating the area of a rectangle is
simple: multiply the width times the height. This value is then returned.
function getPerimeter() {
return ( ($this->width + $this->height) * 2 );
}
function isSquare() {
if ($this->width == $this->height) {
return true;
} else {
return false;
}
}
This method compares the rectangle’s dimensions. If they are the same, the Boolean true is returned, indicating the rectangle is a square.
Otherwise, false is returned.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Rectangle</title>
<link rel="stylesheet"
href="[Link]">
</head>
<body>
<?php # Script 4.4 - [Link]
require('[Link]');
$width = 42;
$height = 7;
echo "<h2>With a width of $width and a height of $height...</h2>";
$r = new Rectangle();
$r->setSize($width, $height);
The first line creates an object of type Rectangle . The second line assigns the values of the variables in this script— $width and $height —
to the object’s attributes. The values here are assigned to $w and $h in the setSize() method when it’s called, which are then assigned to
$this->width and $this->height within that method.
5. Print the rectangle’s area:
To print the rectangle’s area, you only need to have the object tell you what that value is by calling its getArea() method. As this method
returns the area (instead of printing it), it can be used in an echo statement like this.
Since the isSquare() method returns a Boolean value, I can invoke it as a condition. This code will print either This rectangle is also a square.
or This rectangle is not a square.
unset($r);
?>
</body>
</html>
9. Save the file as [Link] and place it in your Web directory, along with [Link] .
Script 4.4. The Rectangle class is used in this PHP script. The rectangle’s dimensions are first assigned to the class’s attributes by invoking the
setSize() method, and then various properties of the rectangle are reported.
Click here to view code image
1 <!doctype html>
2 <html lang="en">
3 <head>
4 <meta charset="utf-8">
5 <title>Rectangle</title>
6 <link rel="stylesheet" href="[Link]">
7 </head>
8 <body>
9 <?php # Script 4.4 - [Link]
10 /* This page uses the Rectangle class.
11 * This page shows a bunch of information about a rectangle.
12 */
13
14 // Include the class definition:
15 require('[Link]');
16
17 // Define the necessary variables:
18 $width = 42;
19 $height = 7;
20
21 // Print a little introduction:
22 echo "<h2>With a width of $width and a height of $height...</h2>";
23
24 // Create a new object:
25 $r = new Rectangle();
26
27 // Assign the rectangle dimensions:
28 $r->setSize($width, $height);
29
30 // Print the area:
31 echo '<p>The area of the rectangle is ' . $r->getArea() . '</p>';
32
33 // Print the perimeter:
34 echo '<p>The perimeter of the rectangle is ' . $r->getPerimeter() . '</p>';
35
36 // Is this a square?
37 echo '<p>This rectangle is ';
38 if ($r->isSquare()) {
39 echo 'also';
40 } else {
41 echo 'not';
42 }
43 echo ' a square.</p>';
44
45 // Delete the object:
46 unset($r);
47
48 ?>
49 </body>
50 </html>
Various attributes for a rectangle are revealed using the Rectangle class.
11. Change the variables’ values in [Link] and rerun it in your Web browser .
If the width and height are the same, the rectangle is also a square.
Tip
Having get_and set methods in a class is a common convention. Methods starting with set are used to assign values to class
attributes. Methods starting with get are used to return values: either attributes or the results of calculations.
Tip
Methods can call each other, just as they would any other function, but you’ll need to use $this again. The following is
unnecessary but valid:
function getArea() {
if ($this->isSquare()) {
return ($this->width *
$this->width);
} else {
return ($this->width *
$this->height);
}
}
One criticism may be that the class is too specific. Logically, if you’ve created a site that performs a lot of geometry, the
Rectangle class might be an inherited class from a broader Shape . You’ll learn about inheritance in the next chapter.
From the first two examples you can see the benefit of objects: the ability to create your own data type. Whereas a string is a
variable type whose only power is to contain characters, the Rectangle is a new, powerful type with all sorts of features.
Creating Constructors
A constructor is a special kind of method that differs from standard ones in three ways:
class ClassName {
$var;
public $var;
_construct(
function _ _construct () {
// Function code.
}
}
A constructor could be used to connect to a database, set cookies, or establish initial values. Basically, you’ll use constructors to do whatever
should always be done—and done first—when an object of this class is made.
Because the constructor is still just another method, it can take arguments, and values for those arguments can be provided when the object is
created:
class User {
_construct(
function _ _construct ($id
$id)) {
// Function code.
}
}
User(
$me = new User(2354
2354));
The Rectangle class could benefit from having a constructor that assigns the rectangle’s dimensions when the rectangle is created.
_construct(
function _ _construct ($w = 0, $h = 0) {
$this-
$this->width = $w;
$w;
$this-
$this->height = $h
$h;
;
}
Script 4.5. A constructor has been added to the Rectangle class. This makes it possible to assign the rectangle’s dimensions when the object is
created.
Click here to view code image
1 <?php # Script 4.5 - Rectangle
Rectangle.
.php
2 /* This page defines the Rectangle class.
3 * The class contains two attributes: width and height.
4 * The class contains five methods:
5 * - _ _construct()
6 * - setSize()
7 * - getArea()
8 * - getPermeter()
9 * - isSquare()
10 */
11
12 class Rectangle {
13
14 // Declare the attributes:
15 public $width = 0;
16 public $height = 0;
17
18 // Constructor:
19 _construct(
function _ _construct ($w = 0, $h = 0) {
20 $this-
$this->width = $w;
$w;
21 $this-
$this->height = $h
$h;;
22 }
23
24 // Method to set the dimensions:
25 setSize(
function setSize($w = 0, $h = 0) {
26 $this-
$this->width = $w
$w;
;
27 $this-
$this->height = $h
$h;;
28 }
29
30 // Method to calculate and return the area:
31 getArea(
function getArea() {
32 $this-
return ($this->width * $this
$this-->height
height)
);
33 }
34
35 // Method to calculate and return the perimeter:
36 function getPerimeter(
getPerimeter() {
37 $this-
return ( ($this->width + $this
$this-->height
height)
) * 2 );
38 }
39
40 // Method to determine if the rectange
41 // is also a square.
42 isSquare(
function isSquare () {
43 $this-
if ($this->width == $this
$this-
->height
height)
) {
44 return true;
true; // Square
45 } else {
46 false;
return false ; // Not a square
47 }
48
49 }
50
51 } // End of Rectangle class.
This method is exactly like the setSize() method, albeit with a different name. Note that constructors are normally the first method defined
in a class (but still defined after the attributes).
160;
$width = 160;
$height = 75;
75;
Rectangle(
$r = new Rectangle($width
$width,
, $height
$height)
);
The object can now be created and the rectangle assigned its dimensions in one step.
This method is still part of the class, though, which makes sense. By keeping it in there, you ensure that a rectangle object’s size can be changed
after the object is created.
Script 4.6. This new version of the script assigns the rectangle’s dimensions when the object is created (thanks to the constructor).
Click here to view code image
1 <!doctype html>
2 lang=
<html lang="en
en"">
3 head>
<head>
4 charset=
<meta charset ="utf-8
utf-8"
">
5 title>
<title>Rectangle
Rectangle</</title
title>>
6 rel=
<link rel="stylesheet
stylesheet" " href
href=
="[Link]
[Link]"
">
7 </head
</head>
>
8 body>
<body>
9 <?php # Script 4.6 - rectangle2
rectangle2..php
10 /* This page uses the revised Rectangle class.
11 * This page shows a bunch of information
12 * about a rectangle.
13 */
14
15 // Include the class definition:
16 require(
require('[Link]'
'[Link]')
);
17
18 // Define the necessary variables:
19 160;
$width = 160;
20 75;
$height = 75;
21
22 // Print a little introduction:
23 echo "<
"<h2>
h2>With a width of $width and a height of $height.
$height...</h2
</h2>
>";
24
25 // Create a new object:
26 Rectangle(
$r = new Rectangle ($width
$width,
, $height
$height));
27
28 // Print the area.
29 echo '<
'<p>The area of the rectangle is ' . $r->getArea() . '</
'</p
p>';
30
31 // Print the perimeter.
32 '<
echo '<p>The perimeter of the rectangle is ' . $r->getPerimeter() . '</
'</p
p>';
33
34 // Is this a square?
35 '<
echo '<p>This rectangle is ';
';
36 $r-
if ($r->isSquare
isSquare(()) {
37 echo 'also';
'also';
38 } else {
39 'not';
echo 'not';
40 }
41 echo ' a square.
square.</
</p
p>';
42
43 // Delete the object:
44 unset(
unset($r
$r)
);
45
46 ?>
47 </body
</body>
>
48 </html
</html>
>
8. Save the file as [Link] , place it in your Web directory along with the new [Link] (Script 4.5), and test in your Web
browser .
The resulting output is not affected by the incorporation of a constructor in the Rectangle class.
Tip
A constructor like the one just added to the Rectangle class is called a default constructor, as it provides default values for its
arguments. This means that a Rectangle object can be created using either of these techniques:
$r = new Rectangle(
Rectangle($width,
$width, $height)
$height);
$r = new Rectangle(
Rectangle();
Tip
You can directly call a constructor (although you will rarely need to):
SomeClass(
$o = new SomeClass();
$o-
$o->_ _construct
_construct(
();
With the Rectangle example, this would let you get rid of the setSize() method without losing the ability to resize a
rectangle.
Tip
In PHP 4 and in other programming languages (like C++), a constructor is declared by creating a method whose name is the
same as the class itself.
Tip
If PHP 5 cannot find a _ _construct() method in a class, it will then try to find a constructor whose name is the same as the
class (the PHP 4 constructor naming scheme).
Creating Destructors
The corollary to the constructor is the destructor. Whereas a constructor is automatically invoked when an object is created, the destructor is
called when the object is destroyed. This may occur when you overtly remove the object:
Or this may occur when a script ends (at which point PHP releases the memory used by variables).
Being the smart reader that you are, you have probably already assumed that the destructor is created like so:
class ClassName {
// Attributes and methods.
_destruct(
function _ _destruct() {
// Function code.
}
}
Destructors do differ from constructors and other methods in that they cannot take any arguments.
The Rectangle class used in the last two examples doesn’t lend itself to a logical destructor (there’s nothing you need to do when you’re done
with a rectangle). And rather than do a potentially confusing but practical example, I’ll run through a dummy example that shows how and when
constructors and destructors are called.
Autoloading Classes
When you define a class in one script that is referenced in another script, you have to make sure that the second script includes
the first, or there will be errors. To that end, PHP 5 supports a special function called _ _autoload (note that functions in PHP
beginning with two underscores are special ones).
The _ _autoload() function is invoked when code attempts to instantiate an object of a class that hasn’t yet been defined. The
_ _autoload() function’s goal is to include the corresponding file. In simplest form, this might be
Click here to view code image
function _ _autoload ($class
$class)
) {
require(
require($class . '.php'
'.php')
);
}
For each new object type created in the following code, the function will be invoked:
Class(
$obj = new Class ();
Human(
$me = new Human ();
Rectangle(
$r = new Rectangle ();
Thanks to the _ _autoload() function, those three lines will automatically include [Link] , [Link] and
[Link] (within the current directory).
Notice that this _ _autoload() function is defined outside of any class; instead, it is placed in a script that instantiates the
objects.
The previous edition of this book demonstrated use of the _ _autoload() function, but that approach has been deprecated in
favor of using the Standard PHP Library (SPL). It will be discussed in Chapter 8, “Using Existing Classes.”
To create a destructor
1. Create a new PHP document in your text editor or IDE, to be named [Link] , beginning with the standard HTML (Script 4.7):
class Demo {
To make this example even simpler, I’ll define and use the class in the same script.
3. Create the constructor:
The constructor doesn’t do anything but print a message indicating that it has been invoked. This will allow you to trace when the class’s
automatic methods are called.
Script 4.7. This script doesn’t do anything except best convey when constructors and destructors are called.
Click here to view code image
1 <!doctype html>
2 lang=
<html lang="en
en"">
3 head>
<head>
4 charset=
<meta charset ="utf-8
utf-8"
">
5 title>
<title>Constructors and Destructors
Destructors</
</title
title>
>
6 rel=
<link rel="stylesheet
stylesheet" " href
href=
="[Link]
[Link]"
">
7 </head
</head>
>
8 body>
<body>
9 <?php # Script 4.7 - demo.
[Link]
10 /* This page defines a Demo class
11 * and a demo() function.
12 * Both are used to show when
13 * constructors and destructors are called.
14 */
15
16 // Define the class:
17 class Demo {
18
19 // No attributes.
20
21 // Constructor:
22 _construct(
function _ _construct() {
23 '<
echo '<p>In the constructor.
constructor.</
</p
p>';
24 }
25
26 // Destructor:
27 _destruct(
function _ _destruct() {
28 '<
echo '<p>In the destructor.
destructor.</
</p
p>';
29 }
30
31 } // End of Demo class.
32
33 // Define a test() function:
34 test(
function test() {
35 '<
echo '<p>In the function
function.
. Creating a new object
object.
...</
</p
p>';
36 Demo(
$f = new Demo ();
37 '<
echo '<p>About to leave the function
function.
.</
</p
p>';
38 }
39
40 // Create the object:
41 echo '<
'<p>Creating a new object.
object...</p
</p>';
42 Demo(
$o = new Demo();
43
44 // Call the test() function:
45 echo ''<
<p>Calling the function
function.
...</
</p
p>';
46 test(
test();
47
48 // Delete the object:
49 echo '<
'<p>About to delete the object.
object...</p
</p>';
50 unset(
unset($o
$o)
);
51
52 '<
echo '<p>End of the script.
script.</
</p
p>';
53 ?>
54 </body
</body>
>
55 </html
</html>
>
To best illuminate the life of objects, which affects when constructors and destructors are called, I’m adding this simple function. It prints
messages and creates its own object, which will be a variable that’s local to this function.
When this object is created, the constructor will be called. So this script first prints this line (Creating a new object...) and will then print In the
constructor.
After printing the status statement, the function is called. Consequently, the function is entered, wherein In the function. Creating a new object...
will first be printed. Then, in that function, a new object is created (called $f ). Therefore, the constructor will be called again, and the In the
constructor. message printed, as you’ll see in the final output.
After the object is created in the function, the About to leave the function. message is printed. Then the function is exited, at which point in time
the object defined in the function— $f —goes away, thus invoking the $f object’s destructor, printing In the destructor.
11. Save the file as [Link] and place it in your Web directory. Then test by viewing it in your Web browser .
The flow of the two objects’ creation and destruction over the execution of the script is revealed by this script. In particular, you can see how
the test() function’s object, $f , lives and dies in the middle of this script.
12. Delete the unset($o) line, save the file, and rerun it in your Web browser .
If you don’t forcibly delete the object , it will be deleted when the script stops running. This means that the $o object’s destructor is
called after the final printed message, even after the closing HTML tags .
Also check the HTML source code of this page to really understand the flow.
The $o object’s destructor is called as the very last script event, when the script stops running. Thus, the In the destructor. message gets
sent to the browser after the closing HTML tag.
(Arguably, you could also delete the About to delete the object... line, although I did not for the two figures.)
Tip
In C++ and C#, the destructor’s name for the class ClassName is ~ClassName , the corollary of the constructor, which is
ClassName . Java does not support destructors.
Its name
Its attributes
Its methods
UML graphically represents a class by creating a class diagram: a three-part box for each class, with the class name at the top. The next section
of the box would identify the class attributes, and the third would list the methods .
For the attributes, the attribute type (e.g., string, array, etc.) is listed after the attribute’s name, as in
userId:
userId:number
username:
username:string
If the attribute had a default value, you could reflect that too:
width:
width:number = 0
To define a method in a class diagram, you would start with the method name, placing its arguments and types within parentheses. This is
normally followed by the type of value the method returns:
sayHello(
sayHello(language
language:
:string
string)
):void
The sayHello() method doesn’t return anything, so its return type is void .
Second, a principle of OOP is encapsulation: separating out and hiding how something is accomplished. A UML, with its listing of
attributes, methods, and arguments, can act as a user guide for those classes. Any code that requires classes that have been
modeled should be able to use the classes, and its methods and attributes, without ever looking at the underlying code. In fact,
you can distribute the UML along with your code as a service to your clients.
With this in mind, you can complete the class diagram for the HelloWorld class . In the next steps, you’ll design the diagram that reflects
the Rectangle class.
If you like the feeling of designing with paper and pencil, feel free, but there are also plenty of software tools that can fulfill this role, too. Search
online for an application that will run on your platform, or for a site that can serve the same purposes within the browser.
Rectangle
width:
width:number = 0
height:
height:number = 0
Here are the two attributes for the Rectangle class. Both are numbers with default values of 0.
This method is named _ _construct . It takes two arguments, both of type number, and both with default values of 0. The method does not
return anything, so its return value is void .
setSize(
setSize(width
width:
:number = 0, height
height:
:number = 0):void
getArea(
getArea():number
getPerimeter(
getPerimeter():number
isSquare(
isSquare():Boolean
Tip
Be certain to update your class design should you later change your class definition.
Tip
In the next chapter, in which more complex OOP theory is unveiled, you’ll learn more UML techniques.
Better Documentation with phpDocumentor
Along with creating a UML class design, another new topic in this edition is creating better code documentation using phpDocumentor
([Link]).
In my opinion, properly documenting one’s code is so vitally important that I wish PHP would generate errors when it came across a lack of
comments! Having taught PHP and interacted with readers for years, I am amazed at how often programmers omit comments, occasionally
under the guise of waiting until later. Proper documentation is something that should be incorporated into code for your own good, for your
client’s, for your co-workers’ (if applicable), and for the programmer in the future who may have to alter or augment your work—even if that
programmer is you.
Although you can adequately document your code using simple comments, as I do in this book, there are two obvious benefits to adopting a
formal phpDocumentor approach:
The generated HTML can also be a valuable resource for anyone using your code, particularly your classes.
phpDocumentor creates documentation by reading the PHP code and your comments. To facilitate that process, you would start writing your
comments in a way that phpDocumentor understands. To begin, you’ll use the docblock syntax:
/**
*
* Short description
*
* Long description
* Tags
*/
The short description should be a single line description. The long description can go over multiple lines and even use some HTML. Both are
optional.
After the description, write one or more lines of tags. Each tag is prefaced by @, and phpDocumentor supports several kinds; which you use will
depend on the thing you’re documenting.
Class definition
Function or method definition
Variable declaration
Constant definition
File inclusion
A docblock should be written at the top of a script, in order to document the entire file (Script 4.8).
To document a variable declaration, you use the @var tag, followed by the variable’s type (and optional description):
/**
* @var string
*/
$name = 'Larry Ullman';
Notice that the docblock doesn’t need to reference the variable name, as phpDocumentor will be able to read that from the following line of
code. The point of the docblock is to indicate the variable’s intended type.
To document methods and functions, use @param to detail the function’s parameters and @return to indicate the type of value the function
returns (Script 4.8).
The details as to the possible types, and the full usage of all of phpDocumentor, can be found in the documentation ([Link]/docs/).
Once you’ve written comments in the proper format, you can use the phpDocu-mentor tool to generate your documentation. To do that, you
must first install phpDocumentor. The best way to install it is using PEAR ([Link] so you must have that installed, too. PEAR already
comes installed with many all-inone WAMP, MAMP, or LAMP stacks; check your associated documentation if you’re using one of these. If not, see
the sidebar for some tips on installing PEAR.
To use phpDocumentor
1. Complete the phpDocumentor-type comments for a file (Script 4.8) or application.
My assumption is that you already know how to do this for your platform. If not, search the Web or use my support forums for answers.
This will allow you to download the latest version of the phpDocumentor directory from that site.
4. Install phpDocumentor :
This instruction comes straight from the phpDocumentor Web site. It may change in time; check the site for the best, current instructions.
Still, installing PEAR is not impossibly hard, and once you master the installation of a single package, installing more is a snap. If
you want to try your hand at installing PEAR packages, start by checking out the PEAR manual, which has instructions. If you’re still
not clear as to what you should do, search the Web for articles on the subject, particular to your operating system, and/or post a
question in the book’s supporting forum, where I’ll be happy to assist.
cd /path/to/folder
That line tells phpDocumentor to parse the file [Link] and to write the output to the target (-t) directory docs , which would be a
folder in that same directory. phpDocumentor will attempt to create that directory, if it does not exist.
Tip
For the sake of saving precious book space, the code in this book will not be documented using the full phpDocumentor syntax.
Tip
To view documentation mistakes, check out the generated errors.
Tip
To have phpDocumentor document an entire project, you can have it parse the current directory using
phpdoc -d . -t docs
Tip
If you want, you can edit the templates used by phpDocumentor to output HTML more to your liking.
Review
How does OOP differ from procedural programming? (See page 120.)
What is a class? What is an object? What is an attribute (or property)? What is a method? (See page 121.)
What syntax do you use to create a class? To create an object? (See pages 121 and 124.)
How do you create class methods? How do you call object methods? (See pages 121 and 124.)
How do you create class attributes? How do you reference those attributes within the class? How do you reference those attributes using an
object? (See pages 121, 124, and 127.)
What is a constructor? How do you create one? When is a constructor called? (See page 133.)
What is a destructor? How do you create one? When is a destructor called? (See page 136.)
What is UML? How do you represent a class in UML? (See page 140.)
What is phpDocumentor? What are the arguments for using it? (See page 143.)
What is a docblock? (See page 144.)
Pursue
Come up with another (relatively simple) class. Define and use it in PHP. Then model and document it using UML and phpDocumentor.
Learn more about UML, if you are so inclined.
Find UML software that you like (for your platform or online).
Learn more about phpDocumentor, if you are so inclined.
Add phpDocumentor-style comments to the Rectangle class and then generate its documentation.