9eyga The Essentials of Object Oriented PHP
9eyga The Essentials of Object Oriented PHP
Contents
Introduction . . . . . . . . . . . . . . . . . . .
Why bother learning object oriented PHP? .
The purpose of this book . . . . . . . . . .
What does the book cover? . . . . . . . . .
Who is this book for? . . . . . . . . . . . .
Getting the most from this book . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1
1
2
3
4
4
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
6
6
7
7
8
9
9
10
12
13
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
15
15
18
19
21
23
24
26
26
27
27
28
30
31
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
CONTENTS
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
32
32
34
35
36
37
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
38
38
40
41
44
45
46
47
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
50
50
51
51
53
54
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
56
56
57
59
59
60
Polymorphism in PHP . . . . . . . . . . . . . . . .
How to implement the polymorphism principle?
Conclusion . . . . . . . . . . . . . . . . . . . . .
Lets practice what we have just learned . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
63
63
65
66
Type hinting . . . . . . . . . . . . . . . . . . . . . . .
How to do array type hinting? . . . . . . . . . . .
How to do object type hinting? . . . . . . . . . . .
Does PHP support type hinting to basic data types?
Conclusion . . . . . . . . . . . . . . . . . . . . . .
Lets practice what we have just learned . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
68
68
69
70
72
72
73
73
CONTENTS
74
77
78
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
79
79
79
80
81
83
83
84
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
85
85
86
87
89
89
89
90
90
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
. 92
. 92
. 94
. 94
. 95
. 97
. 99
. 101
. 101
. 102
Dependency injection . . . . . . . . . . . . . . . . . . . .
The problem: tight coupling between classes . . . . . .
The solution: dependency injection . . . . . . . . . . .
Why is it a good idea to type hint the injected objects?
Conclusion . . . . . . . . . . . . . . . . . . . . . . . .
Lets practice what we have just learned . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
103
103
104
107
110
111
CONTENTS
Are there any other methods that can help us handle exceptions?
What about writing the exceptions to a log file? . . . . . . . . . .
When to use exception handling? . . . . . . . . . . . . . . . . . .
Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Lets practice what weve just learned: . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
117
118
119
119
120
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
122
122
123
127
129
131
133
133
133
134
How to use Packagist and Composer to integrate existing code libraries into your PHP
apps? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
How to install composer? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Installing the package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
How to add packages? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
How to update the packages? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
How to remove a package from Composer? . . . . . . . . . . . . . . . . . . . . . . . .
Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
135
135
136
140
141
141
142
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
143
143
143
144
146
148
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
149
151
151
151
152
155
156
Epilogue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
What have we learned? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
Some additional resources to advance your knowledge . . . . . . . . . . . . . . . . . . . 157
CONTENTS
Introduction
Why bother learning object oriented PHP?
Object oriented programming came late to PHP. It has been around in other languages, like C++,
Ruby, Python, and JavaScript for much longer, but its demand in PHP is becoming stronger. With that
demand for the programming style there is an increasing demand for developers who can program
in object oriented PHP. And those developers typically earn 60% more than programmers who know
only procedural PHP.
Why?
That is a valid question. After all, most PHP code is used in WordPress, and WordPress is not written
with object oriented code at its core. In addition, there are great examples of applications that are
written in a procedural style of PHP. But it does not tell the full story. Consider this:
Procedural programming is inefficient.
PHP frameworks, like Laravel, Symfony, and CodeIgniter rely exclusively on object oriented
PHP.
CMS systems, like Drupal 8 and October are object oriented at their core.
Every day, additional parts of WordPress are becoming object oriented.
Lets expand on the first point as it is the most important one - everything else flows from it, i.e.
object oriented programming is gaining popularity because it is more efficient. As already stated,
there are great applications written in a procedural style of PHP code. But even the best end up in
spaghetti code where functions and variables are mixed together. Add in HTML, CSS, and JavaScript
to the mix and the code becomes something that is, well, inefficient.
Object oriented code is more organized. Distinct units are created for a single purpose. This means
it is easier to find things in the code (ending those days of spending hours trawling through lines
of spaghetti code to find a single element). It is also easier to add, replace, or remove parts of code,
as it only has to be done once. With procedural programming, on the other hand, it is necessary to
change every instance.
Finally, object oriented programming gives the opportunity to developers to integrate code libraries
from other resources without worrying about name collisions, even though some of the functions
in the code might have the same name.
Introduction
So, back to the original question, why bother learning object oriented PHP? The answer is:
It is increasingly common.
Developers with this skill earn more.
The code they write is better.
Programming in object oriented PHP requires a different way of thinking. That is why it is important
to get an understanding of the fundamentals.
Introduction
among programmers. In particular, there is no risk of name collisions. This is where more than
one function or variable in the program has the same name. Modularity means that each of these
functions or variables resides in an independent module, so name collisions are not an issue.
So, the purpose of this book is to instill in programmers the principle of modularity. Everything
is based on this from classes to namespaces to methods to code libraries. Modularity is a way of
organizing code, and it gives object oriented PHP most of its power.
Creating classes
Adding properties to a class
Creating objects from a class
Setting an objects properties
Adding methods to a class
The book also shows developers how to write streaming code that is easier to digest and understand
because it more closely resembles human language.
In addition, the book covers a number of other skills, hints, tips, and tricks to make object oriented
programming more efficient. This includes:
And it covers the intimidating concept of dependency injection in a practical and easy-to-understand
way. Once finished with the dependency injection chapter, object oriented programming becomes
even faster.
Introduction
Introduction
This principle of active learning is carried through to the next stage, which is practice. Readers are
given the opportunity to practice the ideas, concepts, and processes that have just been explained. It
is important to the learning process that time is given to these practice elements, so this is the next
tip - serious learning cannot be done without practice.
Finally, solutions are given for the practice exercises so that the reader can see their success and gain
confidence.
Each principle of object oriented PHP is taught using this process:
The punchy text is easy to digest so that readers can go through sections quickly if they want.
However, there is also enough detailed information and examples if the reader needs to spend more
time getting an understanding of a particular concept.
So, to get the most from this book, approach it with an open mind and be ready to get involved. By
doing so, you will get a good understanding of object oriented PHP with sufficient knowledge and
confidence to apply it practically in your work.
class
object
method
property
We created the object $bmw from the class Car with the new key word.
The process of creating an object is also known as instantiation.
We can create more than one object from the same class.
$bmw = new Car ();
$mercedes = new Car ();
In fact, we can create as many objects as we like from the same class, and then give each object its
own set of properties.
From the same Car class, we created three individual objects with the name of: Mercedes, Bmw, and
Audi.
Although all of the objects were created from the same class and thus have the classs methods
and properties, they are still different. This is not only, because they have different names, but
also because they may have different values assigned to their properties. For example, in the image
above, they differ by the color property - the Mercedes is green while the Bmw is blue and the Audi
is orange.
In order to get a property, we write the class name, and then dash greater than (->), and then
the property name.
Note that the property name does not start with the $ sign; only the object name starts with
a $.
Result:
beige
beige
and in order to set the value of the $comp property for both objects:
$bmw -> comp = "BMW";
$mercedes -> comp = "Mercedes Benz";
10
Result:
blue
We can also get the company name and the color of the second car object.
echo $mercedes -> color;
echo $mercedes -> comp;
Result:
beige
Mercedes Benz
Result:
beep
beep
Here is the full code that we have written during this chapter:
<?php
// Declare the class
class Car {
// Properties
public $comp;
public $color = "beige";
public $hasSunRoof = true;
// Method that says hello
public function hello()
{
return "beep";
}
}
// Create an instance
$bmw = new Car ();
$mercedes = new Car ();
// Get the values
echo $bmw -> color; // beige
echo "<br />";
echo $mercedes -> color; // beige
echo "<hr />";
// Set the values
$bmw -> color = "blue";
$bmw -> comp = "BMW";
$mercedes -> comp = "Mercedes Benz";
11
12
Conclusion
In this chapter we have done our first steps into the world of object oriented PHP by learning about
classes and about the objects that can be created out of them. In the next chapter we will learn
about the $this keyword that enables us to approach properties and methods from within the class.
13
Coding exercise
Almost every application or blog handles users. Whether its the registration process, the login and
logout, sending reminders to users who lost their passwords, or changing the passwords on demand,
all of the code that handles users can be grouped into a single class. In our example, we call the class
that handles users, User, in agreement with the prevailing naming convention.
Lets write a user class with the tools we have just acquired. This class will contain the first and last
name of each user and will be able to say hello to anyone who uses our application.
1.5 Write what you think should be the class name, the names of the properties for the first
and last name, and the name of the method that returns hello.
class name: _______
class properties: (1) _____ , (2) _____
class method: _______
1.6 Write the class User, and add the properties. Thats how we start to write the class:
class User {
// Your code here
}
1.8 Create the first instance, and call it $user1. Use the new keyword to create an object
from the class.
1.9 Set the values for the first and last name to $user1.
$firstName = John
$lastName = Doe
1.10 Get the user first and last name, and print it to the screen with echo.
1.11 Use the hello method with the first and last name variables in order to say hello to
the user.
1.12 Add another object, call it $user2, give it a first name of Jane and last name of Doe,
then say hello to the user.
Suggested solutions
14
We also created two objects out of the class in order to be able to use its code:
$bmw = new Car ();
$mercedes = new Car ();
Only the this keyword starts with the $ sign, while the names of the properties and methods
do not start with it.
The $this keyword indicates that we use the classs own methods and properties, and allows us to
have access to them within the classs scope.
Lets illustrate what we have just said on the Car class. We will enable the hello() method to
approach the classs own properties by using the $this keyword.
15
We use:
$this -> comp
16
We can now call the hello method for the first car object:
echo $bmw -> hello();
Result
Beep I am a BMW, and I am blue.
And for the second car object:
echo $mercedes -> hello();
Result
Beep I am a Mercedes Benz, and I am green.
17
18
Conclusion
In this chapter, we have learned how to use the $this keyword in order to get the classs own
properties and methods from within the class. In the next chapter, we will learn how to chain
methods and properties.
19
Coding exercise
In the previous chapter, we wrote the hello() method inside the User class. In the following exercise,
we will add to the hello() method the ability to approach the class properties with the $this
keyword.
First, lets remind ourselves what the User class looks like:
class User
// The
public
public
{
class properties
$firstName;
$lastName;
Wouldnt it be nicer if we could allow the hello() method the ability to get the classs properties,
so that it would be able to say hello to the user name (for example, hello, John Doe)?
2.2 Add to the hello() method the ability to approach the $firstName property, so the
hello() method would be able to return the string hello, $firstName.
2.3 Create a new object with the first name of Jonnie and last name of Roe.
2.4 Echo the hello() method for the $user1 object, and see the result.
Suggested solutions
20
class Car {
public $tank;
// Add gallons of fuel to the tank when we fill it
public function fill($float)
{
$this-> tank += $float;
}
// Subtract gallons of fuel from the tank as we ride the car
public function ride($float)
{
$miles = $float;
21
22
$gallons = $miles/50;
$this-> tank -= $gallons;
}
}
As we would like our code to look elegant, we will chain the methods and properties. Note the
arrows in the code.
$tank = $car -> fill(10) -> ride(40) -> tank;
In words: How much fuel do we have left in our tank after putting in 10 gallons, and driving 40
miles?
In order to perform the chaining, the methods should return the $this keyword.
In order for us to be able to perform the chaining, the methods should return the object and, since
we are inside the class, the methods should return the $this keyword.
In the code below, we can see how each method returns the $this keyword in order to allow the
chaining.
class Car {
public $tank;
// Add gallons of fuel to the tank when we fill it
public function fill($float)
{
$this-> tank += $float;
return $this;
}
// Subtract gallons of fuel from the tank as we ride the car
public function ride($float)
{
$miles = $float;
$gallons = $miles/50;
$this-> tank -= $gallons;
return $this;
}
}
23
Now, we can create an object from the Car class with the name of $bmw and find out the number of
gallons of fuel left in our cars tank after we have filled the tank with 10 gallons of fuel and driven
40 miles.
// Create an object from the Car class
$bmw = new Car();
// Add 10 gallons of fuel, then ride 40 miles
//
and get the number of gallons in the tank
$tank = $bmw -> fill(10) -> ride(40) -> tank;
// Print the results to the screen
echo "The number of gallons left in the tank: " . $tank . " gal.";
Result:
The number of gallons left in the tank: 9.2 gal.
Conclusion
In this chapter, we learned that we can chain properties and methods to provide for a fluent code
and improve its readability. In the next chapter, we will learn how to restrict access to the properties
and methods inside our classes.
24
{
class properties
$firstName;
$lastName;
3.1 Add a register() method to the class that echoes the name of the user plus the verb
registered.
Use the $this keyword to approach the classs own properties.
3.2 Add a mail() method to the class that echoes the string emailed.
3.3 Add return $this to the register() method so that it can be chained to any other
method in the class.
3.4 Create a new $user1 object with the first name of Jane and the last name of Roe. For
this object, chain the mail() method to the register() method and see the result.
25
Notice that each method we want to chain to should return the $this keyword. So, if we would like
to write the next line of code that chains together 3 methods:
$user1 -> register() -> mail() -> hello();
We would have to return the $this keyword from both the register() and mail() methods, but we
wont have to return the $this keyword from the hello() method because it concludes the chain.
Suggested solutions
Result:
The car model is Mercedes
26
27
Result:
Fatal error: Cannot access private property Car::$model
28
In the following example, we will see that we can get and set the value of a private property,
$carModel, through the use of setter and getter methods. We will use the setModel() method in
order to set the value of the car model, and the getModel() method to get the value of the property.
class Car {
// The private access modifier denies access to the method
//
from outside the classs scope
private $model;
// The public access modifier allows the access to the method
//
from outside the class
public function setModel($model)
{
$this -> model = $model;
}
public function getModel()
{
return "The car model is
}
}
$mercedes = new Car();
// Set the cars model
$mercedes -> setModel("Mercedes");
// Get the cars model
echo $mercedes -> getModel();
Result:
The car model is Mercedes
29
In our example, we can validate that only certain car models can make their way, and be assigned to
the $model property, by defining the allowed alternatives for models in the getModel() method. For
this purpose, we define inside the getModel() method an array of allowed car models, and check
that only these models are assigned to the $model property.
class Car {
// The private access modifier denies access to the
//
method from outside the classs scope
private $model;
// The public access modifier allows the access to
//
the method from outside the class
public function setModel($model)
{
// Validate that only certain car models are assigned
//
to the $carModel property
if(in_array($model,$allowedModels))
{
$this -> model = $model;
}
}
public function getModel()
{
return "The car model is
}
}
$mercedes = new Car();
// Set the cars model
$mercedes -> setModel("Mercedes");
// Get the cars model
echo $mercedes -> getModel();
30
Conclusion
So far, we have learned about two access modifiers: public, which allows outside functions to modify
the code inside a class, and private, that prevents any code from outside the class to change the
properties and methods which it protects. We saw that, in order to modify private methods and
properties, we can use public methods that have the privilege to interact with the code outside the
scope of the class.
In the next chapter, we will learn about magic methods and constants. These are kinds of candies
that PHP provides, but they should be used with much caution.
31
Coding exercise
Lets return to the User class that we developed in the previous chapters, but lets now define the
$firstName of the user as a private property.
This is the User class:
class User {
// Your code goes here
}
4.2 Create a new class property with the name of $firstName, and prevent any code from
outside the class from changing the property value by using the appropriate access modifier
(private or protected).
4.3 Create a method to set the $firstName property value. Remember to use the right access
modifier (public/private).
4.5 Create a new user object with the name of $user1, set its name to Joe and make it
return its name.
Suggested solutions
In order to use the constructor, we have to pass an argument to the class with the name of the model
as soon as we create the object, but if we try to create a new object without assigning the value that
the constructor needs, we will encounter an error.
$car1 = new Car();
32
33
Result:
Warning: Missing argument 1 for Car::__construct()
In order to avoid such an error, we have to assign a value to the constructor. Thus, for the sake of
example, we assign the value "Mercedes" to the constructor by writing it within the brackets of the
newly created object.
$car1 = new Car("Mercedes");
Now, lets add the method getCarModel() in order to echo the car model from the object that we
have just created.
class Car {
private $model;
// The constructor
public function __construct ($model)
{
$this -> model = $model;
}
public function getCarModel()
{
return ' The car model is: ' . $this -> model;
}
}
// We pass the value of the variable
//
once we create the object
$car1 = new Car("Mercedes");
echo $car1 -> getCarModel();
Result:
The car model is: Mercedes.
34
Even though we created the object without passing a value to the model property, we didnt cause
an error because the model property in the constructor has a default value of null.
35
Result:
The car model is: N/A
On the other hand, lets see what happens when we define the model once we create the object. In
the example below, we assign the value Mercedes to the $model property as soon as we create the
object.
class Car {
private $model = '';
// The constructor
public function __construct($model = null)
{
if($model)
{
$this -> model = $model;
}
}
public function getCarModel()
{
return ' The car model is: ' . $this -> model;
}
}
// We create the new Car object
//
with the value of the model
$car1 = new Car('Mercedes');
echo $car1 -> getCarModel();
Result:
The car model is: Mercedes
Magic constants
In addition to magic methods, the PHP language offers several magic constants.
For example, we may use the magic constant __CLASS__ (magic constants are written in uppercase
letters and prefixed and suffixed with two underlines) in order to get the name of the class in which
it resides.
Lets take a look at the following example in which we use the __CLASS__ magic constant in the
getter method:
36
class Car {
private $model = '';
// The constructor
public function __construct($model = null)
{
if($model)
{
$this -> model = $model;
}
}
public function getCarModel()
{
// We use the __class__ magic constant
//
in order to get the class name
return " The <b>" . __class__ . "</b> model is: " . $this -> model;
}
}
$car1 = new Car('Mercedes');
echo $car1 -> getCarModel();
Result:
The Car model is: Mercedes
Other magic constants that may be of help are:
__LINE__ to get the line number in which the constant is used.
__FILE__ to get the full path or the filename in which the constant is used.
__METHOD__ to get the name of the method in which the constant is used.
Conclusion
In this chapter, we have learned about magic methods and constants, and how to use a constructor
to set the values of properties as soon as we create objects out of classes. In the next chapter, we will
learn about inheritance, a principle of object oriented programming that can save us from repeating
ourselves.
37
5.1 Add to the class a constructor method to set a value to the $firstName property as soon
as the object is created.
So far in the chapter, we have used the constructor method to set the value of a single property, but
we can use a constructor in order to set the values of more than one property. In our exercise, we
will use the constructor method to set the value of the $firstName as well as the $lastName.
5.2 Add to the constructor the ability to set the value of the $lastName property (remember
that you can pass to a method more than parameter).
5.3 Add to the class a getFullName() public method that returns the full name.
5.4 Create a new object, $user1, and pass to the constructor the values of the first and last
name. The first name is John and the last name is Doe (you may choose your preferred
combination of first and last name).
Suggested solutions
The child class can make use of all the non-private methods and properties that it inherits from the
parent class. This allows us to write the code only once in the parent, and then use it in both the
parent and the child classes.
In the example given below, the SportsCar class inherits the Car class, so it has access to all of
the Cars methods and properties that are not private. This allows us to write the setModel() and
hello() public methods only once in the parent, and then use these methods in both the parent and
the child classes.
38
Result:
beep! I am a Mercedes Benz
39
40
// The child class can use the code it inherited from the parent class,
//
and it can also have its own code
class SportsCar extends Car {
private $style = 'fast and furious';
public function driveItWithStyle()
{
return 'Drive a ' . $this -> getModel() . ' <i>' .
$this -> style . '</i>';
}
}
41
Result:
Drive a Ferrari fast and furious.
42
}
}
Result:
Notice: Undefined property: SportsCar::$model
We get an error because the hello() method in the child class is trying to approach a private
property, $model, that belongs to the parent class.
We can fix the problem by declaring the $model property in the parent as protected, instead of
private, because when we declare a property or a method as protected, we can approach it from
both the parent and the child classes.
43
Result:
beep! I am a Mercedes Benz
Now it works, because we can access a protected code that belongs to a parent from a child class.
44
Result:
Hallo
The result reflects the fact that the hello() method from the parent class was overridden by the
child method with the same name.
45
Result:
Fatal error: Cannot override final method Car::hello()
46
Since we declared the hello method as final in the parent, we cannot override the method in the
child class.
We use inheritance in order to reduce code duplication by using code from the parent
class in the child classes.
Conclusion
In this chapter we have learned one of the principles of object oriented programming, the concept of
inheritance. We use inheritance in order to reduce code duplication by using code from the parent
class in the child classes.
In the next chapter, we will learn about abstract classes and methods, which are classes that cannot
be instantiated and methods that have no bodies.
6.2 Which keyword do we use in order to declare that a method or property can only be
used within the parent class and its child classes?
A : private
B : protected
C : public
47
48
6.3 We learned about three access control modifiers (public, private, and protected)
that we use to allow/restrict access to the code.
In the following table, we will use V to mark that the code can be accessed from a
certain level, and X if it cannot be accessed.
Fill in the table with the right values.
For example, public code can be accessed from within the class, from the code within
the child classes, and from the global scope, while private code cannot be accessed
from the global scope (*).
Coding exercise
In the following example, we will create an Admin class, which is a child class of the User class.
6.4 Create a user class.
6.5 Add to the class a private property with the name of $username.
6.6 Create a setter method that can set the value of the $username.
6.8 Now, lets add to the Admin class some code. First, add a public method by the name of
expressYourRole, and make it return the string: "Admin".
6.9 Add to the Admin class another public method, sayHello, that returns the string Hello
admin, XXX with the username instead of XXX.
6.10 Create an object $admin1 out of the class Admin, set its name to "Balthazar", and say
hello to the user. Do you see any problem?
Suggested solutions
49
We put the abstract methods that are also declared with the abstract keyword within the abstract
class. Abstract methods inside an abstract class dont have a body, only a name and parameters
inside parentheses.
In the example given below, we create a public abstract method, calcNumMilesOnFullTank(), that
is the skeleton for methods that we will create in the child classes. Once created, these methods will
return the number of miles a car can be driven on a full tank of gas.
50
51
It is important to know that once we have an abstract method in a class, the class must also be
abstract.
52
Lets create a child class with the name of Honda, and define in it the abstract method that it inherited
from the parent, calcNumMilesOnFullTank().
class Honda extends Car {
// Since we inherited abstract method,
//
we need to define it in the child class,
//
by adding code to the method's body.
public function calcNumMilesOnFullTank()
{
$miles = $this -> tankVolume*30;
return $miles;
}
}
We can create another child class from the Car abstract class and call it Toyota, and here again
define the abstract method calcNumMilesOnFullTank() with a slight change in the calculation. We
will also add to the child class its own method with the name of getColor() that returns the string
"beige".
class Toyota extends Car {
// Since we inherited abstract method,
//
we need to define it in the child class,
//
by adding code to the method's body.
public function calcNumMilesOnFullTank()
{
return $miles = $this -> tankVolume*33;
}
public function getColor()
{
return "beige";
}
}
Lets create a new object, $toyota1, with a full tank volume of 10 Gallons, and make it return the
number of miles on full tank as well as the cars color.
53
Result:
330
beige
Conclusion
In this chapter, we had our first encounter with the concept of abstraction, which enables us to
commit the child classes to methods names, and not to methods bodies. In the next chapter, we are
going to revisit the concept of abstraction, but this time through the use of interface.
7.2 Which keyword is used to declare a child class that inherits from an abstract class?
A : abstract
B : inherit
C : abstract
D : extends
7.3 What are the main reasons for using an abstract class in the code?
A : To enable code inheritance in PHP.
B : To commit the child classes to certain methods.
C : To make a good impression on your boss and colleagues.
D : To encapsulate the code of the parent from any code outside the parent class.
54
55
Coding exercise
In the following example, we will create an abstract User class and two child classes (Admin and
Viewer classes) that inherit from the abstract class.
7.5 Create an abstract class with the name of User, which has an abstract method with the
name of stateYourRole.
7.6 Add to the class a protected variable with the name of $username, and public setter and
getter methods to set and get the $username.
7.7 Create an Admin class that inherits the abstract User class.
7.9 Define the method stateYourRole() in the child class and make it return the string
admin;
7.10 Create another class, Viewer that inherits the User abstract class. Define the method
that should be defined in each child class of the User class.
7.11 Create an object from the Admin class, set the username to Balthazar, and make it
return the string admin.
Suggested solutions
In the simple example given below, we will create an interface for the classes that handle cars, which
commits all its child classes to setModel() and getModel() methods.
interface Car {
public function setModel($name);
public function getModel();
}
56
57
Interfaces, like abstract classes, include abstract methods and constants. However, unlike abstract
classes, interfaces can have only public methods, and cannot have variables.
The classes that implement the interfaces must define all the methods that they inherit from the
interfaces, including all the parameters. So, in our concrete class with the name of miniCar, we add
the code to all the abstract methods.
class miniCar implements Car {
private $model;
public function setModel($name)
{
$this -> model = $name;
}
public function getModel()
{
return $this -> model;
}
}
58
59
Abstract classes
the code
-abstract methods
-constants
-abstract methods
-constants
-concrete methods
-concrete variables
access modifiers
-public
-public
-protected
-private
etc.
number of parents
Conclusion
In this chapter, we saw how to create and use interfaces, and learned about the differences between
abstract classes and interfaces. In the next chapter, we are going to use our knowledge of abstract
classes to improve the consistency of our code.
60
8.3 Which of the following access modifiers is allowed for abstract methods in interfaces?
A : public
B : protected
C : private
D:A+B+C
Coding exercise
In this chapter, we saw that a class can implement more than one interface. In the concluding
example, we will go one step further by letting the same child class inherit from both a parent
class and from two interfaces.
8.5 Create a User class with a protected $username property and methods that can set and
get the $username.
8.6 Create an Author interface with the following abstract methods that can give the user
an array of authorship privileges. The first method is setAuthorPrivileges(), and it gets
a parameter of $array, and the second method is getAuthorPrivileges().
8.7 Create an Editor interface with methods to set and get the editors privileges.
8.8 Now, create an AuthorEditor class that extends the User class, and implements both
the Author and the Editor interfaces.
8.9 Create in the AuthorEditor class the methods that it should implement, and the
properties that these methods force us to add to the class.
For example, in order to implement the public method setAuthorPrivileges(), we must
add to our class a property that holds the array of authorship privileges, and name it
$authorPrivilegesArray accordingly.
8.10 Create an object with the name of $user1 from the class AuthorEditor, and set its
username to Balthazar.
8.11 Set in the $user1 object an array of authorship privileges, with the following privileges:
write text, add punctuation.
8.12 Set in the $user1 object an array with the following editorial privileges: edit text,
edit punctuation.
8.13 Use the following code to get the $user1 name and privileges:
61
Suggested solutions
62
Polymorphism in PHP
In this chapter, we are going to learn a naming convention that can help us write code which is
much more coherent and easy to use. According to the Polymorphism (Greek for many forms)
principle, methods in different classes that do similar things should have the same name.
According to the Polymorphism principle, methods in different classes that do similar
things should have the same name.
A prime example is of classes that represent geometric shapes (such as rectangles, circles and
octagons) that are different from each other in the number of ribs and in the formula that calculates
their area, but they all have in common an area that needs to be calculated. In such case, the
polymorphism principle says that all the methods that calculate the area (and it doesnt matter
for which shape or class) should have the same name. For example, we can write in each class that
represents a shape a calcArea() method that calculates the area with a different formula. Now,
whenever the end users would like to calculate the area for the different shapes, the only thing that
they need to know is that a method with the name of calcArea() is used to calculate the area. So,
they dont have to pay any attention to the technicalities of how actually each method works. The
only thing that they need to know is the name of the method and what it is meant to do.
In accordance, the Circle class implements the interface by putting into the calcArea() method
the formula that calculates the area of circles.
63
Polymorphism in PHP
64
The rectangle class also implements the Shape interface but defines the function calcArea() with a
calculation formula that is suitable for rectangles.
class Rectangle implements Shape {
private $width;
private $height;
public function __construct($width, $height)
{
$this -> width = $width;
$this -> height = $height;
}
// calcArea calculates the area of rectangles
public function calcArea()
{
return $this -> width * $this -> height;
}
}
We can be sure that all of the objects calculate the area with the method that has the name of
calcArea(), whether it is a rectangle object or a circle object (or any other shape), as long as they
implement the Shape interface.
Now, we can use the calcArea() methods to calculate the area of the shapes:
Polymorphism in PHP
65
Result:
28.274333882308
12
Conclusion
In this chapter, we have learned how to implement the polymorphism principle in PHP. In the
next chapter, we will learn about type hinting that specifies the expected data type (arrays, objects,
interface, etc.) for an argument in a function declaration.
Polymorphism in PHP
66
Coding example
In our coding example lets return to the User class that we used in the previous chapters.
In order to implement the polymorphism principle, we are going to create an abstract User class
that commits the classes that inherit from it to calculate the number of scores that a user has
depending on the number of articles that he has authored or edited. On the basis of the User class,
we are going to create the Author and Editor classes, and both will calculate the number of scores
with the method calcScores(), although the calculated value will differ between the two classes.
This is the skeleton for the abstract User class:
abstract class User {
protected $scores
= 0;
protected $numberOfArticles = 0;
// The abstract and concrete methods
}
9.2 Add to the class concrete methods to set and get the number of articles:
1. setNumberOfArticles($int)
2. getNumberOfArticles()
$int stands for an integer.
9.3 Add to the class the abstract method: calcScores(), that performs the scores calculations separately for each class.
Polymorphism in PHP
9.4 Create an Author class that inherits from the User class. In the Author create a concrete
calcScores() method that returns the number of scores from the following calculation:
numberOfArticles * 10 + 20
9.5 Also create an Editor class that inherits from the User class. In the Editor create
a concrete calcScores() method that returns the number of scores from the following
calculation:
numberOfArticles * 6 + 15
9.6 Create an object, $author1, from the Author class, set the number of articles to 8, and
echo the scores that the author gained.
9.7 Create another object, $editor1, from the Editor class, set the number of articles to
15, and echo the scores that the editor gained.
Suggested solutions
67
Type hinting
With Type hinting we can specify the expected data type (arrays, objects, interface, etc.) for an
argument in a function declaration. This practice can be most advantageous because it results in
better code organization and improved error messages.
This chapter explains the subject of type hinting for arrays and objects in PHP5. It also explains
the subject of type hinting for basic data types (integers, floats, strings, and booleans) which is only
supported in PHP7.
In the following example, the calcNumMilesOnFullTank() function calculates the number of miles
a car can be driven on a full tank of gas by using the tank volume as well as the number of miles
per gallon (mpg). This function accepts only array as an argument, as we can see from the fact that
the argument name is preceded by the array keyword.
// The function can only get array as an argument.
function calcNumMilesOnFullTank(array $models)
{
foreach($models as $item)
{
echo $carModel = $item[0];
echo " : ";
echo $numberOfMiles = $item[1] * $item[2];
echo "<br />";
}
}
68
69
Type hinting
First, lets try to pass to the function an argument which is not an array to see what might happen
in such a case:
calcNumMilesOnFullTank("Toyota");
Result:
Catchable fatal error: Argument 1 passed to calcNumMilesOnFullTank() must be of the
type array, string given
This error is a precise description of what went wrong with our code. From it, we can understand
that the function expected an array variable, and not a string.
Lets rewrite the code and pass to the function an array with the expected items, including the model
names, the tank volumes, and the mpg (miles per gallon).
$models = array(
array('Toyota', 12, 44),
array('BMW', 13, 41)
);
calcNumMilesOnFullTank($models);
Result:
Toyota : 528
BMW : 533
Now its working because we passed to the function the array that it expected to get.
Type hinting
70
class Car {
protected $driver;
// The constructor can only get Driver objects as arguments.
public function __construct(Driver $driver)
{
$this -> driver = $driver;
}
}
class Driver {}
On the other hand, PHP7 does support scalar type hinting. The supported types are: integers, floats,
strings, and booleans.
The following code example can only work in PHP7.
Type hinting
class car
{
protected $model;
protected $hasSunRoof;
protected $numberOfDoors;
protected $price;
// string type hinting
public function setModel(string $model)
{
$this->model = $model;
}
// boolean type hinting
public function setHasSunRoof(bool $value)
{
$this->hasSunRoof = $value;
}
// integer type hinting
public function setNumberOfDoors(int $value)
{
$this->numberOfDoors = $value;
}
// float type hinting
public function setPrice(float $value)
{
$this->price = $value;
}
}
71
72
Type hinting
Conclusion
In this chapter, we explained type hinting for the array and object data types as well as for the scalar
data types (integers, floats, strings, and booleans), but did not explain how to do it for interfaces.
However, the use of type hinting for interfaces can yield many benefits, as you can learn in the next
chapter.
Suggested solutions
73
74
{
return $this -> rib * $this -> rib * $this -> height;
}
}
Outside of the class, the programmer writes a function to calculate the price for a full tank of gas by
multiplying the tank volume by the price per gallon. However, since he doesnt want the function
to get any argument other than those that belong to the Bmw class, he uses type hinting:
// Type hinting ensures that the function gets only Bmw objects as arguments
function calcTankPrice(Bmw $bmw, $pricePerGalon)
{
return $bmw -> calcTankVolume() * 0.0043290 * $pricePerGalon . "$";
}
Now, he can easily calculate how much a full tank of gas costs for BMWs. for a car with the license
plate number of 62182791, a rib length of 14 and height of 21, and using gas priced at 3 dollars
per gallon.
$bmw1 = new Bmw('62182791', 14, 21);
calcTankPrice($bmw1, 3);
Result:
53.454492$
75
class Mercedes {
protected $model;
protected $radius;
protected $height;
public function __construct($model, $radius, $height)
{
$this -> model = $model;
$this -> radius = $radius;
$this -> height = $height;
}
// Calculate the volume of cylinders
public function calcTankVolume()
{
return $this -> radius * $this -> radius * pi() * $this -> height;
}
}
When our programmer completed the task of writing the Mercedes class, he tried to calculate the
price of a full tank of gas for a Mercedes.
$mercedes1 = new Mercedes('12189796', 7, 28);
echo calcTankPrice($mercedes1, 3);
This error message is the result of not passing the right object to the function, since he tried to pass a
Mercedes object to the calcTankVolume() function, while the function can only accept objects that
belong to the Bmw class.
First, our programmer attempted to solve the problem by not using any type hinting, but then
he understood that a better solution would be the use of type hinting for interfaces. Here I use
interface in its wider meaning that includes both abstract classes and real interfaces.
So, first he created an abstract class with the name of Car that both the Bmw and the Mercedes (and,
in fact, any other car model) can inherit from.
Then he re-factored the Bmw and Mercedes classes so they inherit from the Car class:
class Bmw extends Car {
protected $rib;
public function __construct($model, $rib, $height)
{
$this -> model = $model;
$this -> rib
= $rib;
$this -> height = $height;
}
// Calculate a rectangular tank volume
public function calcTankVolume()
{
return $this -> rib * $this -> rib * $this -> height;
}
}
76
77
return $this -> radius * $this -> radius * pi() * $this -> height;
}
}
Since both the classes inherit from the same interface, he chose wisely to type hint the function
calcTankPrice() with the Car interface, so that the function can get any object that belong to this
interface.
// Type hinting ensures that the function gets only objects
//
that belong to the Car interface
function calcTankPrice(Car $car, $pricePerGalon)
{
echo $car -> calcTankVolume() * 0.0043290 * $pricePerGalon . "$";
}
Now, lets see the result when we try to use the function calcTankPrice() on both a Bmw and a
Mercedes objects:
$bmw1 = new Bmw('62182791', 14, 21);
echo calcTankPrice($bmw1, 3);
$mercedes1 = new Mercedes('12189796', 7, 28);
echo calcTankPrice($mercedes1, 3);
Result:
53.454492$
55.977413122858$
Whenever we need to do type hinting to more than one related classes, we should be
using interface type hinting.
The message to take home from this chapter is that whenever we need to do type hinting to more
than one related classes, we should be using interface type hinting.
Conclusion
In this chapter, we have learned how to implement type hinting for interfaces. In the next chapter
we will learn about static methods and properties that are used without the need of creating an
object.
78
11.3 Create function to add Mr. or Mrs. to the username. When writing the function
make sure to type hint it correctly, so it can only get the types it is expected to.
11.4 Run the code against a user with the name of Jane and against another user with the
name of Bob.
Suggested solutions
79
80
Result:
3
Pay attention to the use of the $ sign right after the scope resolution operator.
Now, we can use the code we have written so far to set and get the number of cars.
echo Utilis::$numCars;
Utilis::addToNumCars(3);
echo Utilis::$numCars;
Utilis::addToNumCars(-1);
echo Utilis::$numCars;
81
Result:
0
3
2
echo Utilis::$numberOfCars;
Utilis::add1ToCars();
echo Utilis::$numberOfCars;
Utilis::add1ToCars();
echo Utilis::$numberOfCars;
82
Utilis::add1ToCars();
echo Utilis::$numberOfCars;
Result:
0
1
2
3
In order to use the redirect() method, all we need to do is call it from the scope of the Utilis class
without having the need to create an object. Its as simple as this:
Utilis::redirect("http://www.phpenthusiast.com");
83
Conclusion
In this chapter, we have learned how and when to use static methods and properties, but most
important when not to use it. In the next chapter, we are going to learn how to include code the
object oriented way with traits.
Suggested solutions
84
In the example given below, a trait with the name of Price has a method changePriceByDollars()
that calculates the new price from the old price and the price change in dollars.
trait Price {
public function changePriceByDollars($price, $change)
{
return $price + $change;
}
}
Once we create a trait, we can use it in other classes with the use keyword. In the example given
below, both the classes Bmw and Mercedes use the Price trait.
85
86
class Bmw {
use Price;
}
class Mercedes {
use Price;
}
In order to see our code in action, lets create objects from the classes and then, lets make use of the
changePriceByDollars() method that they got from the trait.
$bmw1 = new Bmw();
// Add 3000$
echo $bmw1 -> changePriceByDollars(45000, +3000);
Result:
48000
39900
This example can teach us that we can use the code from the traits inside the classes in pretty much
the same way that we can include a block of code into each of the classes.
87
Result:
39900
Mercedes on special sell
88
In a trait it is possible to put concrete (real) methods, abstract methods, properties and even
constants.
While the same class can use more than one trait, it can only inherit from one class.
Traits do not respect the visibility scope, thus allowing a traits methods to access private
properties and methods in the class that uses them.
In the example given below, the traits method changePriceByDollars() is allowed to interact with
the private $price property.
trait Price {
// The method needs the $price property.
public function changePriceByDollars($change)
{
return $this -> price += $change;
}
}
class Mercedes {
use Price;
// The $price is private
private $price;
public function __construct($price)
{
$this -> price = $price;
}
public function getPrice()
{
return $this -> price;
}
}
89
Result:
42000
39900
We can see that the traits methods has access to private methods within the classes that use them.
90
Conclusion
In this chapter, we learned that traits can be used to share code between different classes, but that
they are best reserved for only those cases in which the use of inheritance is limited. Such cases
include the need for inheritance from several classes, and a piece of code which is shared between
several (but not all) of the classes that implement an interface.
In the next chapter, we will learn how to group together related code under a namespace and how
we can approach code within a namespace.
13.3 Is it appropriate to use traits in a scenario in which all of the child classes of an interface
need the same methods?
91
Coding exercise
In the following exercise, we are going to write a simple program that uses an interface. In it, we are
going to have three classes that inherit from the interface User: Author, Commentator, and Viewer.
Only the first two classes have the need to use a Writing trait.
13.4 Write an interface with the name of User.
13.5 Write three classes to implement the User interface: Author, Commentator and Viewer.
13.6 Add a trait with the name of Writing that contains an abstract method with the name
of writeContent().
13.7 Use the trait Writing in the Author class, and implement its abstract method by making
it return the string Author, please start typing an article.
13.8 Use the trait Writing in the Commentator class, and implement its abstract method by
making it return the string Commentator, please start typing your comment.
13.9 Run the code you have just written and see the result.
Suggested solutions
92
93
94
Now, we can write the CarIntro class within the CarIntro.php file:
class CarIntro {
public function sayHello()
{
return "beep!";
}
}
Pay attention to the fact that we call our classes with the same name as our files. This naming
convention would pay off later when wed like to autoload our classes.
namespace Acme\Car;
class CarIntro {
public function sayHello()
{
return "beep!";
}
}
95
<?php
// 1. Require the namespaced file
require "src/Car/CarIntro.php";
// 2. Import the namespace
use Acme\Car\CarIntro;
Pay attention that in order to use a class we add the name of the class to the namespace. So, in order
to import the CarIntro class from the Acme\Car namespace, we use Acme\Car\CarIntro.
Now, that we have imported the class, we can create an object out of it:
<?php
// 1. Require the namespaced file
require "src/Car/CarIntro.php";
// 2. Import the namespace
use Acme\Car\CarIntro();
// 3. Use the class from the context of the namespace
$carIntro = new Acme\Car\CarIntro();
echo $carIntro -> sayHello();
Result:
beep!
96
<?php
// 1. Require the file
require "src/Car/CarIntro.php";
// 2. Import the namespace
use Acme\Car\CarIntro;
// 3. Call the class from the context of the namespace,
//
this time by using only the class name
$carIntro = new CarIntro();
echo $carIntro -> sayHello();
Result:
beep!
We can also give the class a friendly name (also known as aliasing) by using the as keyword with
the following syntax:
use OriginalClassName as AliasName
In our example, lets replace the original class name of CarIntro with the friendly name of Intro,
and then use this friendly name when working with the class methods.
<?php
// 1. Require the file
require "src/Car/CarIntro.php";
// 2. Import the namespace and give it a friendly name
use Acme\Car\CarIntro as Intro;
// 3. Call the class from the namespace with the friendly name
$carIntro = new Intro();
echo $carIntro -> sayHello();
Result:
beep!
97
This is a diagram that depicts the folder structure after we have added the new class to the Car
directory:
98
99
In order for classes from the global scope to be used securely within a namespace, we need to precede
the name of such a class with a backslash.
For example, in the index.php file we need to put a backslash in front of the CarPrice class because
we want to use it from the global namespace:
require "src/Car/CarIntro.php";
require "src/Car/CarPrice.php";
use Acme\Car\CarIntro as Intro;
$carIntro = new Intro();
echo $carIntro -> sayHello();
// We use the backslash in front of the class name in order to call a class
//
from the global namespace
$carPrice = new \CarPrice();
echo $carPrice -> getQuote();
Result:
beep!
19500
Some other common instances in which there is a need to use the backslash before the class
name are for the built in PHP extensions PDO and DateTime, and for PHPs generic empty
class, stdClass.
100
<?php
namespace Acme\Car;
class CarPrice {
public function getQuote()
{
return 19500;
}
}
All the classes within the same directory need to have the same namespace.
Since we follow the good practice of giving the classes a namespace which follows the directory
structure all the classes within the same directory need to have the same namespace. In our example,
all the classes in the src/Car directory have the Acme\Car namespace.
We can now use the CarPrice class in index.php, alongside the CarIntro class:
// 1. Require both classes
require "src/Car/CarIntro.php";
require "src/Car/CarPrice.php";
// 2. Import the namespaces and give them a friendly name
use Acme\Car\CarIntro as Intro;
use Acme\Car\CarPrice as Price;
// 3. Use the methods in the context of their namespace
$carIntro = new Intro();
echo $carIntro -> sayHello();
$carPrice = new Price();
echo $carPrice -> getQuote();
Result:
beep!
19500
101
Conclusion
In this chapter, we learned how to give classes a namespace, and how to use the the namespaced
classes in our scripts.
In the next chapter, we will learn how to loosen the coupling between classes by using dependency
injection.
Suggested solutions
102
However, we can also import the classes with only one use:
use Acme\{
Car\CarIntro as Intro ,
Car\CarPrice as Price
};
And if we would like to also import a user class, we can still do so with the traditional syntax:
use Acme\Car\CarIntro as Intro;
use Acme\Car\CarPrice as Price;
use Acme\User;
Group use declarations is an alternative syntax that was introduced with PHP7, and it will not
damage or break your code in any way.
Dependency injection
One of the less understood subjects for fresh PHP programmers is that of dependency injection.
But dont worry! This chapter will explain the subject to you in the simplest way possible by first
explaining the problem and then showing you how to solve it.
103
Dependency injection
104
Although creating the human driver object inside the Car class might look like the right thing to do,
we are going to face a real problem the first time that we need to switch dependencies. For example,
if the technological advancements dictate us a car that is driven by a robot, we will find our self in
a problem since the Car class only knows how to handle human drivers.
The problem that stems from directly creating the driver object inside the Car class is also known
as tight coupling between classes, something that should be avoided as much as possible. In fact,
tight coupling is considered to be a bad practice for the following reasons:
The programmers need to be concerned with more than one class when they introduce new
classes to their code. In our example, if we would like to change the class on which the Car
class is dependent from HumanDriver to RobotDriver, except for introducing the new class to
our code, we also need to change the Car class so it can handle the new type of driver.
We will have difficulties in performing unit testing since it is meant to check one class at a
time.
In fact, when we do tight coupling between classes, we violate a fundamental principle of well
designed code called the single responsibility principle (SRP), according to which a class should
have only one responsibility. In order to respect this principle, the only code that the Car class needs
to handle is that of cars, without messing with any other code.
Dependency injection
105
We can now perform the dependency injection by first creating the Driver object and then injecting
this object into the newly created Car object through the constructor.
$humanDriver = new HumanDriver();
$car = new Car($humanDriver);
Result:
Bob
Now that we have seen how dependency injection works, lets see how easy it is to switch the
dependency from HumanDriver to RobotDriver, saving us from changing the code in the Car class.
First, lets write the RobotDriver class with the sayYourName method.
Dependency injection
106
class RobotDriver {
public function sayYourName($name)
{
return $name;
}
}
We can leave the Car class without any changes since it depends on a driver but does not require any
commitment to the type of the driver. The driver can be a robot, human, alien, etc. It really doesnt
matter as long as we supply a driver object.
class Car {
protected $driver;
// The constructor sets the value of the $driver
public function __construct($driver)
{
$this -> driver = $driver;
}
// A getter method that returns the driver object
//
from within the car object
public function getDriver()
{
return $this -> driver;
}
}
Now, we can create the driver object from the RobotDriver and inject it to the Car class without too
much of a hassle.
$robotDriver = new RobotDriver();
$car
= new Car($robotDriver);
echo $car -> getDriver() -> sayYourName("R2-D2");
Result:
R2-D2
It is easy to switch dependencies if only we adopt the good practice of injecting the
objects from the outside.
Dependency injection
107
The message to take home from this example would be that it is easy to switch dependencies if
only we avoid the bad practice of creating the objects on which the main class depends inside the
constructor, and adopt the good practice of injecting the objects on which the class depends from
the outside.
Now, we need to type hint the $driver parameter that we want to inject to the Cars constructor
since we want the injected object to implement the Driver interface.
Dependency injection
108
Lets test everything by making the Cars drivers say their names for both a human driver as well
as a robot driver.
$humanDriver = new HumanDriver();
$car = new Car($humanDriver);
echo $car -> getDriver() -> sayYourName("Bob");
$robotDriver = new RobotDriver();
$car = new Car($robotDriver);
echo $car -> getDriver() -> sayYourName("R2-D2");
Dependency injection
109
We will equip the Car class with a setDriver() method that is responsible for setting the $driver
value.
class Car {
protected $driver;
// The setDriver method sets
//
the value for the driver property
public function setDriver(Driver $driver)
{
$this -> driver = $driver;
}
public function getDriver()
{
return $this -> driver;
}
}
Now, we can create the driver object outside the car, inject it to the car with the setDriver() method,
and echo the drivers name.
Dependency injection
110
Result:
Bob
Conclusion
When we use dependency injection we pass the objects on which our class depends
to the class from the outside.
When we use dependency injection we pass the objects on which our class depends to the class
from the outside, instead of creating these objects within the class. By doing so, we make our code
more maintainable and flexible. It is also advisable to type hint the injected objects in order to make
it clear on which type of objects does the main class depend.
Dependency injection
111
15.1 Add to the Article class, a constructor method that gets the parameters of: $title
and $author and sets the classs properties accordingly.
15.2 Write to the class, a getter method that returns the articles title.
15.3 Add to the class, a getter method that returns the authors object.
15.4 Write another class with the name of Author, that has a protected property $name and
setter and getter methods that handle the property.
15.5 Now, first create the Author object, call it $author1, and then set its name to Joe.
15.6 Create the article object, call it $article1, and pass to it the title To PHP and Beyond
and the $author1 object that you have just created.
15.7 Write the code that returns the string: To PHP and Beyond by Joe.
Dependency injection
15.8 Improve your code by type hinting the $author object that you pass as a parameter
to the articles constructor. Clue: You need to first create an Authors interface, make the
Author class implement the interface, and then type hint the $author object that you inject
to the articles constructor.
Suggested solutions
112
We will feed the class with the nested array $dataFromCars, in which each nested array has two
values: the first value is for the distance traveled and the second value is for the gas consumption.
While the first and last nested arrays contain legitimate data, the second nested array provides zero
gas consumption and the third nested array has negative gas consumption.
113
114
$dataFromCars = array(
array(50,10),
array(50,0),
array(50,-3),
array(30,5)
);
Result:
5
Warning: Division by zero
-16.666666666667
6
From the result, we can see what might happen when we feed the class with faulty data. On the
second line, we got a nasty warning for trying to divide by zero while, on the third line, we got a
negative value (which is not what we would expect for gas efficiency). These are the kinds of errors
that we would like to suppress by using exception handling.
115
class FuelEconomy {
// Calculate the fuel efficiency
public function calculate($distance, $gas)
{
if($gas <= 0 )
{
// Throw custom error message, instead of an error
throw new Exception("The gas consumption cannot be less than
or equal to zero. You better drink coffee or take a break.");
}
return $distance/$gas;
}
}
If we run the code as it is written now, well get an even nastier error because, in order to handle
exceptions, we need to not just throw the exception but also to catch it.
116
}
return $distance/$gas;
}
}
// The data to feed the class with
$dataFromCars = array(
array(50,10),
array(50,0),
array(50,-3),
array(30,5)
);
// Create the object from the class and feed it
//
with the array values
foreach($dataFromCars as $data => $value)
{
// Try block handles the normal data
try
{
$fuelEconomy = new FuelEconomy();
echo $fuelEconomy -> calculate($value[0],$value[1]) . "<br />";
}
// Catch block handles the exceptions
catch (Exception $e)
{
// Echo the custom error message
echo "Message: " . $e -> getMessage() . "<br />";
}
}
Result:
5
Message: The gas consumption cannot be less than or equal to zero. You better drink coffee or take
a break.
Message: The gas consumption cannot be less than or equal to zero. You better drink coffee or take
a break.
6
Thanks to exception handling, we now get an elegant error message instead of the nasty one that
we got when not using exception handling.
117
Result:
5
Message: The gas consumption cannot be less than or equal to zero. You better drink coffee or take
a break.
File: C:\wamp\www\index.php
Line: 9
118
Message: The gas consumption cannot be less than or equal to zero. You better drink coffee or take
a break.
File: C:\wamp\www\index.php
Line: 9
6
The result above demonstrates that exception handling can provide more than custom messages. It
can provide beneficial data for tracing the exceptions.
In our example, lets now add the ability to write errors into the log file whenever an exception is
thrown:
foreach($dataFromCars as $data => $value)
{
try
{
$fuelEconomy = new FuelEconomy();
echo $fuelEconomy -> calculate($value[0],$value[1]) . "<br />";
}
catch (Exception $e)
{
// Echo the error message to the user
echo "Message: " . $e -> getMessage() . "<br />";
echo "<hr />";
// Write the
error_log($e
error_log($e
error_log($e
}
}
119
Conclusion
In this chapter, we have learned that exceptions are problems that a program might encounter but
is not meant to solve, and that exceptions are best handled by try - catch blocks that catch, throw,
and handle the exceptions with the Exception class.
120
Coding example
So far, in this chapter, we have seen how to handle a single exception. Now, in the following exercise,
well handle more than one exception.
This is the User class with the methods that set and get the user name and age.
class User {
private $name;
private $age;
public function setName($name)
{
// Trim the white spaces
$name = trim($name);
$this -> name = $name;
}
public function setAge($age)
{
// Cast into an integer type
$age = (int)$age;
$this -> age = $age;
}
public function getName()
{
return $this -> name;
}
16.2 Add to the setName() method a code that throws exception whenever the users name
is shorter than 3 letters. What is a suitable message that can be thrown?
16.3 Add to the setAge() method a code that throws exception whenever the users age is
less than or equal to 0.
This is the nested array that you can feed the class with.
$dataForUsers = array(
array("Ben",4),
array("Eva",28),
array("li",29),
array("Catie","not yet born"),
array("Sue",1.5)
);
16.4 Write a foreach loop (like the one we have already used in this chapter) that feeds the
array to the class, and handles the exceptions by echoing the custom error messages as well
as the file path and line number in which the exception was thrown.
Suggested solutions
121
122
123
* You can find the code for the sql table that is used in the examples in this chapters supplement
section.
The use of placeholders is known as prepared statements. We use prepared statements as templates
that we can fill later on with actual values.
2) Prepare the query:
$query = $dbh -> prepare($sql);
You can add a third parameter which filters the data before it reaches the database:
$query->bindParam(':name',$name,PDO::PARAM_STR);
$query->bindParam(':phone',$phone,PDO::PARAM_INT);
$query->bindParam(':city',$city,PDO::PARAM_STR);
$query->bindParam(':date',$date,PDO::PARAM_STR);
$name
$phone
$city
$date
=
=
=
=
"Joe";
"1231234567";
"New York";
date('Y-m-d');
124
$date
= date('Y-m-d');
125
126
127
6) Assign the data which you pulled from the database (in the preceding step) to a variable.
$results = $query -> fetchAll(PDO::FETCH_OBJ);
Here I used the parameter PDO::FETCH_OBJ that returns the fetched data as an object. If youd like
to fetch the data in the form of an array, use: PDO::FETCH_ASSOC.
7) Make sure that you were able to retrieve the data from the database, by counting the number of
records.
if($query -> rowCount() > 0){}
8) In case that the query returned at least one record, we can echo the records within a foreach loop:
128
> 0)
$result)
name . ", ";
city . ", ";
date_added;
> 0)
$result)
name . ", ";
city . ", ";
date_added;
129
6) Check that the query has been performed and that the database has been successfully updated.
130
131
6) Check that the query has been performed and that the records have been successfully deleted
from the database.
if($query -> rowCount() > 0)
{
$count = $query -> rowCount();
echo $count . " rows were affected.";
}
else
{
echo "No affected rows.";
}
$sql
132
133
Conclusion
Now that youve seen how easy it is to work with PDO, I hope that youll consider using it in your
projects instead of the outdated mysql and mysqli extensions.
17.2 Write a User class that can get the database connection, and save it into a private
property with the name of $dbCon.
17.3 Write into the User class the following methods that can work with the database:
insert method to insert a new user to the users table.
getAll that returns all the users.
getUserById to return only a single user.
updateUser to update user by id.
Suggested solutions
Supplement
The SQL code for the users table:
CREATE TABLE IF NOT EXISTS users (
id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
name varchar(60) DEFAULT NULL,
phone varchar(14) DEFAULT NULL,
city varchar(60) DEFAULT NULL,
date_added date DEFAULT NULL,
PRIMARY KEY (id)
)
134
.
As you can see in the following link: getcomposer.
Installing Composer on Windows machines is also not particularly difficult using a dedicated Wizard
(see the documentation).
https://getcomposer.org
https://getcomposer.org
135
How to use Packagist and Composer to integrate existing code libraries into your PHP apps?
136
We examine the installation by typing the following command into the command line:
$ composer
.
If Composer is properly installed, well see all the composer commands with a short description of
what they do.
Composer commands
At this stage, we expect to see a composer.phar file in the root directory of the website.
How to use Packagist and Composer to integrate existing code libraries into your PHP apps?
137
Well get back to the composr.json file later, but we first need to find a package to install in the
Packagist repository, which is found at packagist.org.
In the packagist.org website, type the name of the package that you want to download in the search
box. For the sake of this chapter, well search for the faker package which generates fake data for
our projects (something that can be most beneficial during the development stage of a website).
You will be shown a number of packages from which you need to choose the package that suits your
needs the best.
Click on a package to open the package page. Here you can find relevant information about the
package, including the latest version and dependencies. You need to copy the command to download
the latest stable version (see the picture below).
https://packagist.org
https://packagist.org
How to use Packagist and Composer to integrate existing code libraries into your PHP apps?
138
Back to the terminal, you need to navigate to the root directory of your app or website, and run the
command that you just copied from packagist.
$ composer require fzaninotto/faker
Once you press enter, Composer will start to auto-magically download the latest stable version of
the package that you require. It also downloads all the packages on which the package depends, and
generates an autoload file.
How to use Packagist and Composer to integrate existing code libraries into your PHP apps?
139
Composer installs the package, its dependencies, and generates an autoload file
At the end of the download process, when you navigate to the root directory, you will see a brand
new vendor directory that holds within it all the packages that Composer installed in your website.
{
"require": {
"fzaninotto/faker": "^1.5"
}
}
How to use Packagist and Composer to integrate existing code libraries into your PHP apps?
140
When you open the vendor folder, youll find the autoloader file (autoload.php) that comes free
of charge with the download. We require the autoloader in our scripts in order for the Composer
libraries to work.
<?php
require_once __DIR__ . '/vendor/autoload.php';
To activate the autoloader, you may need to type the following command into the command line:
$ composer dumpautoload -o
.
Lets write in the index.php file a code that tests if the package that we have just downloaded really
works:
<?php
require_once __DIR__ . '/vendor/autoload.php';
// Use the factory to create a Faker\Generator instance
$faker = Faker\Factory::create();
// Generate fake name
echo $faker->name;
// Generate fake address
echo $faker->address;
// Generate fake text
echo $faker->text;
How to use Packagist and Composer to integrate existing code libraries into your PHP apps?
141
.
This will download the new package, with all its dependencies to the vendor directory, as well as
update the composer.json file. Like so:
1
2
3
4
5
6
{
"require": {
"fzaninotto/faker": "1.4.0",
"monolog/monolog": "~1.13"
}
}
.
As a result of this command, Composer will automatically download all the updated versions of
the packages, including all the dependencies, straight to the project folder.
.
This will remove the package with all of it dependencies from the vendor directory.
How to use Packagist and Composer to integrate existing code libraries into your PHP apps?
142
Conclusion
I am sure that the combination of Packagist as a repository of PHP libraries and Composer as a
dependency manager can help any PHP project, as it has so faithfully been doing for several years
now.
In the next chapter, our PHP skills will take a big leap forward as we learn how to Composer autoload
the classes, including those that we download from Packagist.
But when working with our own classes (or with non-packagist classes) we may need to be
somewhat more savvy
Composer autoloading can work in one of two main ways: through direct autoloading
of classes or through the use of the PSR standards.
143
1
2
3
4
5
6
7
8
144
{
"autoload": {
"classmap": [
"path/to/FirstClass.php",
"path/to/SecondClass.php"
]
}
}
.
Now, we have to include the autoloader at the top of our scripts (e.g., index.php):
<?php
require "vendor/autoload.php";
In the same way that we autoload classes, we can autoload directories that contain classes also by
using the classmap key of the autoload:
1
2
3
4
5
6
7
8
{
"autoload": {
"classmap": [
"path/to/FirstClass.php",
"path/to/directory"
]
}
}
145
a. Put the classes that we want to autoload in a dedicated directory. For example, it is
customary to convene the classes that we write into a directory called src/, thus, creating
the following directory structure:
Directory structure
a. Give the classes a namespace. We must give all the classes in the src/ directory the same
namespace. For example, lets give the namespce Acme to the classes. This is what the Page
class is going to look like:
<?php
namespace Acme;
class Page
{
public function __construct()
{
echo "hello, i am a page.";
}
}
We give the same namespace Acme to all of the classes in the src/ directory.
c. Point the namespace to the src/ directory in the composer.json file. We point the directory
that holds the classes to the namespace in the composer.json file. For example, this is how we specify
in the composer.json file that we gave the namespace Acme to the classes in the src/ directory:
1
2
3
4
5
6
7
146
{
"autoload": {
"psr-4": {
"Acme\\":"src/"
}
}
}
$ composer dumpautoload -o
a. Import the namespace to your scripts. The scripts need to import the namespace as well as
the autoloader, e.g.,index.php:
<?php
require "vendor/autoload.php";
use Acme\Db;
use Acme\User;
use Acme\Page;
$page1 = new Page();
147
<?php
namespace Acme\Pages;
public class Page
{
function __construct()
{
echo "hello, i am a page.";
}
}
1
2
3
4
5
6
7
8
9
<?php
require "vendor/autoload.php";
use Acme\Db;
use Acme\User;
use Acme\Pages\Page;
148
Conclusion
As we demonstrated in the last two chapters, Composer is a powerful tool that can help us to both
manage and autoload our own classes as well as others. Now, that we have such a powerful tool
under our belt were entitled to fully enjoy the best that modern-day PHP has to offer!
149
150
Now, in the template file index.php, we can embed the variables from the controller into the HTML,
but first we need to include the controller file:
<?php require "controller.php"; ?>
<!doctype html>
<html>
<head>
</head>
<body>
<p>
BMW <?=$carsReviewed["Bmw"]["model"]?> is
<?=$carsReviewed["Bmw"]["expensiveOrNot"]?>
while Audi<?=$carsReviewed["Audi"]["model"]?> is
<?=$carsReviewed["Audi"]["expensiveOrNot"]?>.
</p>
</body>
</html>
Result:
BMW 2-Series is expensive while Audi A3 is not expensive.
Separating logic from presentation can improve efficiency when working in a team because it allows
the programmers to work on the logical part of the application and the designers to work on the
template, without interfering with each other.
151
The model
The part that interacts with the data source is called the Model and it has all the code
that handles databases.
We have seen how separating the logical part of the application from the template part can be very
beneficial, but we have still not handled the part of the application that interacts with the data
source.
The part that interacts with the data source is called the Model and it has all the code that handles
databases (and other data sources). The role of the model is to retrieve the information from the
database and maintain, update, or delete that information while keeping everything safe.
152
MVC explained
After the application gets the user data (for example, after the user feeds his data into a form and
submits it), the data is passed to the controller layer that processes the information and decides to
which of the models classes to transfer the data to, and the model itself filters the data and then
stores, updates, or deletes the records in the database.
The data can then make its way back from the model to the controller for further processing (e.g.
which page to redirect the user to or which message to present to the user) while the presentation
is handled and executed in the View.
153
class Model
{
// Store the data
private $carPrice;
// Set the data
public function setPrice($price)
{
$this -> carPrice = $price;
}
// Get the data
public function getPrice()
{
return $this -> carPrice;
}
}
The Controller class is the mediator. It gets the data about the Cars price from the Model and checks
if it is expensive.
class Controller {
private $model;
private $limit = 30000;
// Set the model so we can use its data
public function __construct(Model $model)
{
$this -> model = $model;
}
// Set the data in the module
public function setPrice($price)
{
$this->model->setPrice((int)$price);
}
// Some logic to check if the price is expensive
public function expensiveOrNot()
{
if($this->model->getPrice() > $this->limit) return "expensive";
154
The View class gets the data after it has been processed by the Controller, and outputs it to the user:
class View {
private $controller;
// Set the controller so we can use it
public function __construct(Controller $controller)
{
$this->controller = $controller;
}
// Output the data after processing it by the controller
public function output()
{
return $this->controller->expensiveOrNot();
}
}
Now we can implement the code. We feed the Model with the price, call the controller to perform
its logic, and output everything through the View:
// The data can come from the database
$priceToCheck = 31000;
// The data is retrieved by the model
$model1 = new Model();
$model1 -> setPrice($priceToCheck);
// We need the controller in order to process the data
$controller1 = new Controller($model1);
// We need the view in order to output the processed data
$view1 = new View($controller1);
echo $output = $view1 -> output();
Result:
expensive
The output can be embedded in the HTML.
155
Now, we need the controller to be able to transfer the data to the model, so we add to the controller
a setPrice() method that can set the price within the model.
class Controller {
private $model;
private $limit = 30000;
// Set the model so we can use its data
public function __construct(Model $model)
{
$this -> model = $model;
}
// Set the data in the module
public function setPrice($price)
{
$this->model->setPrice((int)$price);
}
// Some logic to check if the price is expensive
public function expensiveOrNot()
{
if($this->model->getPrice() > $this->limit) return "expensive";
return "not expensive";
}
}
Now we can make the ends meet and output the data:
156
Result:
not expensive
The output can be embedded in the HTML.
Conclusion
The MVC pattern is very important to PHP programmers because it forces us to separate the logical
part from the presentation part in our applications, and so helps us in maintaining and further
developing the application.
Epilogue
What have we learned?
In this book, we have learned the essentials of Object Oriented PHP. We started by understanding
what classes and objects are, as well as how to use them to encapsulate code from the rest of the
application. Additionally, we learned about inheritance as a means of reducing code duplication.
We also learned how to construct our application with the help of interfaces and polymorphism. In
the final part, we began scratching the surface of real-world applications with namespaces that will
allow the code to work with different code libraries, PDO as the database interface, and MVC as a
pattern by which we can construct our applications in a well-tested way.
By this point, I hope that you have a strong grasp of the object-oriented style of programming, which
should include the ability to answer the following questions:
1.
2.
3.
4.
157
Epilogue
158
Composer is the tool that lets you use the packages you want to download from the Packagist
repository. It provides you with autoloading, as well as dependency management, which means that
the packages you download to your application are automatically installed with the packages on
which they depend.
You need to know how to do automated testing of your code with PHPUnit framework being the
most common choice among PHP programmers.
You need to master at least one PHP framework with the most popular being Laravel, symfony,
CodeIgniter, Yii, and CakePHP. The Slim framework is also popular, and has the benefit of
being light weight and easy to learn. When you use a framework, you dont need to reinvent the
wheel every time that you start a new application; instead, you can use a well-tested code as the
foundation.
If you ever wondered how other programmers solve the same programmatic problems that you
toil endlessly upon? Or, better yet, if there exist already established solutions that may help you to
write your code in a better way, you probably need to learn design patterns, which are well tested
solutions to common programmatic problems that you may confront on a daily basis. There are
fewer than a couple dozen design patterns, some of the most beneficial patterns that you need to
learn are the Strategy, Factory, Singleton, Facade, and Decorator patterns.
Never stop learning. Learn new skills, gain new expertise, expand your abilities, and flourish in your
career.
Wishing you all the best!
https://getcomposer.org
https://phpunit.de
http://laravel.com
https://symfony.com
https://www.codeigniter.com
http://www.yiiframework.com
http://cakephp.org
http://slimframework.com
http://phpenthusiast.com/blog/strategy-pattern-the-power-of-interface
http://phpenthusiast.com/blog/the-factory-design-pattern-in-php
http://phpenthusiast.com/blog/the-singleton-design-pattern-in-php
http://phpenthusiast.com/blog/simplify-your-php-code-with-facade-class
http://phpenthusiast.com/blog/the-decorator-design-pattern-in-php-explained
Chapter 1 solutions
1.1 Which of these definitions best explains the term class?
A: A class is a collection of variables and functions working with these variables.
1.2 Which of these definitions best explains the term object?
A: An object gives us the ability to work with the class, and to have several instances of the same
class.
1.3 Which of these definitions best explains the term property?
B: A property is a variable within a class.
1.4 Which of these definitions best explains the term method?
A: A method is a function within a class.
1.5 Write what you think should be the class name, the names of the properties for the first and last
name, and the name of the method that returns hello.
class name: User
class properties: $firstName, $lastName
class method: hello()
1.6 Write the class User and add the properties:
class User {
public $firstName;
public $lastName;
}
159
Chapter 1 solutions
160
class User {
public $firstName;
public $lastName;
public function hello()
{
return "hello";
}
}
1.8 Create the first instance, and call it $user1. Use the new keyword to create an object from the
class.
class User {
public $firstName;
public $lastName;
public function hello()
{
return "hello";
}
}
1.9 Set the values for the first and last name to $user1.
class User {
public $firstName;
public $lastName;
public function hello()
{
return "hello";
}
}
161
Chapter 1 solutions
1.10 Get the user first and last name, and print it to the screen (with echo).
class User {
public $firstName;
public $lastName;
public function hello()
{
return "hello";
}
}
162
Chapter 1 solutions
1.12 Add another object, call it $user2, give it a first name of Jane and last name of Doe, then say
hello to the user.
class User {
public $firstName;
public $lastName;
public function hello()
{
return "hello";
}
}
Result:
hello, John Doe
hello, Jane Doe
Chapter 2 solutions
2.1 Which keyword would you use in order to approach the classs properties and methods from
within the class?
Answer : The $this keyword enables us to approach the classs own properties and methods from
within the class.
2.2 Add to the hello() method the ability to approach the $firstName property, so the hello()
method would be able to return the string hello, $firstName.
class User
// The
public
public
{
class properties
$firstName;
$lastName;
2.3 Create a new object with the first name of Jonnie and last name of Roe.
class User
// The
public
public
{
class properties
$firstName;
$lastName;
163
Chapter 2 solutions
2.4 Echo the hello() method for the $user1 object, and see the result.
class User
// The
public
public
{
class properties
$firstName;
$lastName;
164
Chapter 3 solutions
3.1 Add a register() method to the class that echoes the name of the user plus the verb registered.
class User {
// The class properties
public $firstName;
public $lastName;
// A method that says hello to the user $firstName
// The user $firstName property can be approached
//
with the $this keyword
public function hello()
{
return "hello, " . $this -> firstName;
}
// The register method
public function register()
{
echo $this -> firstName . " " . $this -> lastName . " registered.";
}
}
3.2 Add a mail() method to the class that echoes the string emailed.
class User
// The
public
public
{
class properties
$firstName;
$lastName;
165
Chapter 3 solutions
166
}
// The register method
public function register()
{
echo $this -> firstName . " " . $this -> lastName . " registered.";
}
// The mail method
public function mail()
{
echo " emailed.";
}
}
3.3 Add return $this to the register() method so that it can be chained to any other method in
the class.
class User
// The
public
public
{
class properties
$firstName;
$lastName;
Chapter 3 solutions
167
}
}
3.4 Create a new $user1 object with the first name of Jane and the last name of Roe. For this
object, chain the mail() method to the register() method and see the result.
class User
// The
public
public
{
class properties
$firstName;
$lastName;
Result:
Jane Roe registered. emailed.
Chapter 4 solutions
4.1 We use the private access modifier in order to:
D: We use the private access modifier in order to prevent code from outside the class scope from
interacting with the class properties and methods. The private access modifier, like the public access
modifier, is only relevant to properties and methods, and has no power on classes.
4.2 Create a new class property with the name of $firstName, and prevent any code from outside
the class from changing the property value by using the appropriate access modifier (private or
protected).
class User {
// We use the private access modifier in order to
//
prevent code from outside
//
the class from modifying the property's value
private $firstName;
}
4.3 Create a method to set the $firstName property value. Remember to use the right access modifier
(public/private).
class User {
private $firstName;
// A public setter method allows us to set the
//
$firsName property.
public function setFirstName($str)
{
$this -> firstName = $str;
}
}
168
Chapter 4 solutions
class User {
private $firstName;
// A public setter method allows us to set the
//
$firsName property
public function setFirstName($str)
{
$this -> firstName = $str;
}
// A public getter method allows us to return the
//
$firsName property
public function getFirstName()
{
return $this -> firstName;
}
}
169
Chapter 5 solutions
5.1 Add to the class a constructor method to set a value to the $firstName property as soon as the
object is created.
class User {
private $firstName;
private $lastName;
// Constructor function to set a single value
public function __construct($firstName)
{
$this -> firstName = $firstName;
}
}
5.2 Add to the constructor the ability to set the value of the $lastName property (remember that you
can pass to a method more than parameter).
class User {
private $firstName;
private $lastName;
// Constructor function to set more than one value
public function __construct($firstName,$lastName)
{
$this -> firstName = $firstName;
$this -> lastName = $lastName;
}
}
5.3 Add to the class a getFullName() public method that returns the full name.
170
Chapter 5 solutions
171
class User {
private $firstName;
private $lastName;
// Constructor function to set more than one value
public function __construct($firstName,$lastName)
{
$this -> firstName = $firstName;
$this -> lastName = $lastName;
}
public function getFullName()
{
return $this -> firstName . ' ' . $this -> lastName;
}
}
5.4 Create a new object, $user1, and pass to the constructor the values of the first and last name.
The first name is John and the last name is Doe (you may choose your preferred combination of
first and last name).
class User {
private $firstName;
private $lastName;
// Constructor function to set more than one value
public function __construct($firstName,$lastName)
{
$this -> firstName = $firstName;
$this -> lastName = $lastName;
}
public function getFullName()
{
return $this -> firstName . ' ' . $this -> lastName;
}
}
$user1 = new User("John", "Doe");
Chapter 5 solutions
class User {
private $firstName;
private $lastName;
// Constructor function to set more than one value
public function __construct($firstName,$lastName)
{
$this -> firstName = $firstName;
$this -> lastName = $lastName;
}
public function getFullName()
{
return $this -> firstName . ' ' . $this -> lastName;
}
}
$user1 = new User("John", "Doe");
echo $user1 -> getFullName();
Result:
John Doe
172
Chapter 6 solutions
6.1 Which keyword do we use in order to declare that one class inherits from another class?
C: In order to declare that a certain class is the child of another class we use the extends keyword
in the child class.
6.2 Which keyword do we use in order to declare that a method or property can only be used within
the parent class and its child classes?
B: The protected keyword allows access to methods and properties only from within the parent
class and its child classes.
6.3 We learned about three access control modifiers (public, private, and protected) that we use to
allow/restrict access to the code. In the following table, we will use V to mark that the code can
be accessed from a certain level, and X if it cannot be accessed.
Public methods and properties can be accessed from anywhere in the code.
Protected methods and properties can only be accessed from within the class and its child classes.
Private methods and properties can only be accessed from within the class itself.
6.4 Create a user class.
173
Chapter 6 solutions
174
class User {}
6.5 Add to the class a private property with the name of $username.
class User {
private $username;
}
6.6 Create a setter method that can set the value of the $username.
class User {
private $username;
public function setUsername($name)
{
$this -> username = $name;
}
}
6.8 Now, lets add to the Admin class some code. First, add a public method by the name of
expressYourRole, and make it return the string: "Admin".
class Admin extends User{
public function expressYourRole()
{
return strtolower(__CLASS__);
}
}
6.9 Add to the Admin class another public method, sayHello, that returns the string Hello admin,
XXX with the username instead of XXX.
Chapter 6 solutions
175
6.10 Create an object $admin1 out of the class Admin, set its name to "Balthazar", and say hello to
the user. Do you see any problem?
class User {
private $username;
public function setUsername($name)
{
$this -> username = $name;
}
}
Result:
Chapter 6 solutions
176
Result:
Hello admin, Balthazar
Chapter 6 solutions
177
For a more elegant solution, we may use a getter method inside the parent that can be used from
the child class.
class User {
private $username;
public function setUsername($name)
{
$this -> username = $name;
}
public function getUsername()
{
return $this -> username;
}
}
Chapter 7 solutions
7.1 Which keyword is used to declare a class or method as abstract?
C: abstract
7.2 Which keyword is used to declare a child class that inherits from an abstract class?
D: extends
7.3 What are the main reasons for using an abstract class in the code?
B: The main reason for using an abstract class is to commit the child classes to methods.
7.4 Can we create objects from abstract classes?
Answer: We cannot create objects from abstract classes.
7.5 Create an abstract class with the name of User, which has an abstract method with the name of
stateYourRole.
abstract class User {
abstract public function stateYourRole();
}
7.6 Add to the class a protected variable with the name of $username, and public setter and getter
methods to set and get the $username.
abstract class User {
abstract public function stateYourRole();
public function setUsername($name)
{
$this -> username = $name;
}
public function getUsername()
{
return $this -> username;
}
}
7.7 Create an Admin class that inherits the abstract User class.
178
Chapter 7 solutions
179
7.10 Create another class, Viewer that inherits the User abstract class. Define the method that should
be defined in each child class of the User class.
class Viewer extends User {
public function stateYourRole()
{
return strtolower(__CLASS__);
}
}
7.11 Create an object from the Admin class, set the username to Balthazar, and make it return the
string admin.
$admin1 = new Admin();
$admin1 -> setUsername("Balthazar");
echo $admin1 -> stateYourRole();
Result:
admin
Chapter 8 solutions
8.1 Which keyword should we use in order to implement an interface?
D: We should use the implements keyword in order to implement an interface.
8.2 Which of the following code types are allowed in an interface?
D: Interfaces can have methods and constants, but they cannot have properties.
8.3 Which of the following access modifiers is allowed for abstract methods in interfaces?
A: Methods in interfaces can only be public, because the nature of interfaces is to expose their
methods to the outside world.
8.4 Which of the following is valid inheritance?
E: A class can inherit from only 1 parent/abstract class, while it can implement more than 1 interface.
8.5 Create a User class with a protected $username property and methods that can set and get the
$username.
class User {
protected $username;
public function setUsername($name)
{
$this -> username = $name;
}
public function getUsername()
{
return $this -> username;
}
}
8.6 Create an Author interface with the following abstract methods that can give the user an array
of authorship privileges. The first method is setAuthorPrivileges(), and it gets a parameter of
$array, and the second method is getAuthorPrivileges().
180
181
Chapter 8 solutions
interface Author {
public function setAuthorPrivileges($array);
public function getAuthorPrivileges();
}
8.7 Create an Editor interface with methods to set and get the editors privileges.
interface Editor {
public function setEditorPrivileges($array);
public function getEditorPrivileges();
}
8.8 Create an AuthorEditor class that extends the User class, and implements both the Author and
the Editor interfaces.
class AuthorEditor extends User implements Author,Editor
{}
8.9 Create in the AuthorEditor class the methods that it should implement, and the properties that
these methods force us to add to the class.
class AuthorEditor extends User implements Author,Editor
private $authorPrivilegesArray = array();
private $editorPrivilegesArray = array();
public function setAuthorPrivileges($array)
{
$this -> authorPrivilegesArray = $array;
}
public function getAuthorPrivileges()
{
return $this -> authorPrivilegesArray;
}
public function setEditorPrivileges($array)
{
$this -> editorPrivilegesArray = $array;
}
Chapter 8 solutions
182
8.10 Now, lets create an object with the name of $user1 from the class AuthorEditor, and set its
username to Balthazar.
$user1 = new AuthorEditor();
$user1 -> setUsername("Balthazar");
8.11 Set in the $user1 object an array of authorship privileges, with the following privileges: write
text, add punctuation.
$user1 = new AuthorEditor();
$user1 -> setUsername("Balthazar");
$user1 -> setAuthorPrivileges(array("write text","add punctuation"));
8.12 Set in the $user1 object an array with the following editorial privileges: edit text, edit
punctuation.
$user1
$user1
$user1
$user1
= new AuthorEditor();
-> setUsername("Balthazar");
-> setAuthorPrivileges(array("write text", "add punctuation"));
-> setEditorPrivileges(array("edit text", "edit punctuation"));
8.13 Use the following code to get the $user1 name and privileges:
$userName = $user1 -> getUsername();
$userPrivileges = array_merge($user1 -> getAuthorPrivileges(),
$user1 -> getEditorPrivileges());
echo $userName . " has the following privileges: ";
foreach($userPrivileges as $privilege)
{
echo " {$privilege},";
}
echo ".";
Result:
Balthazar has the following privileges: write text, add punctuation, edit text, edit punctuation,.
Chapter 9 solutions
9.1 Which of these sentences best describes the polymorphism principle in PHP?
A: According to the Polymorphism principle, methods that serve the same functionality in different
classes should have the same name.
9.2 Add to the class concrete methods to set and get the number of articles.
abstract class User {
protected $scores
= 0;
protected $numberOfArticles = 0;
public function setNumberOfArticles($int)
{
// Cast to integer type
$numberOfArticles = (int)$int;
$this -> numberOfArticles = $numberOfArticles;
}
public function getNumberOfArticles()
{
return $this -> numberOfArticles;
}
}
9.3 Add to the class the abstract method: calcScores(), that performs the scores calculations
separately for each class.
abstract class User {
protected $scores
= 0;
protected $numberOfArticles = 0;
public function setNumberOfArticles($int)
{
// Cast to integer type
$numberOfArticles = (int)$int;
$this -> numberOfArticles = $numberOfArticles;
}
183
Chapter 9 solutions
184
9.4 Create an Author class that inherits from the User class. In it create a concrete calcScores()
method that returns the number of scores from the following calculation:
class Author extends User {
public function calcScores()
{
return $this -> scores =
$this -> numberOfArticles * 10 + 20;
}
}
9.5 Also create an Editor class that inherits from the User class. In it create a concrete calcScores()
method that returns the number of scores from the following calculation:
class Editor extends User {
public function calcScores()
{
return $this -> scores =
$this -> numberOfArticles * 6 + 15;
}
}
9.6 Create an object, $author1, from the Author class, set the number of articles to 8, and echo the
scores that it gained.
$author1 = new Author();
$author1 -> setNumberOfArticles(8);
echo $author1 -> calcScores();
9.7 Create another object, $editor1, from the Editor class, set the number of articles to 15, and echo
the scores that it gained.
Chapter 9 solutions
Result:
100
105
185
Chapter 10 solutions
10.1 Type hinting can check if the types of values that are passed to functions belong to the following
data types:
C : Complex types (arrays and objects) type hinting is supported in both PHP 5 and 7, while scalar
type hinting (int, float, string, bool) is only supported in PHP 7.
186
Chapter 11 solutions
11.1 Create a User interface with set and get methods for both a $username property, as well as for
a $gender property.
interface User {
public function setUsername($username);
public function getUsername();
public function setGender($gender);
public function getGender();
}
187
Chapter 11 solutions
188
}
}
public function getGender()
{
return $this -> gender;
}
}
11.3 Create function to add Mr. or Mrs. to the username. When writing the function make sure
to type hint it correctly, so it can only get the types it is expected to.
function addMrOrMrsToUsername(User $user)
{
$userName
= $user -> getUsername();
$userGender = $user -> getGender();
if($userGender === 'female')
{
return "Mrs. " . $userName;
}
else if($userGender === 'male')
{
return "Mr. " . $userName;
}
return $userName;
}
11.4 Run the code against a user with the name of Jane and against another user with the name of
Bob.
$user1 = new Commentator();
$user1 -> setUsername("Jane");
$user1 -> setGender("female");
echo addMrOrMrsToUsername($user1);
$user2 = new Commentator();
$user2 -> setUsername("Bob");
$user2 -> setGender("male");
echo addMrOrMrsToUsername($user2);
Chapter 11 solutions
Result:
Mrs. Jane
Mr. Bob
189
Chapter 12 solutions
12.1 The use of static methods and variables is appropriate in the following cases
Answer: B : We might consider the use of static methods and variables when we need utility
methods, with some common uses being: counters, sanitation, encryption, unit conversion, and any
other methods that only give services to our programs main classes.
190
Chapter 13 solutions
13.1 Which of the following keywords is used to define a trait?
C : the keyword trait is used to define a trait.
13.2 Which of the following types can be found within a trait?
D : Within a trait, we can find all of the types such as abstract methods, concrete methods, properties,
and constants. Having all of these types inside a trait is very powerful. However, good traits are short
and concise, so be sure not to bloat your traits with a code which better resides in your classes.
*13.3** Is it appropriate to use traits in a scenario in which all of the child classes of an interface
need the same methods?
In the case that all of the child classes of an interface use the same methods, we put the methods
in an interface. We consider the use of traits in those cases in which only some of the child classes
(and not all of the child classes) need to use a certain method.
13.4 Write an interface with the name of User.
interface User {}
13.5 Write three classes to implement the User interface: Author, Commentator and Viewer.
interface User {}
class Author implements User {}
class Commentator implements User {}
class Viewer implements User {}
13.6 Add a trait with the name of Writing that contains an abstract method with the name of
writeContent().
trait Writing {
abstract public function writeContent();
}
13.7 Use the trait Writing in the Author class, and implement its abstract method by making it return
the string Author, please start typing an article.
191
Chapter 13 solutions
192
13.8 Use the trait Writing in the Commentator class, and implement its abstract method by making
it return the string Commentator, please start typing your comment.
class Commentator implements User {
use Writing;
public function writeContent()
{
return "Commentator, please start typing your comment...";
}
}
13.9 Run the code you have just written and see the result.
$author1 = new Author();
echo $author1 -> writeContent();
$commentator1 = new Commentator();
echo $commentator1 -> writeContent();
Result:
Author, please start typing an article
Commentator, please start typing your comment.
Chapter 14 solutions
14.1 What are the main reasons for using namespaces?
D : The main reasons for the use of namespaces is to group related code and avoid name collisions
between libraries.
14.2 Which keyword is used to define a namespace?
B: The keyword namespace is used to define a namespace.
14.3 Which keyword is used to import a namespace?
A : The keyword use is used to import a namespace.
193
Chapter 15 solutions
15.1 Add to the Article class, a constructor method that gets the parameters of: $title and $author
and sets the classs properties accordingly.
class Article {
protected $title;
protected $author;
public function __construct($title, $author)
{
$this -> title = $title;
// The object is injected to the class
$this -> author = $author;
}
}
15.2 Write to the class, a getter method that returns the articles title.
class Article {
protected $title;
protected $author;
public function __construct($title, $author)
{
$this -> title = $title;
// The object is injected to the class
$this -> author = $author;
}
public function getTitle()
{
return $this -> title;
}
}
194
Chapter 15 solutions
195
15.3 Add to the class, a getter method that returns the author object.
class Article {
protected $title;
protected $author;
public function __construct($title, $author)
{
$this -> title = $title;
// The object is injected to the class.
$this -> author = $author;
}
public function getTitle()
{
return $this -> title;
}
public function getAuthor()
{
return $this -> author;
}
}
15.4 Write another class with the name of Author, that has a protected property $name and setter
and getter methods that handle the property.
class Author {
protected $name;
public function setName($name)
{
$this -> name = $name;
}
public function getName()
{
return $this -> name;
}
}
15.5 Now, first create the Author object, call it $author1, and then set its name to Joe.
Chapter 15 solutions
196
15.6 Create the article object, call it $article1, and pass to it the title To PHP and Beyond and the
$author1 object that you have just created.
$title = "To PHP and Beyond";
$article1 = new Article($title,$author1);
15.7 Write a code that returns the string: To PHP and Beyond by Joe.
echo $article1 -> getTitle() . ' by ' .
$article1 -> getAuthor() -> getName();
Result:
To PHP and Beyond by Joe
In this code example, instead of creating the author object inside the Article class, we created it
outside the class, and then injected it into the class with the constructor. (The same result can be
achieved by using a setter method.)
15.8 It is also highly advisable to typehint the injected objects. For this purpose, we need to first
write an Authors interface and then make the Author class implement that interface.
interface Authors {
public function setName($name);
public function getName();
}
class Author implements Authors {
protected $name;
public function setName($name)
{
$this -> name = $name;
}
public function getName()
{
return $this -> name;
}
}
Chapter 15 solutions
Now, we need to type hint the $author parameter that is passed to the Article class.
class Article {
protected $title;
protected $author;
public function __construct($title, Author $author)
{
$this -> title = $title;
// The object is injected to the class.
$this -> author = $author;
}
public function getTitle()
{
return $this -> title;
}
public function getAuthor()
{
return $this -> author;
}
}
Result:
To PHP and Beyond by Joe
197
Chapter 16 solutions
16.1 In which of the following cases would you use exception handling?
B : We use exception handling to suppress errors outside the scope of the program in a tested code,
and not in order to hide our own bugs or to replace if-then blocks.
16.2 Add to the setName() method a code that throws exception whenever the users name is shorter
than 3 letters. What is a suitable message that can be thrown?
class User {
private $name;
private $age;
public function setName($name)
{
$name = trim($name);
if(strlen($name) < 3)
{
throw new Exception("The name should be at least 3 characters long."\
);
}
$this -> name = $name;
}
public function setAge($age)
{
$this -> age = $age;
}
public function getName()
{
return $this -> name;
}
public function getAge()
{
return $this -> age;
198
Chapter 16 solutions
199
}
}
16.3 Add to the setAge() method a code that throws exception whenever the users age is less than
or equal to 0.
class User {
private $name;
private $age;
public function setName($name)
{
$name = trim($name);
if(strlen($name) < 3)
{
throw new Exception("The name should be at least 3 characters long."\
);
}
$this -> name = $name;
}
public function setAge($age)
{
$age = (int)$age;
if($age < 1)
{
throw new Exception("The age cannot be zero or less.");
}
$this -> age = $age;
}
public function getName()
{
return $this -> name;
}
public function getAge()
{
Chapter 16 solutions
200
16.4 Write a foreach loop (like the one we have already used in this tutorial) that feeds the array to
the class, and handles the exceptions by echoing the custom error messages as well as the file path
and line number in which the exception was thrown.
$dataForUsers = array(
array("Ben",4),
array("Eva",28),
array("li",29),
array("Catie","not yet born"),
array("Sue",1.5)
);
foreach($dataForUsers as $data => $value)
{
try
{
$user = new User();
$user -> setName($value[0]);
$user -> setAge($value[1]);
echo $user -> getName() . " is " . $user -> getAge() . " years old. <br \
/>";
}
catch (Exception $e)
{
echo "Error: " . $e -> getMessage() . " in the file: " . $e -> getFile()
. " on line: " . $e -> getLine() . "<hr />";
}
}
Chapter 16 solutions
Error: The age cannot be zero or less. in the file: C:\wamp\www\index.php on line: 25
Sue is 1 years old.
201
Chapter 17 solutions
17.1 Write a class with the name of Db that can connect with the database.
// DB credentials.
define('DB_HOST','localhost');
define('DB_USER','root');//database username
define('DB_PASS','');// database passord
define('DB_NAME','testing'); //database name
class Db {
// The PDO object.
private $dbh;
// Establish database connection
// or display an error message.
function __construct()
{
try
{
$this->dbh = new \PDO("mysql:host=".DB_HOST.";dbname=".DB_NAME,
DB_USER, DB_PASS,
array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"));
}
catch (PDOException $e)
{
exit("Error: " . $e->getMessage());
}
}
// We need a method to get the database handler
// so it can be used outside of this class.
function get()
{
return $this->dbh;
}
// Set the PDO object to null to close the connection.
function close()
202
203
Chapter 17 solutions
{
$this->dbh = null;
}
}
17.2 Write a User class that can get the database connection, and save it into a private property with
the name of $dbCon.
class User {
private $tableName = 'users';
private $dbCon;
// First, save the connection in a private property.
function __construct($dbCon)
{
$this->dbCon = $dbCon;
}
}
17.3 Write into the User class the methods that can work with the database.
class User {
private $tableName = 'users';
private $dbCon;
// First, establish the connection with the database.
function __construct($dbCon)
{
$this->dbCon = $dbCon;
}
// Insert new user to the database.
function insert($name,$phone,$city)
{
// The insert query.
$sql = "INSERT INTO `{$this->tableName}`
(`name`,`phone`, `city`, `date_added`)
VALUES
(:name,:phone,:city,:created)";
// Bind and filter.
$query = $this->dbCon->prepare($sql);
204
Chapter 17 solutions
$query->bindParam(':name',$name,PDO::PARAM_STR);
$query->bindParam(':phone',$phone,PDO::PARAM_STR);
$query->bindParam(':city',$city,PDO::PARAM_STR);
$now = date('Y-m-d');
$query->bindParam(':created',$now,PDO::PARAM_STR);
function getUserById($id)
{
$sql = "SELECT * FROM `{$this->tableName}` WHERE `id` = :id LIMIT 1";
$query = $this->dbCon->prepare($sql);
$query -> bindParam(':id', $id, PDO::PARAM_INT);
$query -> execute();
$results = $query -> fetchAll(PDO::FETCH_OBJ);
if($query -> rowCount() < 1) return false;
return
$results[0];
205
Chapter 17 solutions
{
$sql = "SELECT * FROM `{$this->tableName}` WHERE 1";
$query = $this->dbCon->prepare($sql);
$query -> bindParam(':id', $id, PDO::PARAM_INT);
$query -> execute();
$results = $query -> fetchAll(PDO::FETCH_OBJ);
if($query -> rowCount() < 1) return false;
return $results;
}
function updateUser($id,$array)
{
$sql = "UPDATE `{$this->tableName}` SET ";
$columns = array();
foreach($array as $fieldName => $value)
{
$columns[] = "`{$fieldName}` = :{$fieldName}";
}
$sql .= implode(',',$columns);
$sql .= ' WHERE `id` = :id';
$query = $this->dbCon->prepare($sql);
Chapter 17 solutions
return $id;
}
function delete($id)
{
$sql = "DELETE FROM `{$this->tableName}` WHERE `id`=:id";
$query = $this->dbCon->prepare($sql);
$query -> bindParam(':id', $id, PDO::PARAM_INT);
$query -> execute();
if($query -> rowCount() < 1) return false;
return true;
}
}
206
Chapter 17 solutions
207