Learn PHP in One Day and Learn It Well

Chapter 9: Object-Oriented Programming

In the next two chapters, we are going to cover another important concept in PHP – the concept of object-oriented programming (OOP).

OOP is a major topic. Hence, a full discussion of it is beyond the scope of this book. In this chapter, we’ll cover the core concepts in OOP. In the next, we’ll talk about inheritance.

Ready? Let’s get started.

9.1 What is OOP?

First off, what is OOP?

OOP is an approach to programming where we organize our code by grouping related variables, constants and functions into a class. This class serves as a template from which we can create what is known as objects. Objects can then be used to store data and access functions defined inside the class.

Confused? No worries. The best way to understand OOP is to look at an example. Let’s write our own class now.

9.2 Writing our own class

To write our own class, we use the class keyword, followed by the name of the class.

The name of the class is not case-sensitive and can contain letters, numbers, or underscores. However, it cannot be a PHP reserved word (i.e., a word that has a predefined meaning in PHP, such as echoswitchbreak , etc.) and cannot start with a number.

It is a convention to use pascal case when naming our classes. Pascal case refers to the practice of capitalizing the first letter of each word, including the first word (e.g., ClassName).

To create our class, let’s first create a file in Brackets and save it as Movie.php to our htdocs folder. Next, add the following code to Movie.php.

<?php
class Movie{
    //Add class members here
}

Here, we use the class keyword to declare a class called Movie .

Within the Movie class (inside the pair of braces {} ), we are going to add variables, constants and functions. Variables and functions declared inside a class are known as properties and methods respectively. Collectively, these properties, constants and methods are known as class members.

We’ll add properties to our Movie class first. To do that, add the following code to Movie.php (inside the pair of braces):

private $id;
public $title;
public $rentalPrice;

Here, we declare three properties: $id$title and $rentalPrice . Notice that we did not initialize them in the code above? This is because we’ll be initializing them in a special method known as the constructor later. Also, note that we preceded the property declarations with the words public or private . Don’t worry about these keywords at the moment; we’ll come back to them later.

Next, let’s add a constant to our Movie class. To do that, add the following code to Movie.php (inside the pair of braces):

const DISCOUNT = 10;

Here, we define a constant called DISCOUNT and assign the value 10 to it. Notice that we define a constant differently here (compared to what we learned in Chapter 4.1)? Indeed, to define a constant inside a class, we do not use the define() function. Instead, we use the const keyword as shown above.

Finally, let’s add some methods to our class. As mentioned previously, a method is a function that is defined inside a class. We’ll start with the constructor.

A constructor is a magic method in PHP. Magic methods are methods that have special functionalities in PHP; their names are predefined and always start with two underscores.

The constructor is named __construct() and is the first method to be called whenever we create an object from the class. We typically use this method to initialize the properties in the class.

Add the following code to the Movie class after the constant (but before the closing brace of the Movie class):

public function __construct($pId, $pTitle, $pRentalPrice){
	$this->id = $pId;
 	$this->title = $pTitle;
	$this->rentalPrice = $pRentalPrice;
}

Here, we define a constructor with three parameters: $pId$pTitle and $pRentalPrice .

Inside the constructor, we initialize $id$title and $rentalPrice with the values of $pId$pTitle and $pRentalPrice respectively.

Notice a new keyword $this in the code above? We’ll explain this keyword later when we learn to create objects in the next section. For now, just know that whenever we want to access the properties and methods of a class inside the class, we need to use the $this keyword, followed by the -> operator.

Next, let’s add a regular (i.e., non-magic) method to our Movie class. Add the following method after the __construct() method (but before the closing brace of the Movie class):

public function conversion($country){
	$rate = 1;
	switch($country){
 		case 'UK':
		  $rate = 0.76;
 		  break;
 		case 'Japan':
 		  $rate = 110;
 		  break;
	}

 	return round($rate*$this->rentalPrice, 2);
}

Here, we define a method called conversion() . This method has one parameter – $country – and converts USD to pounds or yen depending on the value of $country .

Within the method, we declare and initialize a variable called $rate and use a switch statement to update its value based on the value of $country .

Next, we multiply $rate with the $rentalPrice property ( $rate*$this->rentalPrice ) and pass the product as an argument to a built-in function called round() . This function accepts two arguments and rounds the first argument off to the precision indicated by the second. In our method, we round the product off to 2 decimal places.

Finally, we use the return keyword to return the result of the round() function.

Within the method, notice that we did not use the $this keyword to access $country and $rate ?

This is because $country is a parameter while $rate is a local variable (i.e., a variable declared inside the method). In other words, they are not class properties. We use the $this keyword only when accessing class properties and methods. For instance, we use the $this keyword to access the $rentalPrice property.

Got it? Once you have added the conversion() method to the Movie class, our class is complete. We are now ready to make use of this class. To do that, we need to create an object from it.

9.3 Creating an Object

To create an object, we use the new keyword. An object is also known as an instance of the class, and the process of creating an object is known as instantiating the class.

Create a new file in Bracket and save it as chap9.php to your htdocs folder. Add the following code to chap9.php:

<?php
	include 'Movie.php';
	$mov1 = new Movie('N0001', 'Lusso', 4.99);

Here, we first use the include statement to include Movie.php (which contains the code for the Movie class).

Next, we use the new keyword to create a Movie object called $mov1 , passing 'N0001''Lusso' and 4.99 as arguments to the __construct() method.

As __construct() is a magic method, we do not call it using its name.

Instead, when we create a new Movie object, PHP looks for the __construct() method and executes it for us automatically.

Remember the $this keyword in our Movie class constructor? $this refers to the current object. When we use the statement

$mov1 = new Movie('N0001', 'Lusso', 4.99);

to create $mov1$this refers to $mov1 . In other words, when PHP executes the constructor, the statement

$this->id = $pId;

in the constructor becomes

$mov1->id = 'N0001';

As a result, the value 'N0001' gets assigned to the $id property of $mov1 . The same applies to the other two assignment statements in the constructor. Hence, the values 'Lusso' and 4.99 get assigned to the $title and $rentalPrice properties of $mov1 respectively.

Next, let’s create a second Movie object called $mov2 using the statement below:

$mov2 = new Movie('P0002', 'Junior', 5.99);

When PHP creates $mov2 and calls the constructor, $this refers to $mov2 . Hence, the statement

$this->id = $pId;

in the constructor becomes

$mov2->id = 'P0002';

The same applies to the other two assignment statements in the constructor. As a result, the values 'P0002''Junior' and 5.99 get assigned to the $id$title and $rentalPrice properties of $mov2 respectively.

Got it? Good! Let’s move on.

9.4 Accessing Class Members

After creating an object, we can use the object name and the -> operator to access its properties and methods.

For instance, to access the properties and methods of $mov1 in chap9.php, we use the code below:

echo $mov1->title.'<BR>';
echo $mov1->conversion('Japan').'<BR>';

Here, we first use the -> operator to access the $title property of $mov1 . Next, we use the -> operator to call the conversion() method, passing 'Japan' as an argument to the method.

Add the code above to chap9.php (after the instantiation statements) and load the page, you’ll get

Lusso
548.9

as the output. Pretty straightforward, right?

Now, suppose we want to access the DISCOUNT constant defined in the Movie class, how do we do that?

To access a class constant, we do not use the -> operator. Instead, we use the :: operator.

This is because class constants are different from class properties; they are allocated once per class, not once for each object. This means that all objects of the same class ( $mov1 and $mov2 in our example) share the same constants. In other words, even if there are 100 Movie objects, there is only one memory location allocated to store the DISCOUNT constant.

To access the DISCOUNT constant in the Movie class, add the following code to chap9.php:

echo Movie::DISCOUNT.'<BR>';
echo $mov1::DISCOUNT.'<BR>';
echo $mov2::DISCOUNT.'<BR>';

If you run the code above, you’ll get

10

displayed three times. This shows that we can use either the class name ( Movie ) or the object name ( $mov1 or $mov2 ) to access a class constant. All three give us the same value as they are accessing the same memory location.

9.5 Access Modifiers

Now that we know how to create objects and access class members using these objects, let’s discuss a concept we skipped previously – the public and private keywords.

These two keywords are known as access modifiers; they serve as gatekeepers controlling where we can access a particular class member.

 public class members can be assessed everywhere while private class members can only be accessed within the class in which they are declared.

In our Movie class, we have two public properties ( $title and $rentalPrice ) and one private property ( $id ).

Previously, we learned to access the $title property of $mov1 in chap9.php. As $title is a public class property, we had no problems accessing it in chap9.php. Now, let’s try accessing the $id property. Add the line

echo $mov1->id.'<BR>';

to chap9.php and load the page again. What do you get? You get

Fatal error: Uncaught Error: Cannot access private property Movie::$id...

added to the output, right? This is because $id is a private property. As private class members can only be assessed within the class in which they are declared, we are not allowed to access the $id property in chap9.php, which is outside the Movie class.

This is the gist of how access modifiers work; they basically control whether we can access a particular class member outside the class in which it is declared. Got it?

In PHP, access modifiers are mandatory for properties but optional for methods. If we fail to declare the modifier for a property, we’ll get an error message. If we do not declare the modifier for methods, the default modifier is public . As of PHP 7.1.0, we can also add access modifiers for class constants. If we do not declare the modifier for constants, the default is public .

Besides public and private members, PHP also has protected members. These members can be accessed inside the class in which they are declared and any subclass that inherits from that class. We’ll discuss protected members and inheritance in the next chapter.

At this point, some of you may be wondering why we want class members to be private . For instance, why bother declaring the $id property if we cannot access it?

The reason is that while private members cannot be accessed outside the class in which they are declared, they can be accessed inside it. For instance, we can write a function inside the Movie class to display the page heading based on the $id property. To see how that works, add the code below to Movie.php (after the conversion() method but before the closing brace of the Movie class):

public function displayHeading($tag){
 	if (substr($this->id, 0, 1) == 'N')
 		return "<$tag>Movies</$tag>";
 	else
 		return "<$tag>Award Winning Movies</$tag>";
}

This method checks if $id starts with 'N' using the built-in substr() function. If it does, it returns an HTML element (as defined by the parameter $tag ) with the word “Movies” enclosed. Else, it returns an element with the words “Award Winning Movies” enclosed.

Next, replace the line

echo $mov1->id.'<BR>';

in chap9.php with

echo $mov1->displayHeading('H1');

As displayHeading() is a public method, we have no problems accessing it outside the class. If you run the code now, you’ll get “Movies” displayed as an <h1> element. Got it?

9.6 Getter and Setter

In the previous section, we talked about the difference between public and private class members.

Whenever possible, we should declare class members as private if code outside the class does not need to access them. This act of preventing code outside from accessing class members unnecessarily is known as encapsulation.

Encapsulation makes it easy for us to make changes to class members without affecting code outside the class. For instance, if we want to change the name of the $id property in our Movie class to $movieID , we only need to make changes within the Movie class, any code outside the class is not affected. This is one of the advantages of declaring a class property as private .

Another advantage of declaring class properties as private is that it helps prevent unauthorized modifications to our object properties. To see why this is so, add the following code to chap9.php:

$mov1->rentalPrice = -20;
echo $mov1->rentalPrice.'<BR>';

Here, we first assign -20 to the $rentalPrice property of $mov1 . Next, we use an echo statement to echo its value. If you run the code above, you’ll get -20 as the output.

As you can see, we manage to change the $rentalPrice property of $mov1 to -20 . This is because $rentalPrice is a public property. Hence, we can access it outside the Movie class and change it to any value we like. This is definitely not desirable as rental price should not be negative.

To prevent such modifications from happening, we should not declare the $rentalPrice property as public . Instead, we should declare it as private . Try changing the $rentalPrice property to private in Movie.php and run chap9.php again, what do you get?

You get something similar to the output below, right?

Fatal error: Uncaught Error: Cannot access private property Movie::$rentalPrice in…

We are no longer allowed to access and modify the $rentalPrice property of $mov1 as it is now a private property.

Whenever possible, we should always declare our class properties as private ; this helps to prevent any unauthorized access or modifications to them. However, if we declare all our class properties as private , what happens if code outside the class needs to access or modify those properties?

In cases like these, we can use getters and setters. These are magic methods that allow us to provide limited and controlled access to our private and protected properties.

To see how this works, add the following methods to Movie.php (after the displayHeading() method but before the closing brace of the Movie class):

public function __get($propertyRequested){
	if ($propertyRequested == 'id')
		return 'You do not have permission to access id.<BR>';
 	else
 		return $this->$propertyRequested;
}
public function __set($propertyToModify, $value){
	if ($propertyToModify == 'rentalPrice' && $value > $this->rentalPrice)
 	$this->rentalPrice = $value;
 	else
		 echo 'Failed to modify '.$propertyToModify.'<BR>';
}

The first method ( __get() ) is known as a getter; it controls which property can be accessed outside the class and has one parameter called $propertyRequested . This parameter stores the name of the property we want to access.

Within the __get() method, we use an if-else statement to check If $propertyRequested equals 'id' . If it equals, the __get() method returns a string informing us that we do not have permission to access the $id property. Else, it returns the property requested. For instance, if $propertyRequested equals 'rentalPrice' , it returns $this->rentalPrice .

Next, we have the __set() method, which is known as a setter. This method controls which property can be modified. It has two parameters; the first stores the name of the property we want to modify ( $propertyToModify ), and the second stores the new value ( $value ) to assign to this property.

Within our __set() method, we use an if-else statement to check if $propertyToModify equals 'rentalPrice' and if $value is greater than the current $rentalPrice value. If both conditions are met, it allows us to modify the $rentalPrice property. Else, it echoes a string informing us that it is unable to modify the property. Got it? Good!

Now, let’s look at how we can use the __get() and __set() methods. To do that, we simply use the -> operator, followed by the property name. Behind the scene, as long as we have defined our __get() and __set() methods, PHP will call these magic methods automatically.

First, let’s change the access modifiers of all the properties in our Movie class to private .

Next, load chap9.php again. Recall that previously, we tried to change the $rentalPrice property of $mov1 to -20 and got a fatal error? If you load chap9.php now, you’ll no longer get an error. Instead, you’ll get the following output:

Failed to modify rentalPrice
4.99

This is because we have defined our __get() and __set() methods.

When we try to modify the value of the $rentalPrice property, PHP calls the __set() method for us automatically. As -20 is smaller than the current $rentalPrice value (which is 4.99 ), our  __set() method prevented us from changing the $rentalPrice value. When we use an echo statement to echo the $rentalPrice value, the __get() method gives us 4.99 as the output.

Next, add the following code to chap9.php and run the page again:

$mov1->id = 'A12387';
echo $mov1->id;

You’ll get

Failed to modify id
You do not have permission to access id.

added to the output. Here, the __set() method prevented us from modifying the $id property. Similarly, the __get() method prevented us from accessing the $id property.

Last but not least, add the following code to chap9.php and run the page: $mov1->rentalPrice = 5.99;

 echo $mov1->rentalPrice;

You’ll get

5.99

added to the output. Here, we try to change the $rentalPrice value to 5.99 . As 5.99 is greater than the current $rentalPrice value, the __set() method allowed us to make the change. When we use an echo statement to echo the value of $rentalPrice again, the __get() method gives us 5.99 as the output.

Got it? Great!

9.7 Printing a String Representation of the Object

Besides the __set() and __get() methods, another commonly defined magic method in PHP is the __toString() method. Let’s add one to our Movie class.

Add the following code to Movie.php (after the __set() method but before the closing brace of the Movie class):

public function __toString(){
	return
		'Discount = '.self::DISCOUNT.'%'.
 		'<BR>Id = '.$this->id.
 		'<BR>Title = '.$this->title.
 			'<BR>Rental Price (USD) = '.$this->rentalPrice;
}

This method simply returns a string containing information about the Movie class. Notice a new keyword, self , in the method above? This keyword is used to access the DISCOUNT constant defined earlier in the class.

Previously, we learned that to access a class constant outside the class in which it is defined, we can use either the class name or the object name. For instance, in chap9.php, we used $mov1::DISCOUNT$mov2::DISCOUNT and Movie::DISCOUNT to access the DISCOUNT constant.

What if we want to access this constant inside the Movie class itself (i.e., inside the class in which it is defined)? To do that, we can use either the class name or the self keyword.

In the __toString() method above, we used the self keyword. Alternatively, we could have used the class name ( Movie::DISCOUNT ) as well.

After declaring the __toString() method, we can use it to print a string representation of our Movie class objects. To do that, we simply use the echo statement.

To see how this works, add the following lines to chap9.php and run the page again:

echo '<BR>';
echo $mov1;

you’ll get

Discount = 10%
Id = N0001
Title = Lusso
Rental Price (USD) = 5.99

added to the output.

Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13