Web Programming for Business - PHP Object-Oriented Programming with Oracle

2 Object-Oriented Concepts and Fundamentals

Overview

Object-oriented programming (OOP) is a design philosophy that uses objects and methods rather than linear concepts of procedures and tasks (procedural programming) to accomplish programmatic goals. An object is a self-sustainable construct that enables reusability of code. A methodspecifies one operation without providing any details to describe how the operation should be carried out. This chapter covers OOP fundamentals, including classes, properties, methods, and objects. In addition, encapsulation, polymorphism, inheritance, abstract classes, interfaces, aggregation, and supplemental OOP concepts are covered.

Learning Objectives

After you complete this chapter, you will gain a fundamental understanding of OOP concepts through explanation and code examples. The following objectives summarize the skills the chapter will help you develop:

1.    Learn the main advantages of OOP.

2.    Learn the building blocks of OOP.

3.    Learn how to create and instantiate a class.

4.    Learn OOP fundamentals.

5.    Learn about getters and setters.

6.    Learn about the constructor, destructor, and ‘toString’ methods.

7.    Learn about constants and static methods and properties.

8.    Learn about type hinting.

9.    Learn about exception handling.

10.Learn about debugging.

Advantages of OOP

Object-oriented programming (OOP) has four main advantages over procedural programming – modularity, code reusability, information-hiding, and debugging ease.

Modularity is when a piece of code is independent of other pieces of code. Reusability is when code can be used, without modification, to perform a specific service regardless of what application uses the code. OOP facilitates code reusability by making it easy to break down complex tasks into generic modules (classes) and separate files that contain classes from the main PHP script. Information-hiding is when the details of the internal implementation of a module (class) remain hidden from the outside world. Debugging ease means that when a problem occurs, it is much easier to fix because the module (class) is independent from other pieces of code. Independent modules (classes) facilitate easier maintenance because the code is modular by nature. So, modifying one piece of code doesn’t impact other pieces of code in the application. Reliability is also enhanced because the natural modularity of OOP helps ensure consistency of the code. Once a module (class) has been tested, it can be thought of as a ‘black box’ and relied upon to produce consistent results. Such consistency means that you only have to fix a coding problem in one place.

Class

The fundamental building block of OOP is a class. A class is a collection of related properties and methods wrapped in a pair of curly braces and labeled with its name. A property is what we normally think of in procedural programming as a variable. A method is what we normally think of as a function in procedural programming. Properties and methods, however, are much more flexible than their procedural programming counterparts.

Object

An object is a data structure consisting of data fields and methods together with their interactions. To use the properties and methods of a class, an object (an instance of a class) must be created. Creation of an object from a class is generally referred to as instantiation (or creating an instance) of a class.

Encapsulation

Encapsulation is an OOP fundamental that ensures that each part (class) of an application is self-contained and doesn’t interfere with any others, except in a clearly defined manner. This means that encapsulation prevents the values of important properties from being changed except by following the rules laid out by the class.

Encapsulation allows you to prevent unauthorized access to a class by hiding its properties and methods. To implement encapsulation, a property or method can be defined as public, private, or protected.

Public allows access from both inside and outside the class. Protected can only be accessed from within an object’s method. Private is even more restrictive because, like protected, it can only be accessed from within the object’s method, but it is inaccessible from a derived object’s method. That is, private properties or methods cannot be used with inheritance. We will talk about inheritance shortly, so don’t worry about this distinction because it will be explained with examples later in the chapter.

Inheritance

Inheritance is a way to reuse the code of existing objects. That is, an object is able to inherit characteristics from another object. So, once a class has been developed, you don’t have to reinvent the wheel. You can create a new (child) class that inherits either some or all of the characteristics of the parent class without having to rewrite the code already tested in the parent. Inheritance is therefore most useful when the parent’s properties and methods can be reused in different contexts.

Polymorphism

Polymorphism is the ability to create a property or method of an object that has more than one form. While inheritance allows you to pass the characteristics of a parent class to a child class, polymorphism allows you to override existing properties and methods. That is, you can use the same property or method names, but modify them to suit your needs.

OOP vs. Procedural Programming

When properly applied, polymorphism, encapsulation, and inheritance combine to produce a programming environment that supports the development of far more robust and scalable programs than does procedural programming. I have already mentioned that OOP better facilitates modularity, code reusability, information-hiding, and debugging ease. Before we can start OOP, you need to understand the ‘new’ keyword and ‘this’ identifier.

New

The new keyword creates an instance of a class. When an instance (object) is created (instantiated), the new object must be assigned to a variable. The new object is allocated its own copies of the properties and methods defined in the class, and then the constructor of the object is called if one was defined. I will talk about constructors later in the chapter.

This

The this pseudo-variable is built into all objects and points to the current object. It allows access to properties and methods within the object instance. PHP automatically sets ‘this’ to point to the object you are currently working on. Let’s look at an example to help you understand how ‘this’ works.

PHP file ‘use_this.php’ contains class ‘use_this’ (lines 3–15) that encapsulates private property ‘$_array’ (line 5), public method ‘sum()’ (lines 6–10), and public method ‘avg()’ (lines 11–14). The purpose of ‘$_array’ is to hold the array passed into the class. It is convention (and recommended) to use ‘_’ before the variable name when using ‘protected’ or ‘private’ properties. The purpose of method ‘sum()’ is to return the sum of array elements (passed to the class). The purpose of method ‘avg()’ is to return the average of array elements.

 1 <?php

 2 // File use_this.php

 3 class use_this

 4 {

 5 private $_array;

 6 public function sum($array)

 7 {

 8 $this->_array = $array;

 9 return array_sum($array);

10 }

11 public function avg()

12 {

13 return $this->sum($this->_array)/count($this->_array);

14 }

15 }

16 ?>

From top to bottom, method ‘sum()’ assigns the array passed into the class to the ‘$this->_array’ property (line 8) and returns the sum of array elements. Once assigned, ‘$this->_array’ can be used anywhere in the class. Built-in PHP function ‘array_sum()’ (line 9) automatically sums array element values. Method ‘avg()’ returns the average of array elements (line 13) and is calculated by dividing the sum of array elements by the number of array elements. Summing array elements is done by invoking method ‘sum()’ with ‘$this->sum’ and using the array as parameter with ‘$this->_array’. Using ‘this’ with method ‘sum()’ allows you to invoke the method anywhere within the class. Counting array elements is done by using the built-in PHP function ‘count()’ with the array as parameter. The array is referred to with ‘$this->_array’.

Notice that PHP uses the keyword ‘function’ to refer to OOP methods. Also notice how ‘this’ is used to make properties available inside the class and invoke methods inside the class.

Now, I use a script to instantiate the class and display results. I always place a class in its own PHP file to enhance modularity. This way, other applications and classes can use the class. I also recommend naming a class and PHP file similarly. PHP file ‘run_use_this.php’ invokes the class, makes calculations, and displays results.

1 <?php

2 // File run_use_this.php

3 require_once("use_this.php");

4 $list = array(10,20,30);

5 $c = new use_this;

6 echo "Sum is: " . $c->sum($list);

7 echo '<br />';

8 echo "Average is: " . $c->avg();

9 ?>

The ‘//’ symbol is a comment that identifies the file name (line 2). As a gentle reminder, I always include the name of the file at the top of each PHP script for clarification. To use the class, include it in the calling script with ‘require_once()’ (line 3). Variable ‘$list’ (line 4) is assigned an array with three elements. Next, variable ‘$c’ (line 5) is assigned a new instance of class ‘use_this’ with the ‘new’ keyword. To invoke a method outside a class, use the name of the object instance (in this case ‘$c’) followed by an arrow and method name. So, the sum of array elements is displayed with ‘$c->sum($list)’ (line 6) and the average of array elements with ‘$c->avg()’ (line 8). Notice that ‘echo’ (lines 6–8) is used to display output to the screen. Also notice the use of double quotes for displaying character strings and a single dot ‘.’ for concatenation of strings.

Both ‘sum()’ and ‘avg()’ methods are accessible because they are defined as ‘public’ in class ‘use_this’. Typically, methods are defined as ‘public’ to make them available outside a class. The output from ‘run_use_this.php’ is shown in Figure 2.1.

Figure 2.1

Figure 2.1 Output from ‘use_this’ Class

The next bit of code should help you better understand public, protected, and private visibility. It is not recommended to use ‘echo’ inside a class, but we do it here to help you visualize the concept at hand.

PHP file ‘display.php’ contains class ‘display’ (lines 3–14), which defines ‘public’, ‘protected’, and ‘private’ properties, and assigns values to each (lines 5–7). Method ‘displayVals()’ (lines 8–13) displays each property to the screen.

 1 <?php

 2 //File display.php

 3 class display

 4 {

 5 public $dog = 'Spaniel';

 6 protected $_cat = 'Persian';

 7 private $_bird = 'Parrot';

 8 public function displayVals()

 9 {

10 echo $this->dog;

11 echo $this->_cat;

12 echo $this->_bird;

13 }

14 }

15 ?>

PHP file ‘call_display.php’ creates a new instance of class ‘display’ (line 4) and displays values assigned to the class properties (lines 5–7). Calling script ‘call_display.php’ produces an error because both ‘protected’ and ‘private’ properties are not directly accessible outside the class (Figure 2.2).

1 <?php

2 //File call_display.php

3 require_once 'display.php';

4 $see = new display();

5 echo $see->dog; // Works

6 echo $see->_cat; // Fatal Error

7 echo $see->_bird; // Fatal Error

8 ?>

Figure 2.2

Figure 2.2 Error Displayed Trying to Access Protected or Private Property

A fatal error occurs whenever you try to access a ‘protected’ or ‘private’ class property from the calling environment. To fix the error, modify file ‘call_display.php’ by calling ‘public’ method ‘displayVals()’ (line 5) directly (which works because the method is public). Figure 2.3 shows the desired results, which means that the error was fixed.

1 <?php

2 //File call_display.php

3 require_once 'display.php';

4 $see = new display();

5 echo $see->displayVals();

6 ?>

Figure 2.3

Figure 2.3 Output from ‘display’ Class

Inheritance and Polymorphism Example

The next example demonstrates inheritance and polymorphism. Modify the ‘display.php’ file to include a new class ‘poly’. The new class inherits the characteristics of the ‘display’ class by using the ‘extends’ keyword.

 1 <?php

 2 //File display.php

 3 class display

 4 {

 5 public $dog = 'Spaniel';

 6 protected $_cat = 'Persian';

 7 private $_bird = 'Parrot';

 8 public function displayVals()

 9 {

10 echo $this->dog;

11 echo $this->_cat;

12 echo $this->_bird;

13 }

14 }

15 class poly extends display

16 {

17 public $dog = 'Terrier';

18 public function displayVals()

19 {

20 $display = parent::displayVals();

21 echo $display;

22 }

23 }

24 ?>

Class ‘poly’ (lines 15–23) extends the ‘display’ class, thereby inheriting all its ‘public’ and ‘protected’ properties and methods. Keep in mind that ‘private’ properties and methods cannot be inherited from the parent class. Also, notice the use of the scope resolution operator ‘::’ preceded by keyword ‘parent’ in the ‘poly’ class (line 20), which allows ‘poly’ to access the ‘displayVals()’ method from class ‘display’. Polymorphism is at play when overriding the value of ‘$dog’ (line 17) and modifying the ‘displayVal()’ method in ‘poly’ (lines 18–22). The modified ‘call_display.php’ script creates a new instance of both ‘display’ (line 4) and ‘poly’ (line 7) and displays the results (Figure 2.4).

1 <?php

2 //File call_display.php

3 require_once 'display.php';

4 $see = new display();

5 echo $see->displayVals();

6 echo '<br />';

7 $extend = new poly();

8 echo $extend->displayVals();

9 ?>

Figure 2.4

Figure 2.4 Output from ‘display’ and ‘poly’ Classes

Setters and Getters

Setters are methods that set the value of a property, while getters are methods that get the value of a property (return the value to the calling environment). PHP file ‘get_set.php’ illustrates both method types.

 1 <?php

 2 //File get_set.php

 3 class get_set

 4 {

 5 public $testArray = array();

 6 public $dog;

 7 protected $_cat;

 8 private $_bird;

 9 public function setVals()

10 {

11 $this->dog = 'Pomeranian';

12 $this->_cat = 'Siamese';

13 $this->_bird = 'Cockatoo';

14 $this->setArray();

15 }

16 public function setArray()

17 {

18 $this->testArray[0] = $this->dog;

19 $this->testArray[1] = $this->_cat;

20 $this->testArray[2] = $this->_bird;

21 }

22 public function getVals()

23 {

24 return $this->testArray;

25 }

26 }

27 ?>

PHP file ‘get_set.php’ contains the ‘get_set’ class (lines 3–26) with two set methods and one get method. The ‘setVals()’ method (lines 9–15) sets ‘public’ property ‘$dog’ (line 11), ‘protected’ property ‘$_cat’ (line 12), and ‘private’ property ‘$_bird’ (line 13). The method ends by invoking the ‘setArray()’ method (line 14). Remember that the characteristics of ‘$_bird’ cannot be inherited because it is defined as ‘private’. The ‘setArray()’ method (lines 16–21) sets the first three elements of array ‘$testArray’ to the values of the three properties respectively (lines 18–20). The ‘getVals()’ method (lines 22–25) returns (gets) the array back to the calling environment.

PHP file ‘call_get_set.php’ creates a new instance of ‘get_set’ (line 4) and invokes the ‘setVals()’ method (line 5). Once invoked, the last line of the ‘setVals()’ method invokes the ‘setArray()’ method (see line 14 in ‘get_set’). Next, variable ‘$see’ (line 6) is assigned the populated array. Finally, the ‘foreach’ loop (lines 7 and 8) iterates through the array elements and displays values one by one (Figure 2.5).

1 <?php

2 //File call_get_set.php

3 require_once 'get_set.php';

4 $animal = new get_set();

5 $animal->setVals();

6 $see = $animal->getVals();

7 foreach($see as $display)

8 { echo $display . '<br />'; }

9 ?>

Figure 2.5

Figure 2.5 Output from ‘get_set’ Class

Constructor Method

When you create a new instance of a class (object), PHP automatically looks for the class constructor first. A constructor builds the object, sets default values, and assigns values (passed to the class) to properties when an object is initiated. A constructor can also include calls to class methods.

A constructor is designated in a PHP class with keyword ‘construct’ preceded by two consecutive underscores. PHP file ‘bear.php’ contains class ‘bear’, which includes a constructor. PHP file ‘call_bear.php’ instantiates class ‘bear’ and displays the results. When a new instance of ‘bear’ is created, the constructor in class ‘bear’ is automatically run.

 1 <?php

 2 // File bear.php

 3 class bear

 4 {

 5 public $bearArray = array();

 6 public function __construct($tag,$weight,$color)

 7 {

 8 $this->bearArray['tag'] = $tag;

 9 $this->bearArray['weight'] = $weight;

10 $this->bearArray['color'] = $color;

11 }

12 public function getVals()

13 { return $this->bearArray; }

14 }

15 ?>

Class ‘bear’ constructor (lines 6–11) sets ‘$bearArray’ elements with values passed into the class as parameters (lines 8–10). In this case, the constructor obviates the need for a setter. That is, a setter is not needed. The ‘getVals()’ method (lines 12 and 13) returns (gets) the populated array to the calling environment.

1 <?php

2 // File call_bear.php

3 require_once 'bear.php';

4 $baby = new bear('Baby Bear',100,'brown');

5 $see_it = $baby->getVals();

6 echo 'Tag is ' . $see_it['tag'];

7 echo '<br />Weight is ' . $see_it['weight'];

8 echo '<br />Color is ' . $see_it['color'];

9 ?>

PHP file ‘call_bear.php’ creates a new instance of ‘bear’ (line 4), assigns the populated array to variable ‘$see_it’ (line 5), and displays the results (lines 6–8). Figure 2.6 shows the results.

Figure 2.6

Figure 2.6 Output from ‘bear’ Class

The next example creates a new class ‘polar_bear’ in its own file that uses inheritance to access class ‘bear’ properties and methods. PHP file ‘polarbear.php’ contains class ‘polar_bear’ that extends class ‘bear’. Class ‘polar_bear’ thereby inherits all characteristics of class ‘bear’ with the exception of private elements.

 1 <?php

 2 // File polar_bear.php

 3 class polar_bear extends bear

 4 {

 5 protected $_cold;

 6 public function __construct($tag,$weight,$color)

 7 { parent::__construct($tag,$weight,$color); }

 8 public function ice()

 9 {

10 $this->_cold = 'chilly';

11 return $this->_cold;

12 }

13 }

14 ?>

Keyword ‘parent’ followed by the scope resolution operator (line 7) is used to invoke the constructor from the parent class ‘bear’. The scope resolution operator is represented by the ‘::’ symbol (two consecutive colon symbols). Public method ‘ice()’ (lines 8–12) is a method in ‘polar_bear’ that is not in ‘bear’.

PHP file ‘call_polar_bear.php’ creates a new instance of ‘polar_bear’ (line 5), assigns values to variable ‘$see_it’ (line 6) using the ‘getVals()’ method inherited from ‘bear’, and displays results (lines 7–9). It also invokes its own method ‘ice()’, assigns results to ‘$weather’, and displays results (lines 10 and 11). Figure 2.7 shows what is displayed. Notice that you must include both the original file ‘bear.php’ (since it holds the ‘bear’ class) and file ‘polar_bear.php’ for everything to work properly.

 1 <?php

 2 // File call_polar_bear.php

 3 require_once 'bear.php';

 4 require_once 'polar_bear.php';

 5 $polar = new polar_bear('adult',600,'white');

 6 $see_it = $polar->getVals();

 7 echo 'Tag is ' . $see_it['tag'];

 8 echo '<br />Weight is ' . $see_it['weight'];

 9 echo '<br />Color is ' . $see_it['color'];

10 $weather = $polar->ice();

11 echo '<br />Weather is ' . $weather;

12 ?>

Figure 2.7

Figure 2.7 Output from ‘polar_bear’ Class

Abstract Class

An abstract class defines the basic structure of a class, but cannot be instantiated on its own. It must be ‘extended’ by another class to work. It contains properties and methods, but some methods are incomplete and waiting for some other class to extend them (through inheritance). If a method is defined as ‘abstract’, it cannot be declared private because inheritance must be used. Remember that only ‘public’ or ‘protected’ methods can be extended through inheritance. The advantage is that ‘abstract’ forces all child classes to define the details of a method so that multiple classes can be created to do different things.

PHP file ‘abstract_employee.php’ contains abstract class ‘abstract_employee’ (lines 3–15) with three ‘protected’ properties (lines 5–7), a ‘public’ method ‘setdata()’ (lines 8–13), and an abstract method ‘outputData()’ (line 14). Keyword ‘abstract’ (line 3) preceding keyword ‘class’ defines class ‘abstract_employee’ as abstract.

 1 <?php

 2 // File abstract_employee.php

 3 abstract class abstract_employee

 4 {

 5 protected $_empfirst;

 6 protected $_emplast;

 7 protected $_empage;

 8 public function setdata($empfirst,$emplast,$empage)

 9 {

10 $this->_empfirst = $empfirst;

11 $this->_emplast = $emplast;

12 $this->_empage = $empage;

13 }

14 abstract function outputData();

15 }

16 ?>

PHP file ‘employee.php’ contains class ‘employee’ (lines 3–21), which extends abstract class ‘abstract_employee’ (line 3) so that it can use ‘setdata()’ and ‘outputData()’ methods from ‘abstract_employee’. The constructor invokes the ‘setdata()’ method (line 8) from the abstract class and its own ‘outputData()’ method (line 9). The class also contains the ‘getVals()’ method (lines 17–20). Notice how ‘employee’ provides its own details for its ‘outputData()’ method (lines 11–16). Since ‘outputData()’ is defined as an abstract method in class ‘abstract_employee’, it must be implemented in ‘employee’ (the class that extended the abstract class).

 1 <?php

 2 // File employee.php

 3 class employee extends abstract_employee

 4 {

 5 public $testArray = array();

 6 public function __construct($first,$last,$age)

 7 {

 8 $this->setdata($first,$last,$age);

 9 $this->outputData();

10 }

11 public function outputData()

12 {

13 $this->testArray['first'] = $this->_empfirst;

14 $this->testArray['last'] = $this->_emplast;

15 $this->testArray['age'] = $this->_empage;

16 }

17 public function getVals()

18 {

19 return $this->testArray;

20 }

21 }

22 ?>

PHP file ‘invoke_abstract_employee.php’ creates a new instance of ‘employee’ (line 5), invokes its ‘getVals()’ method, places the results in ‘$see_it’ (line 6), and displays the results (lines 7 and 8). Both ‘abtract_employee.php’ and ‘employee.php’ files are included (lines 3 and 4). Figure 2.8 shows the results.

1 <?php

2 // File invoke_abstract_employee.php

3 require_once 'abstract_employee.php';

4 require_once 'employee.php';

5 $val = new employee('Phil','Collins','50');

6 $see_it = $val->getVals();

7 echo $see_it['first'] . ' ' . $see_it['last'];

8 echo ' ' . $see_it['age'];

9 ?>

Figure 2.8

Figure 2.8 Output from ‘employee’ Class (‘abstract’ Class)

Interface

An interface is a list of methods that must be implemented. All methods must be ‘public’. However, an interface has no properties and cannot define how methods are to be implemented. An advantage is that an interface ensures that all classes that implement it have a common set of functionality.

To illustrate how an interface is implemented, I use the same abstract class ‘abstract_employee’ in PHP file ‘abstract_employee.php’, an interface in PHP file ‘status.php’, a modified ‘employee’ class in PHP file ‘employee.php’, and an invocation file ‘invoke_status.php’.

Keyword ‘interface’ in ‘interface_status.php’ makes ‘status’ an interface (line 3). Interface ‘status’ includes public method ‘getStatus()’ (line 4) with no details.

1 <?php

2 // File interface_status.php

3 interface status

4 { public function getStatus(); }

5 ?>

Keyword ‘implements’ in ‘employee.php’ is required to utilize an interface. The ‘employee’ class (lines 3–26) inherits characteristics of abstract class ‘abstract_employee’ with keyword ‘extends’ and utilizes interface ‘status’ with keyword ‘implements’ (line 3). The constructor (lines 6–10) invokes methods ‘setdata()’ and ‘outputData()’ from abstract class ‘abstract_employee’. Method ‘outputData()’ (lines 11–16) contains details not provided in abstract class ‘abstract_employee’. Method ‘getVals()’ (lines 17 and 18) returns (gets) populated array to the calling environment. Method ‘getStatus()’ (lines 19–25) includes the details for interface ‘status’. Finally, another class ‘basic’ (lines 27–31) is included in this file and contains different details for interface ‘status’. Remember that interface ‘status’ only includes method ‘getStatus()’ with no details.

 1 <?php

 2 // File employee.php

 3 class employee extends abstract_employee implements status

 4 {

 5 public $testArray = array();

 6 public function __construct($first,$last,$age)

 7 {

 8 $this->setdata($first,$last,$age);

 9 $this->outputData();

10 }

11 public function outputData()

12 {

13 $this->testArray['first'] = $this->_empfirst;

14 $this->testArray['last'] = $this->_emplast;

15 $this->testArray['age'] = $this->_empage;

16 }

17 public function getVals()

18 { return $this->testArray; }

19 public function getStatus()

20 {

21 if($this->_empage <= '39')

22 { return ' is a young person'; }

23 else

24 { return ' is an old person'; }

25 }

26 }

27 class basic implements status

28 {

29 public function getStatus()

30 { return ', but this is fine!'; }

31 }

32 ?>

PHP file ‘invoke_interface_status.php’ includes ‘abstract_employee.php’, ‘interface_status.php’, and ‘employee.php’ (lines 3–5) to enable access to abstract class ‘abstract_employee’, interface ‘status’, and class ‘employee’. An instance of ‘employee’ is created (line 6), which inherits abstract class ‘abstract_employee’ and implements interface ‘status’. An array is set and returned to ‘$see_it’ with method ‘getVals()’ (line 7). Status is returned to ‘$status’ with method ‘getStatus()’ (line 8). An instance of ‘basic’ is created (line 9), which implements interface ‘status’. Status is returned to ‘$stuff’ with method ‘getStatus()’ (line 10) and results are displayed (lines 11 and 12). Figure 2.9 displays the results.

 1 <?php

 2 // File invoke_status.php

 3 require_once 'abstract_employee.php';

 4 require_once 'interface_status.php';

 5 require_once 'employee.php';

 6 $val = new employee('Jesse','James','39');

 7 $see_it = $val->getVals();

 8 $status = $val->getStatus();

 9 $more = new basic();

10 $stuff = $more->getStatus();

11 echo $see_it['first'] . ' ' . $see_it['last'];

12 echo ' ' . $see_it['age'] . ' ' . $status . $stuff;

13 ?>

Figure 2.9

Figure 2.9 Output from ‘employee’ Class (‘abstract’ Class and ‘status’ Interface)

I suggest spending extra time with the abstract class and interface examples because they tend to be two of the harder concepts to digest in OOP.

Aggregation

Aggregation is a technique that allows one object to act as a container for one or more other objects. Aggregation can be thought of as a relationship between two classes that is best described as a ‘has-a’ and ‘whole–part’ relationship. The container class is the ‘has-a’ part, while the contained class is the ‘whole–part’ of the relationship.

Aggregation can be used as an alternative to inheritance. An advantage of aggregation over inheritance is that it is easier to create cleanly separated classes that are responsible for one task and nothing else. With inheritance, classes are more dependent on one another, given the natural ‘parent–child’ relationship that is always created. With aggregation, the container class does not pass on its characteristics to the contained class. A disadvantage of aggregation is that you must add large numbers of methods to the interface of the contained class or otherwise expose its instance to the word (which adds complexity to coding). This is because, unlike inheritance, the contained class cannot use properties or methods from the container class. Disadvantages of inheritance include possible bloated class trees that are difficult to change and maintain over time and tight coupling between parent and child, which increases dependencies.

To illustrate aggregation, I first provide a simple inheritance example and then change it to an aggregation example by modifying the files. The example uses three PHP files – ‘fruit.php’, ‘apple.php’, and ‘invoke_apple.php’.

 1 <?php

 2 // File fruit.php

 3 class fruit

 4 {

 5 public function peel()

 6 {

 7 return "Peeling is appealing.";

 8 }

 9 }

10 ?>

The ‘fruit.php’ file contains class ‘fruit’ (lines 3–9). Class ‘fruit’ has one method, ‘peel()’ (lines 5–8), which returns a string to the calling environment.

1 <?php

2 // File apple.php

3 class apple extends fruit

4 { }

5 ?>

The ‘apple.php’ file contains class ‘apple’ (lines 3 and 4). Class ‘apple’ extends (inherits) class ‘fruit’. The class contains nothing else.

1 <?php

2 // File invoke_apple.php

3 require_once 'fruit.php';

4 require_once 'apple.php';

5 $apple = new apple();

6 $see = $apple->peel();

7 echo $see;

8 ?>

The ‘invoke_apple.php’ file includes the ‘fruit’ and ‘apple’ classes (lines 3 and 4), creates a new instance of ‘apple’ (line 5), invokes the ‘peel()’ method (line 6) inherited from the ‘fruit’ class, and displays results (line 7). Figure 2.10 shows what is displayed in a browser when the URL pointing to ‘invoke_apple.php’ is loaded.

Figure 2.10

Figure 2.10 Output from ‘apple’ Class (‘fruit’ Class Inheritance)

Now, let’s turn our attention to aggregation. The example uses the same PHP files, but slightly modifies them.

 1 <?php

 2 // File fruit.php

 3 class fruit

 4 {

 5 public $stuff;

 6 public function peel()

 7 {

 8 $this->stuff = 'Yahoo';

 9 return "Peeling is appealing.";

10 }

11 }

12 ?>

I change class ‘fruit’ by adding property ‘$stuff’ (line 5) and a setter for the property (line 8).

 1 <?php

 2 // File apple.php

 3 class apple

 4 {

 5 private $_fruit;

 6 public function __construct()

 7 {

 8 $this->_fruit = new fruit();

 9 }

10 public function apple_peel()

11 {

12 return $this->_fruit->peel() . " " . $this->_fruit->stuff;

13 }

14 }

15 ?>

PHP file ‘apple.php’ contains a modified class ‘apple’ (lines 3–14). Changes include adding property ‘$_fruit’ (line 5), a constructor (lines 6–9), and method ‘apple_peel()’ (lines 10–13).

The constructor assigns a new instance of ‘fruit’ to ‘$this->_fruit’ (line 8) . The ‘apple_peel()’ method invokes the ‘peel()’ method and ‘$stuff’ property from class ‘fruit’ (line 12), and returns the result to the calling environment.

1 <?php

2 // File invoke_apple.php

3 require_once 'fruit.php';

4 require_once 'apple.php';

5 $apple = new apple();

6 $see = $apple->apple_peel();

7 echo $see;

8 ?>

File ‘invoke_apple.php’ creates a new instance of ‘apple’ (line 5), invokes the ‘apple_peel()’ method (line 6), and displays results (line 7). Figure 2.11 shows the results.

Figure 2.11

Figure 2.11 Output from ‘apple’ Class (‘fruit’ Class Aggregation)

In this example, aggregation occurs when class ‘apple’ creates a new instance of class ‘fruit’. All ‘public’ methods and properties of ‘fruit’ are accessible to class ‘apple’. However, ‘protected’ and ‘private’ methods and properties are not available.

Aggregation cleanly separates the two classes, but requires more code and complexity to obtain the same results as inheritance. It is difficult to recommend when to use inheritance or aggregation because it depends on what you are trying to accomplish.

So far in the chapter, I have presented fundamental OOP concepts and reinforced them with coding examples. So, you should possess a basic skill set and understanding of OOP. I now move forward with supplementary OOP concepts, including magic methods, type hinting, constants, static properties and methods, exception handling, and debugging.

Magic Methods

Magic methods are automatically invoked in specific circumstances. The magic methods I cover include constructors, ‘toString’, and destructors. Since I have already covered constructors, no examples are provided in this section.

PHP magic methods begin with a double underscore. For instance, ‘__construct()’ runs automatically when an object is instantiated with the ‘new’ keyword. Another useful magic method is ‘__toString()’, which allows you to specify what to display and also runs automatically upon instantiation of a new object.

The next example illustrates how to use the ‘__toString()’ method and uses two PHP files – ‘tostring.php’ and ‘call_tostring.php’.

 1 <?php

 2 // File tostring.php

 3 class person

 4 {

 5 private $_desc;

 6 public function __construct($first_name,$age)

 7 {

 8 $this->first_name = $first_name;

 9 $this->age = $age;

10 }

11 public function getFirstName()

12 {

13 return $this->first_name;

14 }

15 public function getAge()

16 {

17 return $this->age;

18 }

19 public function __toString()

20 {

21 $this->_desc = $this->getFirstName() . ' (age ' .

22 $this->_desc .= $this->getAge() . ')';

23 return $this->_desc;

24 }

25 }

26 ?>

PHP file ‘tostring.php’ contains class ‘person’ (lines 3–25), a constructor (lines 6–10), method ‘getFirstName()’ (lines 11–14), method ‘getAge()’ (lines 15–18), and a ‘toString()’ magic method (lines 19–24). The constructor accepts name and age (line 6) and sets them to properties (lines 8 and 9). When ‘person’ is instantiated, ‘tostring()’ is automatically invoked. When invoked, ‘tostring()’ calls methods ‘getFirstName()’ and ‘getAge()’, builds a string, places the string in ‘$this->_desc’ (lines 21 and 22), and returns the result (line 23).

The ‘toString()’ magic method returns the full description of a person as a string (lines 21–23). To avoid an error, be sure that whatever the ‘toString()’ method returns is a string. I assign strings to ‘private’ property ‘$_desc’ (lines 21 and 22), so no errors occur.

1 <?php

2 // File call_tostring.php

3 require_once 'tostring.php';

4 $person = new person('Dave','52');

5 echo $person;

6 ?>

PHP file ‘call_tostring.php’ includes the ‘tostring.php’ file (line 3), creates a new instance of ‘person’ (line 4), and displays results (line 5). Figure 2.12 shows the results. The constructor and ‘toString()’ run automatically upon instantiation of ‘person’, since they are magic methods. Also notice that object ‘$person’ is displayed directly. This only works because the class contains a ‘toString()’ method. If you try to display the object of a class directly without a ‘toString()’ method, an error will occur. So, be careful!

Figure 2.12

Figure 2.12 Output from ‘person’ Class with ‘toString’ Magic Method

Since ‘toString()’ automatically builds and returns the final string, less code is needed, which is an advantage of using magic methods. You can also use ‘toString()’ to help debug since it automatically displays values of your choice.

Two caveats are in order at this point. First, be sure to precede magic methods with two consecutive underscores. Second, be sure that the ‘toString()’ method returns a character string. If it returns anything else, an error will occur.

I recommend explicitly converting any ‘toString()’ return values that you are unsure about. Two options are available to accomplish conversion – type casting or the ‘strval()’ function. Type casting variable ‘$varname’ to a string is accomplished by placing ‘(string)’ before the variable and assigning it to another variable.

$var = (string)$varname;

Using the ‘strval()’ function is accomplished by using the variable as a parameter to the function and assigning it to another variable.

$var = strval($varname);

The next example illustrates an improper way to use ‘toString()’. The example uses PHP files ‘avg.php’ and ‘call_avg.php’.

 1 <?php

 2 // File avg.php

 3 class avg

 4 {

 5 private $_arr;

 6 private $_avgval;

 7 public function __construct($arr)

 8 {

 9 $this->_arr = $arr;

10 $this->calc_avg();

11 }

12 public function calc_avg()

13 {

14 $this->_avgval = array_sum($this->_arr)/count($this->_arr);

15 return $this->_avgval;

16 }

17 }

18 ?>

PHP file ‘avg.php’ contains class ‘avg’ (lines 3–17), which returns the average of an array. The constructor (lines 7–11) sets property ‘$_arr’ and invokes the ‘calc_avg()’ method (lines 12–16). The ‘calc_avg()’ method uses built-in functions ‘array_sum()’ and ‘count()’ (line 14) to calculate the average, and returns the result to the calling environment (line 15).

1 <?php

2 // File call_avg.php

3 require_once 'avg.php';

4 $arr = array(10,20,30,40,50);

5 $obj = new avg($arr);

6 echo "Average is: " . $obj;

7 ?>

PHP file ‘call_avg.php’ instantiates class ‘avg’ (line 5) and attempts (but fails) to display results (Figure 2.13).

Figure 2.13

Figure 2.13 Error Displayed because of Improper Usage of ‘toString’ Method

The error occurs because the PHP engine expects ‘toString()’ to set a string value for the object. One solution is to remove the call to the ‘calc_avg()’ method from the constructor, add an external call to the method, and display results (Figure 2.14). This way, the PHP engine doesn’t look for ‘toString()’ because no attempt was made to display the object as a string.

 1 <?php

 2 // File avg.php

 3 class avg

 4 {

 5 private $_arr;

 6 private $_avgval;

 7 public function __construct($arr)

 8 {

 9 $this->_arr = $arr;

10 }

11 public function calc_avg()

12 {

13 $this->_avgval = array_sum($this->_arr)/count($this->_arr);

14 return $this->_avgval;

15 }

16 }

17 ?>

The setter (line 9) is all that remains in the constructor.

1 <?php

2 // File call_avg.php

3 require_once 'avg.php';

4 $arr = array(10,20,30,40,50);

5 $obj = new avg($arr);

6 $val = $obj->calc_avg();

7 echo "Average is: " . $val;

8 ?>

Notice that I added an explicit call to ‘calc_avg()’ (line 6).

Figure 2.14

Figure 2.14 Output from ‘avg’ Class with ‘toString’ Method Removed

Another solution is to add ‘__toString()’ to class ‘avg’ and modify it accordingly. Be sure to change PHP file ‘call_avg.php’ back to its original form. Both modified files are shown next for your convenience. Notice that the ‘return’ statement was removed from method ‘calc_avg()’ because it is not needed. Also notice that function ‘strval()’ (line 18) was added to magic method ‘toString()’ to ensure proper conversion. Figure 2.15 shows the results.

 1 <?php

 2 // File avg.php

 3 class avg

 4 {

 5 private $_arr;

 6 private $_avgval;

 7 public function __construct($arr)

 8 {

 9 $this->_arr = $arr;

10 $this->calc_avg();

11 }

12 public function calc_avg()

13 {

14 $this->_avgval = array_sum($this->_arr)/count($this->_arr);

15 }

16 public function __toString()

17 {

18 $this->_avgval = strval($this->_avgval);

19 return $this->_avgval;

20 }

21 }

22 ?>

1 <?php

2 // File call_avg.php

3 require_once 'avg.php';

4 $arr = array(10,20,30,40,50);

5 $obj = new avg($arr);

6 echo "Average is: " . $obj;

7 ?>

Figure 2.15

Figure 2.15 Output from ‘avg’ Class with ‘toString’ Method

PHP automatically handles garbage collection, which is removal of variables and objects that are no longer needed once the PHP script has finished processing. However, you can manually delete a resource using magic method ‘__destruct()’. Like other magic methods, PHP automatically runs ‘__destruct()’. But unlike others, ‘__destruct()’ is automatically run immediately before the PHP engine removes a defined object from memory. After the destructor is run, the object is released from memory. A destructor cannot take arguments.

An example illustrates how a destructor works. The example uses PHP files ‘destruct.php’ and ‘call_destruct.php’.

 1 <?php

 2 // File destruct.php

 3 class destruct

 4 {

 5 public function __construct()

 6 {

 7 print get_class($this) . ' is defined.' . '<br />';

 8 }

 9 public function __destruct()

10 {

11 print 'Destroying ' . get_class($this);

12 }

13 }

14 ?>

Class ‘destruct’ (lines 3–13) contains a constructor (lines 5–8) and a destructor (lines 9–12). Function ‘get_class()’ (lines 7 and 11) is built-in and returns the class name of the current instance (because the parameter provided to the function is ‘$this’).

1 <?php

2 // File call_destruct.php

3 require_once 'destruct.php';

4 $obj = new destruct();

5 ?>

PHP file ‘call_destruct.php’ invokes class ‘destruct’. Figure 2.16 shows the results.

Figure 2.16

Figure 2.16 Output from ‘destruct’ Class with ‘destruct’ Magic Method

Type Hinting

PHP type hinting allows you to explicitly type cast a value as objects of a class or an array. Type hinting automatically generates an error message if the data type of the actual parameter does not match the data type of the formal parameter. An actual parameter is the actual value that is passed into a method by the calling program (calling environment). A formal parameter is the identifier used in a method to stand for the value that is passed into the method by the calling program (calling environment). While an actual parameter is the value itself, a formal parameter acts like a placeholder. When a method is called, the formal parameter is temporarily ‘bound’ to the actual parameter.

With type hinting, methods can force parameters to be objects or arrays. This is accomplished by preceding the method’s parameter with the type of data. For an object type hint, use the name of the class. For an array type hint, use the keyword ‘array’.

The next set of examples illustrates how type hinting is implemented, using PHP files ‘type_hint.php’ and ‘call_type_hint.php’. PHP file ‘type_hint.php’ contains two classes – ‘mine’ and ‘yours’. Class ‘mine’ (lines 3–13) contains two methods. The first method ‘test()’ (lines 5–8) includes a type hint for object ‘yours’ that directly precedes parameter ‘$yours’ (line 5). The second method ‘count_array()’ (lines 9–12) includes a type hint for an array that directly precedes parameter ‘$input_array’ (line 9). Class ‘yours’ contains a single public property (lines 14–17).

 1 <?php

 2 // File type_hint.php

 3 class mine

 4 {

 5 public function test(yours $yours)

 6 {

 7 return $yours->var;

 8 }

 9 public function count_array(array $input_array)

10 {

11 return count($input_array);

12 }

13 }

14 class yours

15 {

16 public $var = 'Hello World';

17 }

18 ?>

PHP file ‘call_type_hint.php’ creates new object instances of ‘mine’ and ‘yours’ (lines 4 and 5). It then invokes method ‘test()’ from object ‘mine’ and passes parameter ‘$yours’ (line 6). Results are displayed (line 7). Finally, method ‘count_array()’ from object ‘mine’ is invoked (line 8) and results are displayed (line 9). Figure 2.17 shows the results.

 1 <?php

 2 // File call_type_hint.php

 3 require_once 'type_hint.php';

 4 $mine = new mine;

 5 $yours = new yours;

 6 $see = $mine->test($yours);

 7 echo $see . '<br />';

 8 $see_count = $mine->count_array(array('a', 'b', 'c'));

 9 echo 'Array has ' . $see_count . ' elements.';

10 ?>

Figure 2.17

Figure 2.17 Output from ‘mine’ and ‘yours’ Classes Using Type Hinting

To review, method ‘test()’ in class ‘mine’ ensures that parameter ‘$yours’ is of object type ‘yours’ with type hint ‘yours’ (line 5, ‘type_hint.php’). Method ‘count_array()’ ensures that parameter ‘$input_array’ is of array type with type hint ‘array’ (line 9, ‘type_hint.php’).

For the next four examples, I use the same PHP file ‘type_hint.php’, but call it with different types of data to illustrate how type hinting works in different contexts. The first example, in file ‘call_error1.php’, passes a character string to the ‘test()’ method.

1 <?php

2 // File call_error1.php

3 require_once 'type_hint.php';

4 $mine = new mine;

5 $yours = new yours;

6 $see = $mine->test('hello');

7 ?>

PHP file ‘call_error1.php’ creates an instance of both classes (lines 4 and 5) and then passes string ‘hello’ as a parameter to method ‘test’ (line 6). An error occurs because method ‘test()’ includes a type hint that restricts the parameter to object type ‘yours’. Since, we passed string ‘hello’ (which is not an object of type ‘yours’) to the ‘test()’ method, PHP automatically returns an error (Figure 2.18).

Figure 2.18

Figure 2.18 Error Displayed Trying to Pass a String Type Hinted for an Object

The second example in PHP file ‘call_error2.php’ passes an object of class ‘mine’ to the ‘test()’ method.

1 <?php

2 // File call_error2.php

3 require_once 'type_hint.php';

4 $mine = new mine;

5 $yours = new yours;

6 $see = $mine->test($mine);

7 ?>

PHP file ‘call_error2.php’ creates an instance of both classes (lines 4 and 5) and then passes an instance of ‘mine’ as a parameter to method ‘test’ (line 6). An error occurs because the ‘test()’ method includes a type hint that restricts the parameter to object type ‘yours’. Since, we passed an instance of ‘mine’ (which is an object of type ‘mine’, not an object of type ‘yours’) to the ‘test()’ method, PHP automatically returns an error (Figure 2.19).

Figure 2.19

Figure 2.19 Error Displayed Trying to Pass ‘mine’ Type Hinted for ‘yours’ Object

The third example in PHP file ‘call_error3.php’ passes ‘null’ to the ‘test()’ method.

1 <?php

2 // File call_error3.php

3 require_once 'type_hint.php';

4 $mine = new mine;

5 $yours = new yours;

6 $see = $mine->test(null);

7 ?>

PHP file ‘call_error3.php’ creates an instance of both classes (lines 4 and 5) and then passes ‘null’ as a parameter to method ‘test’ (line 6). An error occurs because the ‘test()’ method includes a type hint that restricts the parameter to type ‘yours’. Since, we passed ‘null’ to the ‘test’ method, PHP automatically returns an error (Figure 2.20).

Figure 2.20

Figure 2.20 Error Displayed Trying to Pass ‘null’ Type Hinted for ‘yours’ Object

The fourth example in PHP file ‘call_error4.php’ passes a string to the ‘count_array()’ method.

1 <?php

2 // File call_error4.php

3 require_once 'type_hint.php';

4 $mine = new mine;

5 $yours = new yours;

6 $see_array = $mine->count_array('a string');

7 ?>

PHP file ‘call_error4.php’ creates an instance of both classes (lines 4 and 5) and then passes a string as a parameter to method ‘count_array()’ (line 6). An error occurs because the ‘count_array’ method includes a type hint that restricts the parameter to type ‘array’. Since, we passed a string to the ‘count_array()’ method, PHP automatically returns an error (Figure 2.21).

Figure 2.21

Figure 2.21 Error Displayed Trying to Pass String Type Hinted for an Array

The final example uses an ‘array’ type hint for parameter ‘$a’ in a constructor. PHP file ‘avg_hint.php’ contains class ‘avg_hint’ (lines 3–25), which contains a public and private property (lines 5 and 6), a constructor (lines 7–11), and two methods. Public property ‘$arr’ (line 5) is cast as an array type. The constructor accepts one parameter that is protected with an ‘array’ type hint (line 7), which means that only an array type can be passed to the constructor. The method ‘dynamic()’ (lines 12–20) totals all elements of the array passed to the class (lines 14–18) and assigns the average to ‘$this->_avg’ (line 19). Method ‘getAvg()’ (lines 21–24) returns the array average (line 23).

 1 <?php

 2 // File avg_hint.php

 3 class avg_hint

 4 {

 5 public $arr = array();

 6 private $_avg;

 7 public function __construct(array $a)

 8 {

 9 $this->arr = $a;

10 $this->dynamic();

11 }

12 public function dynamic()

13 {

14 $total = 0;

15 foreach ($this->arr as $avg)

16 {

17 $total = $total + $avg;

18 }

19 $this->_avg = $total/count($this->arr);

20 }

21 public function getAvg()

22 {

23 return $this->_avg;

24 }

25 }

26 ?>

PHP file ‘call_avg_hint.php’ creates an array (line 4), a new instance of ‘avg_hint’ (line 5), calls method ‘getAvg()’ (line 6), and displays the results (line 7). Figure 2.22 shows the results.

1 <?php

2 // File call_avg_hint.php

3 require_once 'avg_hint.php';

4 $array = array(10,20,30,20,20);

5 $total = new avg_hint($array);

6 $see_it = $total->getAvg();

7 echo $see_it;

8 ?>

Figure 2.22

Figure 2.22 Output from ‘avg_hint’ Class Type Hinted for an Array

Type hinting is a useful technique for limiting the types of acceptable data passed to a class method. Although limited to objects and arrays, it strengthens the ability to protect websites from what comes in from the outside world.

Constants

Constants are values that never change. Unlike properties, constants do not begin with ‘$’. Constants are normally written in uppercase letters. You do not need to instantiate an object to access a constant, but you do need to instantiate an object if you want to access a method that uses a constant.

To access a constant inside a class, use the ‘self’ keyword with the scope resolution operator followed by the name of the constant. To access a constant externally, use the class name with the scope resolution operator followed by the name of the constant.

I now illustrate constants with an example. The example uses two PHP files – ‘lbs_to_kilos.php’ and ‘call_lbs_to_kilos.php’.

 1 <?php

 2 // File lbs_to_kilos.php

 3 class lbs_to_kilos

 4 {

 5 const POUNDS_TO_KILOGRAMS = 0.45359237;

 6 private $_val;

 7 function displayInfo()

 8 {

 9 $this->_val = self::POUNDS_TO_KILOGRAMS;

10 return $this->_val;

11 }

12 }

13 ?>

PHP file ‘lbs_to_kilos.php’ contains a class ‘lbs_to_kilos’ (lines 3–12) with a constant (line 5), private property (line 6), and method that refers to the constant (lines 7–11). Method ‘displayInfo()’ (lines 7–11) assigns the constant to ‘$this_val’ (line 9), and returns it to the calling environment. Notice that the ‘self’ keyword followed by the scope resolution operator and constant name are required to access the constant inside the class (line 9).

1 <?php

2 // File call_lbs_to_kilos.php

3 require_once 'lbs_to_kilos.php';

4 echo lbs_to_kilos::POUNDS_TO_KILOGRAMS;

5 $val = new lbs_to_kilos();

6 $hold = $val->displayInfo();

7 echo '<br />' . $hold;

8 ?>

PHP file ‘call_lbs_to_kilos.php’ displays the constant without instantiating a new object (line 4), creates a new object so the constant within the method can be accessed externally (line 5), invokes ‘displayInfo()’ method and assigns result to ‘$hold’ (line 6), and displays results (line 7).Figure 2.23 shows what is displayed. Notice that the class name, scope resolution operator, and constant name are needed to access the constant outside the class (line 4).

Figure 2.23

Figure 2.23 Output from Constant and ‘lbs_to_kilos’ Class

To review, object instantiation is not needed to display the constant, but object instantiation is needed to use the method that contains the constant. Also, remember to use the keyword ‘self’ with the scope resolution operator and constant name to access the constant inside the class method, and use the class name with the scope resolution operator and constant name to access the constant outside the class.

Static Properties and Methods

static property is accessible without needing instantiation of a class, but, unlike a constant, cannot be accessed with an instantiated class object. To access a static property, place it in a ‘public’ static method and return its value. An example should help clarify how to use static properties and methods.

The example uses two PHP files – ‘count.php’ and ‘call_count.php’. PHP file ‘count.php’ includes class ‘count’ (lines 3–11) with static property ‘$count’ (line 5) and static method ‘keep_track()’ (lines 6–10), and class ‘see_count’ (lines 12–18) with static method ‘see_result()’ (lines 14–18).

In class ‘count’, static method ‘keep_track()’ uses the ‘self’ keyword with scope resolution operator and name of static property to access static property ‘$count’. So, ‘self::$count++;’ (line 8) increments static property ‘$count’ by one and ‘return self::$count;’ (line 9) gets (returns) the value of ‘$count’ to the calling environment with each call to ‘keep_track()’.

Class ‘see_count’ extends ‘count’ (line 12), thereby inheriting the characteristics of class ‘count’. Static method ‘see_result()’ uses the ‘parent’ keyword with scope resolution operator and name of static property (line 16) to access the value of static property ‘$count’, which is returned. Since static property ‘$count’ cannot be accessed with an instantiated class object, pseudo-variable ‘$this’ is not available.

 1 <?php

 2 // File count.php

 3 class count

 4 {

 5 public static $count = 0;

 6 public static function keep_track()

 7 {

 8 self::$count++;

 9 return self::$count;

10 }

11 }

12 class see_count extends count

13 {

14 public static function see_result()

15 {

16 return parent::$count;

17 }

18 }

19 ?>

PHP file ‘call_count.php’ displays the value of static property ‘$count’ without instantiating a new object with class name, scope resolution operator, and static property name (line 4). To access and display the value of static property ‘$count’ with a method, a new object instance is created (line 5) and public static method ‘keep_track()’ is invoked three times (lines 6–8). A new instance of ‘see_count’ is then created (line 9) and public static method ‘see_result()’ is invoked once (line 10). Figure 2.24 shows the results.

 1 <?php

 2 // call_count.php

 3 require_once 'count.php';

 4 echo count::$count . '<br />';

 5 $obj = new count();

 6 echo $obj->keep_track() . '<br />';

 7 echo $obj->keep_track() . '<br />';

 8 echo $obj->keep_track() . '<br />';

 9 $obj = new see_count();

10 echo $obj->see_result() . '<br />';

11 ?>

Figure 2.24

Figure 2.24 Output from Static Variable, and ‘count’ and ‘see_count’ Classes

Static properties are valuable because they retain previously assigned values. In our example, we were able to build a counter with the help of a static property and a static method.

The next example converts pounds to kilograms and vice versa using static properties and methods. The example uses two files – ‘convert_static.php’ and ‘call_convert_static.php’.

PHP file ‘convert_static.php’ contains the ‘convert_static’ class (lines 3–17). The class contains two static properties (lines 5 and 6), two private properties (lines 7 and 8), and two static methods. Static method ‘convertLbToKg()’ (lines 9–12) converts pounds to kilograms and static method ‘convertKgToLb()’ (lines 13–16) converts kilograms to pounds.

 1 <?php

 2 // File convert_static.php

 3 class convert_static

 4 {

 5 protected static $_lbToKg = 0.45359237;

 6 protected static $_KgTolb = 2.20462262;

 7 private $_pounds;

 8 private $_kilograms;

 9 public static function convertLbToKg($_pounds)

10 {

11 return $_pounds * self::$_lbToKg;

12 }

13 public static function convertKgToLb($_kilograms)

14 {

15 return $_kilograms * self::$_KgTolb;

16 }

17 }

18 ?>

PHP file ‘call_convert_static.php’ uses the static methods from class ‘call_convert’ for conversions. First, a new instance of ‘convert_static’ is created (line 4). Static properties ‘$_lbToKg’ and ‘$_KgTolb’ are accessed indirectly by public static methods ‘convertLbToKg’ (line 5) and ‘convertKgToLb’ (line 7), which return (get) the appropriate values. Figure 2.25 shows the results.

1 <?php

2 // File call_convert_static.php

3 require_once 'convert_static.php';

4 $val = new convert_static();

5 $weight_in_kilo = $val->convertLbToKg(100);

6 echo 'Weight in Kilograms is: ' . $weight_in_kilo;

7 $weight_in_pounds = $val->convertKgToLb(100);

8 echo '<br />Weight in Pounds is: ' . $weight_in_pounds;

9 ?>

Figure 2.25

Figure 2.25 Output from ‘convert_static’ Class

Exception Handling

An exception is when something goes wrong in a block of code. Instead of handling the error when it occurs in the script, you can throw an exception and catch it in a special block. One advantage is that you can keep all error handling in a single place rather than scattering it throughout your script. Another advantage is that you can display what you wish to the screen rather than letting PHP display a generic and typically nasty looking error message. This is a big advantage because anyone seeing the message will only see what you wish them to see.

Within a customized message, you can instruct users what to do next instead of having them see a nasty PHP error message. PHP has a built-in ‘Exception’ class that utilizes a ‘Try’ block, a ‘Throw’, and a ‘Catch’ block. The ‘Try’ block contains code that is being tested for errors. The ‘Throw’ is a mechanism for triggering an exception. Each ‘Throw’ must have at least one ‘Catch’ block. The ‘Catch’ block retrieves the exception and creates an object containing exception information.

If an exception is not triggered, code processing continues as normal. If an exception is triggered, an exception is thrown (triggered). Since the ‘Exception’ class has a built-in ‘toString()’ method, details can be displayed to the calling environment. An example is provided to help understanding.

The example uses two PHP files – ‘checknum.php’ and ‘call_check_num.php’. PHP file ‘checknum.php’ includes class ‘checknum’ (lines 3–14) with ‘private’ property ‘$_num’ (line 5) and ‘public’ method ‘chk()’ (lines 6–13).

Method ‘chk()’ accepts a number as parameter (line 6). If the number is not numeric (line 9), an exception is triggered (line 10). PHP built-in function ‘is_numeric()’ checks for numeric values. Placing ‘!’ before the function does the opposite. That is, it checks for nonnumeric values. Although a custom message is included (line 10), a nasty message is displayed because the method does not include a ‘try–catch’ block.

 1 <?php

 2 // File checknum.php

 3 class checknum

 4 {

 5 private $_num;

 6 public function chk($number)

 7 {

 8 $this->_num = $number;

 9 if(!is_numeric($this->_num))

10 { throw new Exception("Value '$this->_num' is nonnumeric!"); }

11 else

12 { return true; }

13 }

14 }

15 ?>

PHP file ‘call_checknum.php’ creates an instance of ‘checknum’ (line 5), invokes ‘chk()’ (line 6) with a nonnumeric value from line 4, and displays a nasty result (line 7) (because no ‘try–catch’ block is present). Figure 2.26 shows the results.

1 <?php

2 // File call_checknum.php

3 require_once 'checknum.php';

4 $var = 'chicken';

5 $obj = new checknum();

6 $result = $obj->chk($var);

7 echo $result;

8 ?>

Figure 2.26

Figure 2.26 Nasty Error Displayed from Uncaught Exception

To rectify the problem, modify class ‘checknum’ by adding a ‘try–catch’ block.

 1 <?php

 2 // File checknum.php

 3 class checknum

 4 {

 5 private $_num;

 6 public function chk($number)

 7 {

 8 $this->_num = $number;

 9 try

10 {

11 if(!is_numeric($this->_num))

12 { throw new Exception("Value '$this->_num' is nonnumeric!"); }

13 else

14 { return true; }

15 }

16 catch(Exception $e)

17 { echo $e->getMessage(); }

18 }

19 }

20 ?>

Reload ‘call_checknum.php’ in a browser to see results (Figure 2.27).

Figure 2.27

Figure 2.27 Nice Message Displayed from Trapped Exception

Now, the error message is clean and informative. The ‘catch’ block uses the ‘Exception’ class built into the PHP engine. Two parameters – ‘Exception’ and ‘$e’ – are passed to ‘catch’ (line 16). Parameter ‘Exception’ tells PHP to use the ‘Exception’ class. Parameter ‘$e’ tells PHP to create a new instance of ‘Exception’ and place the object into variable ‘$e’. The message to users is retrieved by invoking method ‘getMessage()’ (line 17) from the ‘Exception’ class and displayed with the ‘echo’ statement (line 17).

The ‘Exception’ class can be extended to create custom error messages. PHP file ‘custom_exception.php’ contains class ‘custom_exception’ (lines 3–12) that extends ‘Exception’. The class includes method ‘errorMessage()’ (lines 5–11) that builds a customized error message. Built-in methods ‘getLine()’ (line 7), ‘getFile()’ (line 8), and ‘getMessage()’ (line 8) are used to build the error message.

 1 <?php

 2 // File custom_exception.php

 3 class custom_exception extends Exception

 4 {

 5 public function errorMessage()

 6 {

 7 $errorMsg = 'Error on line '. $this->getLine().

 8 ' in '.$this->getFile() .': <b>'.$this->getMessage().

 9 '</b> is not a valid E-Mail address';

10 return $errorMsg;

11 }

12 }

13 ?>

PHP file ‘call_custom_exception.php’ validates an email address with a built-in validate function and flag (lines 7 and 8). If the email address is invalid, an exception is triggered (line 10) and the ‘catch’ block (lines 13–16) displays the custom error message. Figure 2.28 shows the results.

 1 <?php

 2 // File call_custom_exception.php

 3 require_once 'custom_exception.php';

 4 $email = "someone@example...com";

 5 try

 6 {

 7 if(filter_var($email,

 8 FILTER_VALIDATE_EMAIL) == FALSE)

 9 {

10 throw new custom_exception ($email);

11 }

12 }

13 catch (custom_exception $e)

14 {

15 echo $e->errorMessage();

16 }

17 ?>

Figure 2.28

Figure 2.28 Nice Message Displayed from Custom Exception

A custom exception class can be used with the built-in ‘Exception’ class. PHP file ‘call_multiple.php’ uses the custom class we created (line 9) to test for a valid email address. If valid, a test is made (line 10) to see if the word ‘example’ is in the valid email.

 1 <?php

 2 // File call_multiple.php

 3 require_once 'custom_exception.php';

 4 $email = "someone@example...com";

 5 try

 6 {

 7 if(filter_var($email,

 8 FILTER_VALIDATE_EMAIL) == FALSE)

 9 { throw new custom_exception($email); }

10 if(strpos($email, "example") == FALSE)

11 { throw new Exception

12 ("$email is not an example e-mail"); }

13 }

14 catch (custom_exception $e)

15 { echo $e->errorMessage(); }

16 catch(Exception $e)

17 { echo $e->getMessage(); }

18 ?>

Since email ‘someone@example...com’ is invalid, ‘custom_exception’ is triggered and the appropriate error message is displayed (Figure 2.29).

Figure 2.29

Figure 2.29 Nice Message Displayed from Custom and Built-In Exceptions

Modify PHP file ‘call_multiple.php’ to use a valid email address – ‘someone@exampe.com’ (line 4). The email is valid, so class ‘custom_exception’ is not triggered. However, the email address does not include the word ‘example’, so built-in class ‘Exception’ is triggered (Figure 2.30).

 1 <?php

 2 // File call_multiple.php

 3 require_once 'custom_exception.php';

 4 $email = "someone@exampe.com";

 5 try

 6 {

 7 if(filter_var($email,

 8 FILTER_VALIDATE_EMAIL) == FALSE)

 9 { throw new custom_exception($email); }

10 if(strpos($email, "example") == FALSE)

11 { throw new Exception

12 ("$email is not an example e-mail"); }

13 }

14 catch (custom_exception $e)

15 { echo $e->errorMessage(); }

16 catch(Exception $e)

17 { echo $e->getMessage(); }

18 ?>

Figure 2.30

Figure 2.30 Nice Message Displayed from Custom and Built-In Exceptions

Debugging

In this section, some simple techniques to aid in debugging are discussed. First, build classes that have a single theme whenever possible. That is, build classes that focus on one idea or task. The classes built in this chapter adhere to the notion of ‘one idea or task’ per OOP class. Single-theme classes mitigate (reduce) potential errors and are easier to debug. Second, use magic method ‘toString()’ to display values of properties. Third, use ‘foreach()’ to display the contents of an array or object. Extensive use of ‘foreach()’ is covered in later chapters. Fourth, use ‘var_dump()’ or ‘print_r’ to display information about a variable, including ‘protected’ and ‘private’ properties of an object. Use ‘print_r()’ to display more human-readable information. Finally, display contents of an array or property by getting values set in a class. An example should help.

The example uses two PHP files – ‘dim.php’ and ‘call_dim.php’. PHP file ‘dim.php’ contains class ‘dim’ (lines 3–16) with a constructor (lines 6–11) that sets array elements (lines 8–10) from three incoming parameters (line 6) and a method ‘getVals()’ (lines 12–15) that gets the array.

 1 <?php

 2 // File dim.php

 3 class dim

 4 {

 5 public $dim = array();

 6 public function __construct($l,$w,$h)

 7 {

 8 $this->dim['length'] = $l;

 9 $this->dim['width'] = $w;

10 $this->dim['height'] = $h;

11 }

12 public function getVals()

13 {

14 return $this->dim;

15 }

16 }

17 ?>

PHP file ‘call_dim.php’ creates a new instance of ‘dim’ with the parameters length, width, and height (line 4). It then invokes ‘getVals()’ (line 5), and displays array contents (lines 7–11). Figure 2.31 shows the results.

 1 <?php

 2 // File call_dim.php

 3 require_once 'dim.php';

 4 $dim = new dim('20','5','12');

 5 $see_it = $dim->getVals();

 6 echo 'Length is ' .

 7 $see_it['length'] . ' inches ';

 8 echo '<br />Width is ' .

 9 $see_it['width'] . ' inches';

10 echo '<br />Height is ' .

11 $see_it['height'] . ' inches';

12 ?>

Figure 2.31

Figure 2.31 Output from ‘dim’ Class that Displays Returned Array

Modify ‘call_dim.php’ to display contents of the array with ‘foreach()’ (lines 6 and 7), ‘var_dump()’ (line 9), and ‘print_r’ (line 11). With ‘foreach()’, display the index and corresponding element. With ‘var_dump()’, all array information is displayed, but can be difficult for an untrained programmer to decipher. With ‘print_r()’, less information is displayed but it is easier to understand. Figure 2.32 shows the results.

 1 <?php

 2 // File call_dim.php

 3 require_once 'dim.php';

 4 $dim = new dim('20','5','12');

 5 $see_it = $dim->getVals();

 6 foreach($see_it as $key=>$value)

 7 { echo "$key  $value<br />"; }

 8 echo "<p>";

 9 var_dump($see_it);

10 echo "<p>";

11 print_r($see_it);

12 ?>

Figure 2.32

Figure 2.32 Output from ‘dim’ Class Using ‘foreach’, ‘var_dump’, and ‘print_r’

Now, modify class ‘dim’ in PHP file ‘dim.php’ by adding a ‘toString()’ magic method (lines 13–22). Be sure to include two consecutive underscores before the ‘toString()’ magic method. Notice how concatenation is used with the ‘.=’ symbol to add to ‘$this->desc’ property (lines 17–20).

 1 <?php

 2 // File dim.php

 3 class dim

 4 {

 5 public $dim = array();

 6 public $desc;

 7 public function __construct($l,$w,$h)

 8 {

 9 $this->dim['length'] = $l;

10 $this->dim['width'] = $w;

11 $this->dim['height'] = $h;

12 }

13 public function __toString()

14 {

15 $this->desc = "Length is " .

16 $this->dim['length'];

17 $this->desc .= "<br />Width is " .

18 $this->dim['width'];

19 $this->desc .= "<br />Height is " .

20 $this->dim['height'];

21 return $this->desc;

22 }

23 }

24 ?>

Modify PHP file ‘call_dim.php’. Notice that the code is simplified because the ‘toString()’ magic method is automatically invoked when the instance is created. All that is needed is to display object instance ‘$dim’ (Figure 2.33).

1 <?php

2 // File call_dim.php

3 require_once 'dim.php';

4 $dim = new dim('20','5','12');

5 echo $dim;

6 ?>

Figure 2.33

Figure 2.33 Output from ‘dim’ Class Using ‘toString’

OOP Concepts Revisited

In this chapter, OOP advantages, fundamentals, and supplements with applicable code examples were introduced to reinforce and deepen knowledge. To further deepen understanding of OOP, a discussion of three important concepts – encapsulation, visibility, and extensibility – ends the chapter.

The idea of encapsulation is to create self-contained classes. As such, encapsulation facilitates modularity, reusability, information-hiding, and debugging. Independent classes promote modularity. Modular classes are easy to access from the outside world and to use in different contexts; this promotes reusability. Self-contained classes allow you to easily hide the details of the class from the outside world, thus promoting information-hiding. Finally, modular classes promote debugging ease because the code is simple and changing the code does not impact other classes.

If you create methods encapsulated in a class that are as mutually exclusive as possible, this further enhances modularity, reusability, information-hiding, and debugging ease. For instance, if you add a new method that is mutually exclusive from the existing methods, existing methods will work as before. So, even if the new method doesn’t work properly, the other methods still work. Therefore, encapsulation not only facilitates modularity, reusability, information-hiding, and debugging ease, it also stabilizes a class by allowing addition or modification of methods without impacting the usability of the class.

Visibility determines whether a property or method can be accessed directly by any part of a script that uses a class or if it remains internal to the class. So, visibility promotes information-hiding. Visibility is determined by the keywords ‘public’, ‘protected’, and ‘private’, which were introduced as part of encapsulation at the beginning of the chapter. Visibility is therefore a term used to describe how to hide information as we attempt to encapsulate class methods and properties from the outside world.

Since methods often serve as the interface to the functionality of a class, they usually need to be ‘public’. Properties, however, should almost always be hidden away as ‘protected’ or ‘private’, to prevent them from being accidently changed. If you ever intend to extend a class, you should use ‘protected’ visibility. Use ‘private’ visibility only if you do not want a method or property to be accessed outside the class. When you need to expose or change the value of a property, the normal way to do so is through a getter (expose) or setter (change) method.

Extensibility refers to the ability to extend a class through inheritance. To use inheritance, notice that we always use the keyword ‘extends’. Extensibility is therefore the ability to implement inheritance principles in OOP.

Summary

The goal of this chapter was to facilitate a fundamental understanding of OOP concepts. I believe this goal was met by introducing fundamental OOP concepts and including coding examples (with explanation) to enrich practical application.