Modern Application Development with PHP
Modern Application Development with PHP
Tom Oram
Buy on Leanpub

Preface

I have been working professionally with PHP since 2000. In that time I have seen it grow from a basic scripting language which allowed you to hack your ideas together in version 3, to something that resembled a fully featured language in version 4, through to actually becoming that fully featured language in version 5.

One of the fantastic features of PHP is that it’s so easy to get up and running quickly; you can easily add some dynamic elements to your existing HTML page with very little knowledge or experience. However, this is also a problem. Since anyone can start piecing together snippets of PHP code to get something to work, there are many people out there who are writing bad PHP code as they have never learnt how to program properly. Badly written code is often broken, very hard to add new functionality to, hard to maintain and rarely scalable.

In this book I hope to incorporate many programming methodologies, techniques and tools and apply them in the context of PHP to create a well designed application. These include Object Oriented Programming, Design Patterns, elements from Domain Driven Design, Refactoring, The SOLID Principals, Test Driven Development and Behaviour Driven Development. If these are all new to you, then this will be quite a ride.

I do not intend to cover any of these topics extensively. There are already many great books and resources covering all of them already and written by far cleverer people than myself. Therefore, I encourage you to read and learn more about all these subjects further. This book should, however, provide a great introduction to many of these methodologies, techniques and tools and show you how to get started quickly using them with PHP.

This book aims to introduce you to what you need to start building a well designed, manageable, and extensible medium size PHP application. The approach and process of working throughout this book should also fit very well into an Agile process of working. However, it will only deal with the actual development and architecture of the project rather than the full planning, communication and team management aspects included in the Agile way of working.

The architecture of the application we will be building in this book is a fairly common approach. It will not be based on any frameworks, but we will make use of some later on to see how frameworks can be very useful tools. In my mind this is how modern frameworks should be used. This architecture and approach to PHP application design is one we often use at the company I work for and is a tried and tested approach.

So finally, who is this book for? Firstly this is not an introduction to PHP. I assume you are already familiar with the language; you should be able to use classes and at least understand what an interface is. You have probably built at least one medium scale application but may not really know a lot about software design principles. If you have less experience than this you may struggle to keep up. If you have more then there may be less to be learnt from this book but hopefully it will still be helpful.

Source Code

The example source code for this book is included as part of the Leanpub purchase. You can download it via your Leanpub Dashboard.

Discussing Book Content

I have created a Google Group which can be used by readers of this book to discuss the ideas and content. This group can be found at:

https://groups.google.com/forum/#!forum/modern-application-development-in-php

Getting in Contact

I’d love to hear from you! Whether it’s about something in the book which you didn’t understand, think I could improve or didn’t agree with, or if you’d like to share how you do things differently, or even just to talk about software design in general then please get in touch.

You can find me on:

Twitter: @tomphp Email: tom@x2k.co.uk Skype: x2kmusic

Thanks

Many people have contributed to the creation of this book, as well as to my journey to get to this point of creating it. I would like to say thanks to:

My parents for inspiring and encouraging me to do positive things in my life. My collegues Felix and Rob for our daily debates and mutual encouragement to develop our skills further. John and Jamie for employing me in this industry and John for all his mentoring. George and Ollie for engaging with lengthy technical phone calls. Matthew for his inspiration and support to create this book. Rob, Felix, Lowri, Loki, Peter, Lee and Steph for pointing out errors and typos.

Prerequisites

This section of the book makes sure you have all the knowledge and tools which will be needed to progress through the rest of the book. It will cover a lot of topics briefly; the idea is to give you enough information on each topic for you to progress through this book, however, each topic is pretty deep so I don’t want to try and cover any of them completely. Many of them also have great books covering that topic exclusively and I encourage you to learn more about each of them yourself.

Terms and Conventions

Some Terms

Before getting started, I’d just like to introduce a few terms which I’ll be using in this book. If you’re used to reading about software development and architecture, then these may seem quite obvious. But if this is you’re first real entry point into these topics, then it’s probably useful to point these out now.

Stakeholder

When I talk about the stakeholder, I’m referring to the person (or persons) responsible for requesting the features you have to build into the application. If you’re a freelancer and you’re building a application for one of your clients, or if you work for a development company and you’re working on a team building an application for one of the company’s clients, then the client is the stakeholder. If your working in-house at a company, and you’re developing software for the employees, and the management team are telling you what needs to be built: then the management team are the stakeholders.

Basically, the stakeholders are the people who will pay you or your company if you build what they want. They choose what features are needed, and you have to keep them happy!

Domain

The domain is the real world process or environment which you are trying to translate into software. If you are building an e-commerce application, then the domain is the sales process.

Every project’s domain will be unique. The sales process of a small manufacturer with 10 products will be different to that of a company selling thousands of products from multiple warehouses.

The domain is considered to be the problem space. This is because it contains the problems which you need to solve in order to model it in software.

Domain Model

The domain model is the solutions to the domain’s problems, it is considered to be the solutions space. The domain model is the core of your application and it models just the domain. It does not include the User Interface, the Database Layer, a Framework, API requests; it is a pure model of the data and logic in the domain.

A bit later on I’ll introduce Domain Driven Design which is a process that holds the design of the domain model at utmost importance when creating software.

Conventions

In this book I will often instruct you to run commands in the terminal. Whenever I show a command to be run, it will be in fixed width text and preceded by a ‘$’ symbol, like this:

1 $ ls -l

When executing the command, do not include the $ symbol. For the example above, simply type ls -l into the terminal window, then press the Enter key on your keyboard.

Other times I will show the output of a command executed in the terminal. In this case I’ll use the same fixed with font, but there will be no preceding $, like so:

1 total 13640
2 -rw-rw-r-- 1 tom tom      142 Aug 20 23:49 LICENSE.md
3 drwxrwxr-x 4 tom tom     4096 Oct 18 14:15 manuscript
4 -rw-rw-r-- 1 tom tom      956 Aug 20 23:56 README.md
5 -rw-rw-r-- 1 tom tom 13952786 Sep 24 22:25 tags

Finally, there are times where I’ll show the command and the output in one block of text. The commands will be preceded by the $ symbol, and the output will be in the lines which follow without the $ symbol:

1 $ ls -l
2 total 13640
3 -rw-rw-r-- 1 tom tom      142 Aug 20 23:49 LICENSE.md
4 drwxrwxr-x 4 tom tom     4096 Oct 18 14:15 manuscript
5 -rw-rw-r-- 1 tom tom      956 Aug 20 23:56 README.md
6 -rw-rw-r-- 1 tom tom 13952786 Sep 24 22:25 tags

Everything else should hopefully be self explanatory.

Next we’ll look at the tools you will need to work through this book.

The Development Environment

First up I will be using a Linux system in all my examples, therefore most of the content in terms of using the command line and configuration should translate directly if you’re a Mac OS X user. If you’re a Windows user things may be a bit different but shouldn’t be too hard to work out.

Requirements

The only real requirement for working through this book is that you are using PHP 5.5 or above and the SQLite extension. Throughout this book we will be using PHP both from the command line and in a webserver environment.

Install PHP and SQLite on Ubuntu easily by running:

1 $ sudo apt-get install php5-cli php5-sqlite

When working in a web environment I will be using a tool called Vagrant, which runs the development environment in a virtual machine on the computer. This removes the need to set up and configure a webserver (and database servers) directly on the development computer. This is the way I would recommend working. However, if you do want to manually set up the relevant webserver and database servers on your development machine then you can do that, but you’ll have to work that out yourself.

Vagrant

Vagrant is a neat little tool. It allows many developers working on the same project to run a local copy of the project’s environment easily without having to install all the project’s dependencies on their development machines. It does this by building and running a virtual machine from a config file included in the project.

Vagrant itself simply instructs a virtualisation provider on what type of virtual machine to create and then uses a configuration automation system to configure that virtual machine.

Different providers, such as VMWare, are available for use with Vagrant but I will be using VirtualBox.

Also, different configuration automation systems, such as Chef and Puppet, can be used with Vagrant. I am choosing to use Ansible just because I prefer the syntax.

Installing

In order to use Vagrant you will need to install:

I recommend that you install both Vagrant and VirtualBox by downloading the distribution packages directly from their websites so you get the current versions.

With Ansible, you need to make sure you have an up to date version. On Ubuntu I tend to install it via Rodney Quillo’s PPA since it’s more up to date than the version in the Software Center.

Creating a Vagrant Config for PHP Development

Once you have Vagrant, VirtualBox and Ansible installed, it’s time to build a Vagrant configuration.

It’s not hard to build a Vagrant config file by hand, or to build the config automation scripts. However, it is a bit tedious, takes some learning, and is not really something this book intends to cover. Luckily there are some fantastic online tools available which make this process a lot easier. Since we want to build a PHP development environment and we’re going to use Ansible. We will use a fantastic tool called Phansible to create our config for us.

Phansible

First, open http://www.phansible.com/ in your browser. You will see a form asking questions about the development environment that you want to create. For this example choose the following options:

Options Value
Operating System Ubuntu Trusty Tahr (14.04) 64
Name VagrantExample
IP Address 192.168.5.10
Memory 512
Shared Folder ./
Webserver Apache + PHP5
PHP Version 5.6

You can use a different local IP address if you want, but remember it, since we’ll need to use it shortly.

Ignore the Database and Package settings for now, and finally choose an appropriate Timezone.

Next, click the Generate button at the bottom of the form, and save the generated .zip file to your hard drive. I saved my file to /home/tom/Downloads/phansible_VagrantExample.zip.

Creating the Project

Now that we have generated the Vagrant configuration, let’s create a PHP project and add the Vagrant configuration to it.

At your terminal, cd to where ever you want to create your project:

1 $ cd /home/tom/Projects

Next, create a directory for your new project, and cd into it:

1 $ mkdir VagrantExample
2 $ cd VagrantExample

Now create a file inside this directory called index.php, and add the following content, using your favourite IDE or text editor:

index.php


1 <?php
2 
3 echo 'Hello wonderful World!';

Next, unpack the contents of the Vagrant configuration .zip file that we downloaded from the Phansible website earlier,

1 $ unzip /home/tom/Downloads/phansible_VagrantExample.zip

Finally, while still inside the project’s directory and with your computer connected to the Internet, run:

1 $ vagrant up

This may take some time, and you may be prompted to enter your password to allow Vagrant to sudo to update some config files. Just be patient.

When it is done, open your browser and enter the IP address we selected earlier into the location bar like so:

http://192.168.5.10/

If all has gone to plan you should see Hello wonderful World! displayed on the page! Success! - we have created a PHP development environment for our project without installing or configuring a webserver on our local machine.

Once you have marvelled in the glory of Vagrant you can shut down the virtual machine by running the following command at your terminal:

1 $ vagrant halt

Shutting Down

I have found that if I forget to shutdown my virtual machines before I try to shut down my computer, it hangs during the shut down process. If you have a solution to this problem I’d love to hear it!

Getting up to Speed with PHP

As I said previously, this book assumes you are already familiar with PHP. In this chapter I will quickly cover a few newer additions to PHP, as well as a few tools and techniques which you will need to know about to continue with this book.

I don’t intend to go into anything in too much depth. It will contain just enough information the things we will be using. Therefore, I encourage you to research them further yourself.

Namespaces

If namespaces are new to you then the easiest analogy I can think of is that they are like folders for your code. Using them means you can have 2 or more classes with the same name in different namespaces - in the same way that you can have 2 or more files with the same name in different folders.

Without covering all the details of PHP namespaces here, I will quickly cover the aspects of them which we will be using.

Firstly, in order to define a class inside a specific namespace, you use the namespace statement on the first line of the file containing the class. Like so:

Class defined inside namespace


1 <?php
2 
3 namespace MyApp\Entity;
4 
5 class Contact
6 {
7     // ...
8 }

This defines the class Contact inside the Entity namespace which is inside the MyApp namespace. Namespaces are separated by backslashes.

To use a class inside code which in the same namespace, you can simply refer to it by name:

Using a class defined in the current namespace


1 <?php
2 
3 namespace MyApp\Entity;
4 
5 $contact = new Contact();

To use a class inside code in a different namespace, you can refer to it by its Fully Qualified Class Name (FQCN). Like so:

Referencing a class by its FQCN


1 <?php
2 
3 namespace MyApp;
4 
5 $contact = new \MyApp\Entity\Contact();

You can also refer to a class in a sub-namespace relative to the current namespace. Like so:

Referencing a class by its relative namespace


1 <?php
2 
3 namespace MyApp;
4 
5 $contact = new Entity\Contact();

Finally, you can pull a class from a different namespace into scope with the use statement. Add this at the top of the file just after the namespace statement. This is the way I prefer in most situations - here’s an example:

The use statement


1 <?php
2 
3 namespace MyApp;
4 
5 use MyApp\Entity\Contact;
6 
7 $contact = new Contact();

One final thing: if you want to use a class from one namespace in another namespace which already has a class with the same name in it, then you can rename the one you’re importing with the as keyword. Like so:

Aliasing an imported class


 1 <?php
 2 
 3 namespace MyApp\Form;
 4 
 5 use MyApp\Entity\Contact as ContactEntity;
 6 
 7 class Contact
 8 {
 9     public function __construct(ContactEntity $entity)
10     {
11         // ...
12     }
13 
14     // ...
15 }

It’s all pretty simple really right? That’s everything you’ll need to know about namespaces to continue with this book. However, if you do want to learn more about them, then the full documentation for PHP namespaces can be found in the manual.

Typehints

PHP is a dynamically typed language. It has a few basic, scalar types:

Scalar types in PHP


1 <?php
2 
3 42; // integer
4 
5 12.5; // float or double
6 
7 'abc123'; // string
8 
9 false; // boolean

It also has arrays, callables, resources and any user defined classes or interfaces, which are all also types.

Being a dynamically typed language means that a variable or function argument can contain any type of value at any time (this also goes for function return types):

Dynamic typing example


 1 <?php
 2 
 3 function fn($p)
 4 {
 5     return $p;
 6 }
 7 
 8 class C1
 9 {
10 }
11 
12 class C2
13 {
14 }
15 
16 $x = 42; // $x contains an integer
17 
18 $x = 12.5; // now $x contains a float
19 
20 $y = fn(123); // $p in fn() contains an integer and $y contains an integer
21 
22 $y = fn(false); // $p in fn() contains a boolean and $y contains a boolean
23 
24 $c = new C1(); // $c contains a C1 instance
25 
26 $c = new C2(); // $c contains a C2 instance

In contrast: in a statically typed language a variable, function argument or return value can only ever be the type it is defined to contain. If another type is assigned it will either cause an error, or it will get converted. Here’s a C++ version of the last example:

Static typing example (in C++)


 1 int fn(int p) {
 2     return p;
 3 }
 4 
 5 class C1 {
 6 };
 7 
 8 class C2 {
 9 };
10 
11 int main() {
12     int x = 42; // x contains an integer
13 
14     x = 12.5; // x contains 12, it keeps only the integer part
15 
16     y = fn(123); // p in fn() contains an integer and y contains an integer
17 
18     y = fn(false); // p in fn() contains 0 and y contains 0
19 
20     C1 *c = new C1(); // c contains a C1 instance
21 
22     c = new C2(); // this is an error as c can only contains instances of C1
23 }

Statically typed languages have great benefits. Because you always know what type everything is, there’s never a chance of you doing something to a variable which is not allowed to be done the type it contains. On the other hand, dynamically typed languages let you get on and do things quickly and without having to worry about how to work with type constraints.

Since static typing does have benefits, PHP introduced typehints on function arguments. Typehints allow you to specify exactly what user defined type a function accepts for each parameter; PHP will throw an InvalidArgumentException exception if the wrong type is given:

PHP typehint example


 1 <?php
 2 
 3 class C1
 4 {
 5 }
 6 
 7 class C2
 8 {
 9 }
10 
11 function fn(C1 $c)
12 {
13 }
14 
15 fn(new C1()); // works perfectly
16 
17 fn(new C2()); // error
18 
19 fn(5); // error

Frustratingly PHP does not allow typehints for scalar types or function return values (yet).

However, even though PHP is a dynamically typed language you should still strive to keep your typing sensible. This means that if you create a variable that contains a specific type, you should try not to reuse it by assigning a new value of a different type to it. Also, don’t call methods on objects if they are not in the typehinted interface. If you do PHP will produce be an error but it’s really not good practice:

Mis-using an interface in PHP


 1 <?php
 2 
 3 interface Fooer
 4 {
 5     public function doFoo();
 6 }
 7 
 8 class FooBar implements Fooer
 9 {
10     public function doFoo()
11     {
12     }
13 
14     public function doBar()
15     {
16     }
17 }
18 
19 function performAction(Fooer $f)
20 {
21     // This is fine, doFoo() is defined in the Fooer interface
22     $f->doFoo();
23 
24     // Don't do this, $f is a Fooer and doBar() is not defined
25     // in the Fooer interface
26     $f->doBar();
27 }
28 
29 performAction(new FooBar());

Throughout this book I will be writing PHP code as if I’m writing in a statically typed language 90% of the time - using typehint whenever possible. However, PHP is still a dynamic language and some times it’s helpful to take advantage of this; whenever I do this I will point it out and explain my reason for choosing to do so.

Front Controllers

The front controller is a design pattern for web applications which involves creating a single entry point into your application. It requires you to configure your webserver to redirect all requests to a single PHP script which then processes the request and decides what content to display.

Let’s take a look at an example:

The Traditional Approach

First, let’s look at the traditional approach of using PHP. Create 2 files inside an empty folder, the first one we’ll call page1.php:

page1.php


1 <?php
2 
3 echo 'You are on page 1';

And the second one we’ll call page2.php

page2.php


1 <?php
2 
3 echo 'You are on page 2';

Next open a terminal and cd into the directory containing these files, Now, use the following command to start up PHP’s built in webserver:

1 $ php -S localhost:8080

Now if you open your browser and go to http://localhost:8080/page1.php then you will see You are viewing page 1. If you then go to http://localhost:8080/page2.php you will see You are viewing page 2.

When you are done, press CTRL+C in your terminal to stop the webserver.

This is the approach that you normally first learn when starting out with PHP. There’s nothing wrong with this approach, but, in general using a front controller is better so let’s take a look at that.

Single Entry Point

Create a new folder and this time create a single file called index.php containing:

index.php


1 <?php
2 
3 echo 'You are looking at: ' . $_SERVER['REQUEST_URI'];

Then, in the terminal cd to this new directory. This time start the PHP built in webserver with the name of the file we want to use as the application entry point. Like so:

1 $ php -S localhost:8080 index.php

Again open your browser and visit http://localhost:8080/page1 and you will see You are looking at: /page1, and again go tohttp://localhost:8080/page2 and you will see You are looking at: /page2.

So, as you can see, anything you type after the http://localhost:8080 is redirected to the index.php file, and you can use the $_SERVER superglobal to get the actual URI requested.

The Simplest Front Controller in the World

Next, let’s modify the index.php file to look like this:

index.php


 1 <?php
 2 
 3 switch ($_SERVER['REQUEST_URI']) {
 4     case '/page1':
 5         echo 'You are viewing page 1';
 6         break;
 7 
 8     case '/page2':
 9         echo 'You are viewing page 2';
10         break;
11 
12     default:
13         header('HTTP/1.0 404 Not Found');
14 
15         echo '<html>'
16             . '<head><title>404 Not Found</title></head>'
17             . '<body><h1>404 Not Found</h1></body>'
18             . '</html>';
19 }

Now if we go to our browser and go to http://localhost:8080/page1 or http://localhost:8080/page2 then they work as expected. Also, going to http://localhost:8080/anything-else now shows a 404 message.

Obviously this is a pretty pointless and limiting front controller, but hopefully you now understand the theory behind it.

Stop the webserver again by pressing CTRL+C in the terminal.

Front Controllers using Apache

In order to use a front controller with Apache you need to tell it where to find the PHP script to be used for the application entry point. As of Apache version 2.2.16, you can simply do this by adding the following to the .htaccess file in your document root:

.htaccess


1 FallbackResource /index.php

Standards

As a language gets more powerful it often allows many ways and approaches to achieve the same thing. Each person then has their own preferences of how they personally like to do things.

On one hand this is great: it allows programmers to be expressive and to write their code in the way which best fits how they think, lay it out in they way which looks the most aesthetically pleasing to them, and structure it in the way which they find easiest to navigate.

On the other hand this becomes a total nightmare: when you are working with several libraries, all written by different programmers who each have their own way of doing all things. You have to learn each of the different approaches to efficiently navigate and understand each author’s code. Also, it may make it tricky for some of the libraries to happily interact with each other.

For the reasons just mentioned, programmers get together in groups and create standards, these are a nice middle ground which everyone is mostly happy with. You’ll often find that you won’t agree with everything defined in a standard, but by putting that to one side and accepting it you reap the benefits of having your code being much more consistent with all the other users of the standard’s code - as well as any tools which have been built to work with that standard.

PHP-FIG

Introducing PHP-FIG! PHP-FIG or the PHP Framework Interoperability Group is a group built up of various key people in the PHP community who have got together and started to build some standards for using PHP. Many PHP software projects have now adopted or are adopting many of these standards. I fully recommend you do the same!

At the time of writing this there are 5 published standards:

Standard Description
PSR-0 Autoloading Standard
PSR-1 Basic Coding Standard
PSR-2 Coding Style Guide (implies PSR-1)
PSR-3 Logger Interface
PSR-4 Improved Autoloading (an extension to PSR-0)

And a 3 more in discussion:

Standard Description
PSR-5 PHPDoc
PSR-6 Caching Interface
PSR-7 HTTP Message Interfaces

In this book I will be using PSR-0 or PSR-4 for all code (except in some small examples) and PSR-2 for coding style. I will explain a bit more about these in the next few sections.

For more Information on PHP-FIG visit the website.

PHP The Right Way

PHP The Right Way is not a standard as such, it’s simply a website which lists lots of things about how PHP should be used if you are serious about writing good code. It contains lots of fantastic advice and I highly recommend studying it.

Docblocks

Docblocks are comments which contain annotations which can be added to your code to make it possible to generate documentation about your codebase automatically. One such document generation tool is phpDocumentor. This can be fantastically useful if you are building a library for others to use, since you can easily generate great API documentation using it.

There is however another use for it; we’ve already talked about typehints which, by enforcing the types of function arguments, provide an extra level of documentation to people reading the code; it helps them to understand it quicker. They also help IDEs provide auto completion functionality while you’re writing the code. This is great, but so far PHP has only gone half way - as I said earlier there are no typehints for function return values or for scalar types. Also, the type of a variable or property cannot be defined. Therefore, I’ve made it a habit to document these by using PHPdoc tags. I hope one day PHP will add more complete typehinting.

The format of docblocks are fairly standard now, but there’s work to fully standardise it with PSR-5.

Here’s a little example of how I’ll be using docblocks in the code in this book:

Using docblocks to annotate types


 1 <?php
 2 
 3 class Example
 4 {
 5     /** @var string */
 6     private $name;
 7 
 8     /** @var Email */
 9     private $email;
10     
11     /** @param string $name */
12     public function addCustomer($name, Email $email)
13     {
14         // ...
15     }
16 
17     /** @return Customer[] */
18     public function getCustomers()
19     {
20         // ...
21     }
22 }

Docblocks allow you to add much more detail than I’ve shown here. You can give descriptions and details for the file, the class, any variables, properties or parameters, etc. But since I don’t want to generate an API document for this codebase, I’m only using it to specify the types which cannot be specified directly in PHP.

The Autoloader

You have may have never created a PHP autoloader, you may have never ever heard of one, but if you’ve every build an application using a recent PHP framework you have probably used one. However, if you’re not aware of the autoloader and you’re including all your different classes and functions by using PHP’s require, require_once, include and include_once statements, then you need to STOP and read this section now!

The autoloader is a system in PHP where you can create a callback function that will be called if you try to use a class which has not yet been defined. This callback receives the name of the class trying to be used as a parameter. The function can then use the name to lookup and require the file needed to provide the class definition.

In order to use an autoloader callback you can either define a function called __autoload which will provide the autoloading logic. Or, you can use the more recent and more flexible spl_autoload_register function to register your autoloading function.

Now you know what an autoloader is there’s some good news: there’s no actual need to write the autoloader function yourself, there’s a wonderful tool called Composer which can take care of that for you. However, if you do want to look into autoloading in more detail you can read about it in the manual.

PSR-0 - Autoloading Standard

Before talking about Composer I’d like to first introduce PSR-0. PSR-0 is a standard which was designed to make it easy to find the files where given classes are defined.

The basic rules of PSR-0 are as follows:

  • There is exactly one class defined per file.
  • The file name is the same name (and case) as the name of the class defined inside it, with .php appended to it.
  • The file exists in a directory structure which fully matches the namespace in which the class is defined.

The full PSR-0 specification can be read on the PHP-FIG website.

Example

A file located at /home/tom/projects/AutoloadExample/src/MyApp/Entity/Contact.php would contain the following class definition:

PSR-0 compliant class


1 <?php
2 
3 namespace MyApp\Entity;
4 
5 class Contact
6 {
7     // ...
8 }

Whatever comes before the root namespace in the file path (in this case /home/tom/projects/AutoloadExample/src) is not important, so long as the FQCN is mirrored in the folder structure up to the class name.

PSR-4 - Improved Autoloading Standard

PSR-4 improves on the PSR-0 standard. It removes some old, obsolete features and allows a namespace prefix to be defined. If your whole application exists under a single namespace this remove the need of having a directory level for that namespace.

Using the previous PSR-0 example: if the prefix MyApp is chosen then the Contact class definition can remain exactly the same, but the file is instead stored in /home/tom/projects/AutoloadExample/src/Entity/Contact.php.

Composer

Composer is a dependency manager for PHP. It allows you to specify all the libraries and tools that your PHP project depends on in a simple JSON file. It will then fetch the correct versions of those dependencies (and all their dependencies) into your project.

This means that it’s easy to distribute your project without including its 3rd party dependencies. While making it very easy for users or developers working on the project to easily install them themselves. It also makes it easy to quickly update to newer versions of dependencies.

Composer installs the dependencies locally to the project in a directory called vendor, rather than installing them globally onto the system. This is a definite plus, as it means you can run many projects on the same system, all working with different versions of their dependencies and without getting in to a mess.

Now this is all very interesting, but you might have no intention of using any external libraries or tools with your new project. So is Composer still useful?

The answer is most definitely yes:

  • Firstly, there are lots of great development tools which can be installed via Composer. You should be using these tool even if you don’t intend on using 3rd party libraries.
  • Secondly, you may not intend on using 3rd party libraries but if you start off using Composer from the beginning, you can always change your mind and add a dependency very easily later on.
  • Thirdly, Composer provides a nice and easy to set up autoloader for PHP. By simply adding a few lines of JSON to your project, your autoloader is set up and ready to go.

While there are plenty of people out there who will have a good reason not to use Composer, in my opinion if you don’t have one, then you should definitely be using it in your projects.

So, that’s a little intro on what Composer can do for you. You can find out about all its features and settings in the documentation but, to save you the hassle of reading it all now let’s have a look at a little example of the basics.

Composer Example

Installing

The various installation options for Composer can be found on the website.

You can either install a copy locally to your project which means your use it by running:

1 $ ./composer.phar

Or you can install it globally on your system and rename it to composer. I have done it this way so on my system I run Composer by simply typing:

1 $ composer

If you have installed it differently from me you will need to adjust my instructions accordingly.

Setting up the Autoloader

To start off, create a new project directory and cd into it:

1 $ mkdir ComposerExample
2 $ cd ComposerExample

If you want to use Composer locally you’ll want to install it inside this directory now. However, if you have installed it global already then you can just carry on.

Next up, create a file in the project folder called composer.json and add the following content:

composer.json


1 {
2     "autoload": {
3         "psr-0": {
4             "ComposerExample\\": "./src"
5         }
6     }
7 }

What we have told Composer to do here is set up its autoloader, to locate any classes in the ComposerExample namespace, by using the PSR-0 file structure inside a directory in our project called src.

Next, tell Composer to apply these settings with the following command (remember you will need to adjust it if you have installed Composer locally):

1 $ composer install

Once it has finished, you will notice it has created a new directory called vendor and another file called composer.lock. If you’re are using a source control system like git (and you really should be!), then you should instruct it to ignore the vendor directory from the repository. The composer.lock file should be added to the repository though.

Next up, create a directory structure for our PSR-0 classes to go in:

1 $ mkdir -p src/ComposerExample

Then create a file called src/ComposerExample/HelloApplication.php with the following content:

src/ComposerExample/HelloApplication.php


 1 <?php
 2 
 3 namespace ComposerExample;
 4 
 5 class HelloApplication
 6 {
 7     public function run()
 8     {
 9         echo "Hello beautiful World!\n";
10     }
11 }

Finally, create a file called run.php containing:

run.php


1 <?php
2 
3 // Load up Composer's autoloader
4 require_once __DIR__ . '/vendor/autoload.php';
5 
6 // This class will loaded automatically
7 $app = new \ComposerExample\HelloApplication();
8 $app->run();

Now to see it work run:

1 $ php run.php

Ta da!

Composer also supports PSR-4. To use it instead simply use psr-4 in the composer.json. When doing this everything in the src folder will have the prefix (ComposerExample) applied to the namespace so the ComposerExample directory level would have to be removed.

Adding a Dependency

Next let’s dress it up a bit using a 3rd party library. I had a little hunt around for something interesting to try and found Maxime Bouroumeau-Fuseau’s ConsoleKit library.

First up, let’s add it to the project as a dependency by updating our composer.json file to contain the following:

composer.json


 1 {
 2     "require": {
 3         "maximebf/consolekit": ">=1.0.0"
 4     },
 5     "autoload": {
 6         "psr-0": {
 7             "ComposerExample\\": "./src"
 8         }
 9     }
10 }

Then we tell Composer to download its new dependency by running:

1 $ composer update

This should download the ConsoleKit package, which will now be ready to use. Let’s update our ComposerExample\HelloApplication class to look like this:

src/ComposerExample/HelloApplication.php


 1 <?php
 2 
 3 namespace ComposerExample;
 4 
 5 use ConsoleKit\Console;
 6 
 7 class HelloApplication extends Console
 8 {
 9     public function run()
10     {
11         $console = new Console();
12         $console->addCommand('ComposerExample\\HelloCommand');
13         $console->run();
14     }
15 }

And let’s add a new class called ComposerExample\HelloCommand like so:

src/ComposerExample/HelloCommand.php


 1 <?php
 2 
 3 namespace ComposerExample;
 4 
 5 use ConsoleKit\Command;
 6 use ConsoleKit\Colors;
 7 
 8 class HelloCommand extends Command
 9 {
10     public function execute(array $args, array $options = array())
11     {
12         $this->writeln('Hello green World!', Colors::GREEN);
13     }
14 }

Now to try to run it:

1 $ php run.php hello

There we have it, we’ve simply added a dependency to our app and made use of it. Composer has done all the hard work of downloading it and setting up the autoloader required to find it.

Adding Development Tools

Composer’s require section lets you define the requirements your project needs to run. It also has a require-dev section which is for dependencies which you want to use for development only - testing tools for example.

CodeSniffer is a tool which checks that your code follows a given coding style, lets add it to our project. To use it update the composer.json file to include the CodeSniffer development dependency:

composer.json


 1 {
 2     "require": {
 3         "maximebf/consolekit": ">=1.0.0"
 4     },
 5     "require-dev": {
 6         "squizlabs/php_codesniffer": "1.*"
 7     },
 8     "autoload": {
 9         "psr-0": {
10             "ComposerExample\\": "./src"
11         }
12     }
13 }

Once again, tell Composer to update its dependencies by running:

1 $ composer update

After it has finished, CodeSniffer is ready to be used. When Composer installs any tools it will install the executable files in a local directory, by default this directory is vendor/bin.

We can now run CodeSniffer by with the following command:

1 $ vendor/bin/phpcs --standard=psr2 src

If all the code in our src directory conforms to the PSR-2 coding style then CodeSniffer should have completed without and errors.

To make life easier, your can add vendor/bin to your operating system’s PATH variable so you can execute your tools more easily. On Linux you do this by adding the following to your .bashrc file in your home directory:

PATH=./vendor/bin:$PATH

After you have done this you should be able to simple run:

1 $ phpcs --standard=psr2 src

Keeping Logic and Display Code Separate

PHP lets you easily mix text output (usually HTML) with your logic. This makes PHP a really useful and powerful web templating language, but it also makes it very easy to write hideous code which mixes application logic in with the HTML output like so:

Mixing logic and display code


 1 <?php
 2 
 3 $repository = new CustomerRepository();
 4 
 5 ?>
 6 
 7 <h1>List Customers</h1>
 8 
 9 <?php
10 
11 function escape($string)
12 {
13     return htmlentities($string);
14 }
15 
16 if ($_POST['search']) {
17     try {
18         $customers = $repository->getMatching($_POST['search']);
19     } catch (LoadingException $e) {
20         die('The was an error');
21     }
22 }
23 
24 if (count($customers)) { ?>
25     <table>
26         <thead>
27             <tr>
28                 <th>Name</th>
29                 <th>Email Address</th>
30                 <th>Phone Number</th>
31             </tr>
32         </thead>
33         <tbody>
34             <?php foreach ($customers as $customer) { 
35                 echo '<tr>';
36                 echo '<td>' . escape($customer->name) . '</td>';
37                 $customer->printEmail();
38                 ?>
39                     <td><?php echo escape($customer->phone); ?></td>
40                 </tr>
41             <?php } ?>
42         </tbody>
43     </table>
44 <?php } else {  ?>
45     <p>No customers found.</p>
46 <?php } ?>

I think we can all agree that is pretty ugly, but if it’s left to get out of control it can get a lot uglier!

The solution to this is to not mix your HTML and PHP code together and instead maintain a clear separation between the two. This also allows designers to work on the user interface without have to understand the codebase.

There are templating libraries for PHP such as Twig and Smarty which introduce their own template tags for using in your HTML templates. You can also use PHP itself to do the templating, but if you do you really should maintain the discipline of keeping logic and view code separate; it may even be worth using different file extensions to keep it clear - .php for logic and .phtml for HTML templates is often used.

The choice between using PHP or a dedicated templating library can often be down to who is going to have access to modify the view templates. If your designers are in house, trustworthy and trained, then using PHP can be the easiest approach. However, if you are out sourcing the design work to people you trust less, then using a templating engine means they cannot compromise the security of the application by adding bad PHP code into the templates.

Coding Style

Coding style is simply the way you layout and format your code. In the previous Standards section I talked about how they were introduced to maintain a consistent approach to using a programming language between many developers. Using a consistent coding style is one element of this.

Coding style standards define things like:

  • How many spaces should be used to indent code.
  • If the opening brace for a function’s body goes on the same line as the function definition, or on the line after.
  • If variables be named using camelCase or snake_case
  • etc.

As with all standards, it’s unlikely that you’ll find one which you agree with every bit of. Even so, rather that creating your own perfect one which no one else uses, you should use a well used one you like mostly.

At the moment the best one to use for PHP in my opinion is the one defined by PSR-2 as many people have adopted it. All application code I present in this book will follow the PSR-2 standard - with a couple of exceptions:

1. Unit Tests

When writing unit tests I follow PSR-2 apart from 2 elements - both regarding the method names for the tests.

  • Firstly, instead of using camelCase for test method names I use snake_case. This is because the method names are sentences, and with snake_case it’s easier to separate the words visually when reading it.
  • Secondly I’ll omit the public access specifier as it’s the default in PHP and keeps the line shorter with long test method names.

Unit test coding style example


 1 <?php
 2 
 3 namespace spec;
 4 
 5 use PhpSpec\ObjectBehavior;
 6 
 7 class ExampleSpec extends ObjectBehavior
 8 {
 9     function it_adds_2_numbers_together()
10     {
11         $this->add(5, 2)->shouldReturn(7);
12     }
13 }

2. Template Code

When writing template code using PHP I prefer to keep it looking as close to HTML as possible. I try to keep the code inside PHP tags to single expressions and I use the foreach :/endforeach, if :/endif, etc. style of code blocks instead of using braces as I think they are easier to match up in this context. Here’s an example:

Neat display template code example


 1 <h1>List Customers</h1>
 2 
 3 <?php if (count($customers)) : ?>
 4     <table>
 5         <thead>
 6             <tr>
 7                 <th>Name</th>
 8                 <th>Email Address</th>
 9                 <th>Phone Number</th>
10             </tr>
11         </thead>
12         <tbody>
13             <?php foreach ($customers as $customer) : ?>
14                 <tr>
15                     <td><?php echo escape($customer->name); ?></td>
16                     <td><?php echo escape($customer->email); ?></td>
17                     <td><?php echo escape($customer->phone); ?></td>
18                 </tr>
19             <?php endforeach; ?>
20         </tbody>
21     </table>
22 <?php else : ?>
23     <p>No customers found.</p>
24 <?php endif; ?>

Methodologies, Techniques and Tools

In this chapter I want to introduce the methodologies, techniques and tools incorporated in this book. None of these are exclusive to PHP and therefore they are worth learning about regardless of which language you’re developing in. Also, none of these are brand new to PHP - in fact any serious PHP development company will be using at least some, if not all of these already. While some of these are new and have been developed in recent years, many of them have been developed over the last one, two or more decades.

As in the previous chapter, I don’t want to go into any real depth with any of these topics. I just want to give a short introduction or primer on each subject. This should provide enough of an understanding to work through this book, but as always, I do encourage you dig deeper into each of the subjects yourself. I will provide references for each topic of good places to start looking when you want to learn more.

Object Oriented Programming (OOP)

Sometimes I think there is a misconception that if you use classes in your code then you are doing OOP. This is not the case. OOP is an approach to modelling which involves grouping your business model down into objects, then grouping the related data and behaviours (methods) of these objects in your code as classes. This style of programming can even be done in languages which have no concepts of classes, and classes can be used ways which really don’t represent good OO code.

This is not a book on OO design but we will be using it extensively. I will be explaining my choices for doing the things I do and as a result, if you’re coming in cold to the subject you will probably get a good feel for OOP from this book alone. Even so I think this is a subject which you should study in more detail. If you do already have some experience of OOP, but you’re not an expert, then I hope you will really have a lot to gain from this book.

Before moving on I just want to quickly cover a couple of OO topics:

Encapsulation

Objects consist of state (their properties) and a public interface (all public methods and properties). Generally there are rules as to what are the valid values for any object’s state. Encapsulation is making state private so that it can only be changed via the public interface’s methods.

The point I want to make here is: that you should design your public methods so that there is no way that the object can be put into an invalid state.

Let’s look at a couple of examples:

Example 1

An object to represent an email address should not be able to contain a value which could not be a valid email address. In this case it would make sense to throw an exception if the email address provided does not look like a valid email address:

Well defined email address object example


 1 <?php
 2 
 3 class EmailAddress
 4 {
 5     /** @var string */
 6     private $address;
 7 
 8     /** @param string $address */
 9     public function __construct($address)
10     {
11         if (strpos($address, '@') === false) {
12             throw new InvalidArgumentException(
13                 'Email addresses must contain an @ symbol'
14             );
15         }
16 
17         $this->address = $address;
18     }
19 
20     public function __toString()
21     {
22         return $this->address;
23     }
24 }

In the example above we chose the simple rule that “anything with an @ symbol in it could be an email address”. Obviously in production code this would need to be more well defined.

If you study the code above you will find that there is no way that you can create an instance of EmailAddress with an email address which does not contain an @ symbol. This is good design!

Example 2

Now consider implementing a collection of words which maintains a count of how many words it contains. This collection class will have 2 properties: the list of words and the count. In order to add words to the collection we must add the word to the list and increment the count. First let’s try this with 2 separate methods:

Bad state consistency example


 1 <?php
 2 
 3 class WordCollection
 4 {
 5     /** @var string[] */
 6     private $words = [];
 7 
 8     /** @var int */
 9     private $count = 0;
10 
11     /** @param string $word */
12     public function addWord($word)
13     {
14         $this->words[] = $word;
15     }
16 
17     public function incrementCounter()
18     {
19         $this->count++;
20     }
21 
22     /** @return string[] */
23     public getWords()
24     {
25         return $this->words;
26     }
27 
28     /** @return int */
29     public getNumberOfWords()
30     {
31         return $this->count;
32     }
33 }

Now you can probably see what’s wrong with that straight away, but let me explain for completeness. Take the following code:

1 <?php
2 
3 $collection = new WordCollection();
4 
5 $collection->addWord('hello');
6 $collection->incrementCounter();

It looks OK and $collection is left in a valid state at the end right? But is it always in a valid state? Look again:

 1 <?php
 2 
 3 $collection = new WordCollection();
 4 
 5 // words in list = 0
 6 // counter = 0
 7 
 8 $collection->addWord('hello');
 9 
10 // words in list = 1
11 // counter = 0
12 // Oh dear!
13 
14 $collection->incrementCounter();
15 
16 // words in list = 1
17 // counter = 1

There’s a point in the middle where the state of the object is invalid, we do fix it in the next line of code but what if a developer forgot to increment the counter? It could lead to a nasty bug!

The solution is simple - design the class so it can never be put into an invalid state:

Good state consistency example


 1 <?php
 2 
 3 class WordCollection
 4 {
 5     /** @var string[] */
 6     private $words = [];
 7 
 8     /** @var int */
 9     private $count = 0;
10 
11     /** @param string $word */
12     public function addWord($word)
13     {
14         $this->words[] = $word;
15 
16         // increment the counter when the word is added
17         $this->count++;
18     }
19 
20     /** @return string[] */
21     public getWords()
22     {
23         return $this->words;
24     }
25 
26     /** @return int */
27     public getNumberOfWords()
28     {
29         return $this->count;
30     }
31 }

SORTED!

Inheritance vs. Composition

Inheritance is a very useful and powerful tool in OOP but it’s often misused. The most common misuse of inheritance is using it to bring common functionality into 2 unrelated classes.

An example could be:

A bird and an aeroplane both fly, so it might seem reasonable to inherit both a Bird class and an Aeroplane class from a FlyingThing superclass:

Misused Inheritance


 1 <?php
 2 
 3 abstract class FlyingThing
 4 {
 5     public function startFlying()
 6     {
 7         // ...
 8     }
 9 
10     // ...
11 }
12 
13 class Bird extends FlyingThing
14 {
15 }
16 
17 class Aeroplane extends FlyingThing
18 {
19 }

There are a few reasons why this is a problem:

Firstly, we only have single inheritance in PHP which means we can’t extend from more than one super class. Birds can communicate with each other and aeroplanes (well the pilots) can communicate with each other too. If we wanted to add a CommunicatingThing class then we couldn’t inherit from it as well as FlyingThing (without creating a horrible CommunicatingFlyingThing class instead).

Next up, birds start flying by flapping their wings whereas an aeroplane is propelled by its engines. Now we have 2 different types of FlyingThing. The same goes for communicating: birds do it by tweeting and aeroplanes do it by radio.

Finally, we’ve categorised birds and aeroplanes, which are 2 very different things, together as flying things and communicating things - which we’ve had to make up. A much more sensible category for an aeroplane might be a vehicle, and for a bird maybe an animal.

So how to fix it? So far we’ve been talking about is a relationships; a bird is a flying thing. Inheritance is all about is a relationships, but we also have has a relationships. What might be better would be if we said “a bird has a flight system” or “an aeroplane has a communication system”. When talking about has a relationships we are talking about composition. With this in mind Let’s take a look at a better example of how to model this:

Using composition


 1 <?php
 2 
 3 class FlightSystem
 4 {
 5     public function startFlying()
 6     {
 7         // ...
 8     }
 9 
10     // ...
11 }
12 
13 class CommunicationSystem
14 {
15     /** @param string $message */
16     public function sendMessage($message)
17     {
18         // ...
19     }
20 
21     // ...
22 }
23 
24 class Bird
25 {
26     /** @var FlightSystem */
27     private $flightSystem;
28 
29     /** @var CommunicationSystem */
30     private $communicationSystem;
31 
32     public function __construct()
33     {
34         $this->flightSystem = new FlightSystem();
35         $this->communicationSystem = new CommunicationSystem();
36     }
37 
38     public function startFlying()
39     {
40         $this->flightSystem->startFlying();
41     }
42 
43     /** @param string $message */
44     public function sendMessage($message)
45     {
46         $this->communicationSystem->setMessage($message);
47     }
48 }
49 
50 
51 class Aeroplane
52 {
53     /** @var FlightSystem */
54     private $flightSystem;
55 
56     /** @var CommunicationSystem */
57     private $communicationSystem;
58 
59     public function __construct()
60     {
61         $this->flightSystem = new FlightSystem();
62         $this->communicationSystem = new CommunicationSystem();
63     }
64 
65     public function startFlying()
66     {
67         $this->flightSystem->startFlying();
68     }
69 
70     /** @param string $message */
71     public function sendMessage($message)
72     {
73         $this->communicationSystem->setMessage($message);
74     }
75 }

What’s more, once we start to realise that a bird’s flight system is very different from an aeroplane’s, then we can start having different flight systems which can still be instructed to start flying in the same way by making use of an interface:

Flexible flight systems


 1 interface FlightSystem
 2 {
 3     public function startFlying();
 4 }
 5 
 6 class FlappingFlightSystem implements FlightSystem
 7 {
 8     public function startFlying()
 9     {
10         // ...
11     }
12 }
13 
14 class PropelledFlightSystem implements FlightSystem
15 {
16     public function startFlying()
17     {
18         // ...
19     }
20 }
21 
22 class Bird
23 {
24     // ...
25 
26     public function __construct()
27     {
28         $this->flightSystem = new FlappingFlightSystem();
29         // ...
30     }
31 
32     // ...
33 }
34 
35 class Aeroplane
36 {
37     // ...
38 
39     public function __construct()
40     {
41         $this->flightSystem = new PropelledFlightSystem();
42         // ...
43     }
44 
45     // ...
46 }

The general rule here is: determine if you are really modelling an is a relationship or a has a relationship. Don’t bend your model to fit your code, rather make your code fit the model. When done properly you should find you actually use inheritance pretty rarely.

Design Patterns

Design Patterns are tried and tested solutions to various problems programmers often face. There’s several common design patterns which are very well known, these are called things like the visitor pattern and the strategy pattern.

The de facto resource on this subject is the book titled Design Patterns: Elements of Reusable Object-Oriented Software by the Gang of Four[^the-gang-of-four]. Robert C. Martin says this book is “probably the most important book in software engineering which has been written in the last 30 years”. This book is definitely a must read for all programmers. However, you can also find all the common design patterns listed and explained on Wikipedia.

If you’d prefer to learn about Design Patterns from a PHP point of view then Brandon Savage has written a book on the subject called Practical Design Patterns in PHP.

I’m not going to go into any more details on design patterns here, I just wanted you to know what they are for now. As we work though this book we will be using various design patterns, and as they come up I shall point out which one we are using and explain the choice to do so.

Value Objects & Immutability

When we say something is immutable we mean that its value is fixed and can not be changed. This means a class is either mutable or immutable depending on whether its public interface contains methods which change its internal state. Let’s see an example of each:

Mutable email address class


 1 <?php
 2 
 3 class MutableEmailAddress
 4 {
 5     /** @var string */
 6     private $address;
 7 
 8     /** @var string */
 9     public function __construct($address)
10     {
11         $this->address = $address;
12     }
13 
14     /** @var string */
15     public function setAddress($address)
16     {
17         $this->address = $address;
18     }
19 
20     public function __toString()
21     {
22         return $this->address;
23     }
24 }

Immutable email address class


 1 <?php
 2 
 3 class ImmutableEmailAddress
 4 {
 5     /** @var string */
 6     private $address;
 7 
 8     /** @var string */
 9     public function __construct($address)
10     {
11         $this->address = $address;
12     }
13 
14     public function __toString()
15     {
16         return $this->address;
17     }
18 }

We call immutable classes value objects. This is because an instance of a given class represents a value and only that value. In the same way that we can say 5 will always be 5, we can say that an ImmutableEmailAddress object containing the email address bill@microsoft.com will always contain the email address bill@microsoft.com - therefore this object represents the value of that email address.

Value objects are used to make the type of things explicit and should be used to classify anything which can be classified:

An Example

Instead of using a float for temperate use a Temperature value object - even if it simply contains a single float value. You might however also want to store the unit (Fahrenheit or Celsius) in the Temperature object - a value object can contain more than 1 scalar value. Also, the unit of temperature is classifiable itself, therefore make that a value object too.

Your value objects should only be able to be created with valid values, we don’t want anyone to be able to create a temperature of “30 degrees hotness. This should be enforced in the class definition!

For completeness, let’s look a good implementation of what we’ve just discussed:

Temperature; a good use of value objects


 1 <?php
 2 
 3 class TemperatureUnit
 4 {
 5     const CELSIUS    = 'c';
 6     const FAHRENHEIT = 'f';
 7 
 8     /** @var string */
 9     private $value;
10 
11     /** @param string $value */
12     public function __construct($value)
13     {
14         $this->assertValueIsValid($value);
15 
16         $this->value = $value;
17     }
18 
19     /** @return string */
20     public function getValue()
21     {
22         return $this->value;
23     }
24 
25     private function assertValueIsValid($value)
26     {
27         if (!in_array($value, [self::CELSIUS, self::FAHRENHEIT])) {
28             throw new InvalidArgumentException(
29                 'A temperature unit must be celsius or fahrenheit'
30             );
31         }
32     }
33 }
34 
35 class Temperature
36 {
37     /** @var float */
38     private $degrees;
39 
40     /** @var TemperatureUnit */
41     private $unit;
42 
43     /** @param float $degrees */
44     public function __construct($degrees, TemperatureUnit $unit)
45     {
46         $this->degrees = $degrees;
47         $this->unit    = $unit;
48     }
49 
50     /** @return float */
51     public function getDegrees()
52     {
53         return $this->degrees;
54     }
55 
56     /** @return TemperatureUnit */
57     public function getUnit()
58     {
59         return $this->unit;
60     }
61 }

The benefits

There are several benefits to using value objects:

Confidence

With a value object you know that it can’t change unexpectedly. Using our MutableEmailAddress class from earlier consider the following code:

Unexpected change of value


 1 <?php
 2 
 3 function sendEmail(MutableEmailAddress $address)
 4 {
 5     mail($address->getValue(), 'Hello', '...');
 6     $address->setValue('steve@apple.com');
 7 }
 8 
 9 function logEmailSent(MutableEmailAddress $address)
10 {
11     echo "A message was sent to " . $address->getValue();
12 }
13 
14 $address = new MutableEmailAddress('bill@microsoft.com');
15 
16 sendEmail($address);    // send email to bill@microsoft.com
17 logEmailSent($address); // but logs "A message was sent to steve@apple.com"

Looking at just the last 3 lines of code in the example, you would expect the message would get sent to Bill and the log message would reflect that, but it doesn’t!

If we had used an ImmutableEmailAddress object instead then the $address->setValue('steve@apple.com'); line of code would not have been allowed and would have caused an error. Therefore, we could be certain that our last 3 lines of code would work as expected.

Consistency

If we create a function that takes a Temperature as an argument we can be sure that the value we get is a valid Temperature. We don’t need to write any defensive code to check that the unit is valid or that degrees are specified as a floating point value, because all that has been taken care of in the class definitions of our value objects.

Documentation

When you open a file and look at the code, it’s much easier to know the type of a parameter that was typehinted in the method argument list. This is really a benefit of typehints rather than of value objects. However, by using value objects abundantly you will have more types to typehint for.

Entities

Entities make up an important part of the business model of most applications. Unlike value objects they are mutable. They are also the objects which are often persisted and make up the ongoing state of the application.

Entities have identities. They can have all their properties changed but they continue to maintain the same identity through out their lifetime. A simple analogy of an entity object is a person, they can change their name but they are still the same person. This means that the equality of entities determined by the equality of their identities - unlike value objects the equality of their other properties are not important when determining equality.

Here’s a simple example of what a simple entity class make look like:

Example entity class


 1 <?php
 2 
 3 class Customer
 4 {
 5     /** @var CustomerId */
 6     private $id;
 7 
 8     /** @var PersonName */
 9     private $name;
10 
11     /** @var EmailAddress */
12     private $email;
13 
14     public function __construct(
15         CustomerId $id,
16         PersonName $name,
17         EmailAddress $email
18     ) {
19         $this->id    = $id;
20         $this->name  = $name;
21         $this->email = $email;
22     }
23 
24     public function changeName(PersonName $newName)
25     {
26         $this->name = $newName;
27     }
28 
29     public function changeEmail(EmailAddress $newAddress)
30     {
31         $this->email = $newAddress;
32     }
33 
34     /** @return CustomerId */
35     public function getId()
36     {
37         return $this->id;
38     }
39 
40     /** @return Name */
41     public function getName()
42     {
43         return $this->name;
44     }
45 
46     /** @return EmailAddress */
47     public function getEmail()
48     {
49         return $this->email;
50     }
51 }

Dependency Injection (DI) & Inversion of Control (IoC)

Dependency Injection is simply explained by saying: if you have a class that relies on another class, rather than letting it create that other class internally, inject the dependency into it.

Example without dependency injection:

No dependency injection example


 1 <?php
 2 
 3 class Foo
 4 {
 5     public function doFoo()
 6     {
 7         // ...
 8     }
 9 }
10 
11 class Bar
12 {
13     /** @var Foo */
14     private $fooer;
15 
16     public function __construct()
17     {
18         /*
19          * Bar is in control of creating a Foo.
20          *
21          * As a result bar can only ever use a Foo and never a subtype of
22          * Foo.
23          *
24          * This is known as "tight coupling" because Bar can not exist without
25          * Foo
26          */
27         $this->fooer = new Foo();
28     }
29 
30     public function doBar()
31     {
32         $this->fooer->doFoo();
33     }
34 }

Example with dependency injection:

Dependency injection example


 1 <?php
 2 
 3 class Foo
 4 {
 5     public function doFoo()
 6     {
 7         // ...
 8     }
 9 }
10 
11 class Bar
12 {
13     /** @var Foo */
14     private $fooer;
15 
16     /**
17      * The Foo must be injected into the instances of Bar.
18      *
19      * It is also possible to inject a subtype of Foo.
20      */
21     public function __construct(Foo $fooer)
22     {
23         $this->fooer = $fooer
24     }
25 
26     public function doBar()
27     {
28         $this->fooer->doFoo();
29     }
30 }

That’s it, Dependency Injection is as easy as that, but why do it?

Substituting Behaviour

By injecting dependencies you’re promoting the development of flexible and reusable code. Since you can not only can you inject the dependent type but also any subtype. This makes it possible to extend your code without actually modifying it - by simply injecting a different subtype of a dependency.

Example

Take this simple email address printer:

Email printer using dependency injection


 1 <?php
 2 
 3 class EmailAddress
 4 {
 5     /** @var string */
 6     private $address;
 7 
 8     /** @param string $address */
 9     public function __construct($address)
10     {
11         $this->address = (string) $address;
12     }
13 
14     public function __toString()
15     {
16         return $this->address;
17     }
18 }
19 
20 interface EmailAddressRenderer
21 {
22     /** @return string */
23     public function render(EmailAddress $email);
24 }
25 
26 class PlainTextRenderer implements EmailAddressRenderer
27 {
28     public function render(EmailAddress $email)
29     {
30         return (string) $email;
31     }
32 }
33 
34 class EmailAddressPrinter
35 {
36     /** @var EmailAddressRenderer */
37     private $renderer;
38 
39     public function __construct(EmailAddressRenderer $renderer)
40     {
41         $this->renderer = $renderer;
42     }
43 
44     public function printAddress(EmailAddress $address)
45     {
46         echo $this->renderer->render($address) . "\n";
47     }
48 }

To use our class we’d simply write something like this:

Email printer example use


1 <?php
2 
3 $address = new EmailAddress('bill@microsoft.com');
4 
5 $printer = new EmailAddressPrinter(new PlainTextRenderer());
6 
7 $printer->printAddress($address);

This works great! But then we’re told we need to print out the email address on a web page as a mailto link. Since we’ve injected our EmailAddressRenderer into the printer rather than letting the printer create it, we can now inject anything which implements the EmailAddressRenderer interface.

Let’s add a HTMLRenderer:

HTML email address renderer


1 <?php
2 
3 class HTMLRenderer implements EmailAddressRenderer
4 {
5     public function render(EmailAddress $email)
6     {
7         return sprintf('<a href="mailto:%1$s">%1$s</a>', htmlentities($email));
8     }
9 }

Our code to make use of this would now look like this:

HTML email printer example use


1 <?php
2 
3 $address = new EmailAddress('bill@microsoft.com');
4 
5 $printer = new EmailAddressPrinter(new HTMLRenderer());
6 
7 $printer->printAddress($address);

Simples! Notice how in order to change the way it behaves we have not altered the original code in any way, instead we’ve simply extended it. Here we’ve written our code in such a way that even though the printer uses a renderer, it does not have control over how that renderer is created. Instead it is uses the one given. This is known as inversion of control.

Inversion Of Control

We’ve just seen an example of inversion of control so we know what it is. But again, what is it useful for?

Well…

  • Using it creates extensible code.
  • It removes the need for your business model to know about implementation details such as: how things are displayed or how messages are sent. Instead, it allows those details to be plugged in; this is often done using the Adapter design pattern.
  • It allows your code to be easily tested as small, independent units. This is possible through the use of test doubles.

Testing

Each class in your codebase may depend on on other classes, each of which may then depend on even more classes. As your codebase grows, testing anything becomes quite hard as you need create all the dependencies of the class you are trying to test. Also, each of these dependencies will have their own dependencies which will need to be created as well. In this situation tests get very complex and also fragile; if you were to change anything then lots of your tests could break, and it could take a long time to get them passing again.

By using dependency injection, inversion of control and interfaces, you get code which doesn’t depend on fixed dependencies but rather on abstractions (the interface) of the dependency. When your code is written like this your dependencies are considered to be loosely coupled.

When your dependencies are loosely coupled you can create test doubles. These are very simple and predictable versions of a class’s dependencies. These can be injected into the class instead of the real dependencies, allowing the class to be tested in isolation. We’ll look at this in more detail in the next chapter.

Dependency Injection Containers (DIC) & Service Managers

These are tools which can manage the creation of objects and ensure that the required dependencies get injected into them on creation. I’m not going to talk about these here but will cover them in more detail when we need to use one.

All I will add now is that there are many DIC and Service Manager libraries available should you ever decide you need one.

The SOLID Principles

The SOLID Principles are the first 5 principles from a list compiled by Robert C. Martin of Principles of Object Oriented Design. These 5 principles are:

Single Responsibility Principle (SRP)
A class should only have a single responsibility - don’t create classes which do a lot of different things.
Open Closed Principle (OCP)
Your application should be open for extension but closed for modification. We saw an example of this in action in the Dependency Injection section.
Liskov Substitution Principle (LSP)
This states objects can be replaced by subtypes of themselves and the program should still work. What this means is: when you extend a class you should make sure its public interface still behaves in the expected way, making it possible to use the class in place of its parent anywhere in the program.
Interface Segregation Principle (ISP)
This principle states that if something has a dependency but only uses a subset of that dependency’s public interface, then that subset should be made into a separate interface. The new interface then becomes the dependency.
Dependency Inversion Principle (DIP)
Classes should not depend on other concrete classes, but rather on abstractions (i.e. abstract classes and interfaces). Again, we looked at this earlier on in the email printer example.

More in-depth details can be found on Robert Martin’s article: Principles of OOD.

If you stick to these principles you will create fantastically modular, extensible and testable code.

Functional Programming (FP)

History

PHP is naturally heavily biased towards the imperative programming paradigm. Imperative programs are basically sequences of statements which are executed in order, changing the program state they run. The imperative style of programming has been the most popular style for several decades now.

There are however other paradigms, one of which is functional programming. Functional Programming pre-dates Imperative Programming, but Imperative Programming still won the popularity race up until recently. Once it stopped being possible for computer CPUs to get any faster, the manufacturers decided to start adding more cores instead. So rather than trying to have a single thread of instructions executing faster and faster, we have multiple threads executing simultaneously.

The imperative style of programming is very well suited towards single threads of execution because statements always run in the correct order. With multiple threads however, one thread might run faster than another, and if they are both trying to read and change the same state then there’s no guarantee that it will happen in the right order. To make this work using imperative programming you need to introduces locks to keep track of and synchronise how the threads are interacting with the shared state. This is tricky and is not fun to do!

The functional style of programming, makes this a lot simpler. You can tell the computer to execute 2 different functions in 2 different threads and be sure that they will behave as expected, and not conflict with each other. For this reason, functional programming and functional programming languages are gaining a lot of popularity at the moment. Also, many imperative languages are adding more and more functional style features.

So What is Functional Programming?

Functional programming has its roots in lambda calculus, and is based on the idea that whenever you call a given function with the same set of arguments, you will always get the same result. Some other aspects of functional programming are:

  • Functions have no side effects - they never modify or read global/persistent state. These are considered pure functions.
  • There is no assignment - once a variable has been initialised with a value it will always be that value.
  • Functions can accept other functions as arguments and return new functions. These are known as higher order functions.

I’m not going to go much deeper into functional programming in this book, I only really want to show what pure functions are. I will be applying some functional programming knowledge during the building of our application but I’m not going to highlight it too much.

Pure Functions

As previously mentioned, pure functions are functions which have no side effects. Let’s look at some examples of pure functions:

All these functions will always return the same value when given the same arguments. And they never alter persistent state:

Pure functions


 1 <?php
 2 function add($a, $b)
 3 {
 4     return $a + $b;
 5 }
 6 
 7 function fahrenheitToCelsius($fahrenheit)
 8 {
 9     return ($fahrenheit - 32) / 1.8;
10 }
11 
12 function applyTwiceAndAdd(callable $fn, $value)
13 {
14     return $fn($value) + $fn($value);
15 }

The following functions are not pure. If called twice with the same arguments the result may not be the same:

Impure functions


 1 <?php
 2 $counter = 0;
 3 
 4 function incrementCounter()
 5 {
 6     global $counter;
 7 
 8     $counter++;
 9 }
10 
11 function getCount()
12 {
13     global $counter;
14 
15     return $counter;
16 }
17 
18 function getCountAndIncrement()
19 {
20     global $counter;
21 
22     return $counter++;
23 }
24 
25 function threeTimesRand($max)
26 {
27     return 3 * rand(0, $max);
28 }
29 
30 function readFile($filename)
31 {
32     return file_get_contents($filename);
33 }

Now some functional programming languages do not have assignment statements to allow the changing of the value of a variable - but PHP does! It is possible to make use of this inside a function, while still providing a functionally pure interface to it:

Pure function with local state


 1 <?php
 2 
 3 function applyNTimesAndAdd(callable $fn, $n, $value)
 4 {
 5     $total = 0;
 6 
 7     for ($count = 0; $count < $n; $count++) {
 8         $total += $fn($value);
 9     }
10 
11     return $total;
12 }

While applyNTimesAndAdd does have internal state, it is never persisted beyond each execution of the function. Therefore, this can still be considered a pure function - even though the implementation uses imperative code.

Now lets move this theory inside objects. Obviously we can have methods which are pure functions:

Methods as pure functions


 1 <?php
 2 
 3 class RandomFunctions
 4 {
 5     public function add($a, $b)
 6     {
 7         return $a + $b;
 8     }
 9 
10     public function fahrenheitToCelsius($fahrenheit)
11     {
12         return ($fahrenheit - 32) / 1.8;
13     }
14 
15     public function applyTwiceAndAdd(callable $fn, $value)
16     {
17         return $fn($value) + $fn($value);
18     }
19 }

Of course this hasn’t really achieved much other than grouping some functions together.

However, as soon as methods start to make use of properties, they can no longer be considered as pure functions. This is because the properties persist beyond method calls:

Impure methods


 1 <?php
 2 
 3 class Counter
 4 {
 5     private $counter = 0;
 6 
 7     public function incrementCounter()
 8     {
 9         $this->counter++;
10     }
11 
12     public function getCount()
13     {
14         return $this->counter;
15     }
16 
17     public function getCountAndIncrement()
18     {
19         return $this->counter++;
20     }
21 }

Since the behaviour of the methods in the Counter class now depends on the $counter property, none of the methods in the class could be considered pure.

Now thinking back to the applyNTimesAndAdd function, can we do something similar in the context of an object? Take a look at this example and consider whether you think it behaves in a functional way:

 1 <?php
 2 
 3 class ResultAdder
 4 {
 5     private $fn;
 6 
 7     private $total;
 8 
 9     private $value;
10 
11     public function applyNTimesAndAdd(callable $fn, $n, $value)
12     {
13         $this->fn = $fn
14         $this->total = 0;
15         $this->value $value;
16         
17         for ($count = 0; $count < $n; $count++) {
18             $this->applyFunction();
19         }
20 
21         return $this->total;
22     }
23 
24     private function applyFunction()
25     {
26         $fn = $this->fn;
27 
28         $fn($this->value);
29     }
30 }

What do you think? If you study it carefully you will notice that: even though properties are being used inside the class, every time a method in the public interface is invoked, the properties are being reset. This means that the applyNTimesAndAdd method does indeed appear to be working in a functional way.

Classes like this one are often created by the use of the Replace Method with Method Object refactoring.

Learn More About FP

Learning a functional programming language is not only fascinating, but it also gives you a whole new set of tools which you can apply in any language. Also, as we’re get more and more cores in our computers, it’s going to become increasingly important over the next few years! So, if you’re not already familiar with functional programming I really recommend taking a look at it in the not so distant future - it will be a very rewarding experience!

There are many resources on functional programming which can be easily found. Two notable ones are:

Structure and Interpretation of Computer Programs (SICP)
This is one of the most recommended text books covering functional programming. It was written by MIT professors Harold Abelson & Gerald Jay Sussman with Julie Sussman, and was formerly used there as a text book. It can also be read for free online.
Functional Programming in PHP
This is a much easier book to read, written by Simon Holywell. It introduces functional programming to PHP programmers, along with some useful functional libraries which are available for PHP.

Command Query Separation (CQS)

Command Query Separation is more or what the name implies:

Methods are classified as either commands or a queries (but not both). A command is a method which changes the state of the object. Whereas, a query is a method which returns a value from the object. Also, a command must not return a value, and a query must not change the object’s state.

Let’s take another quick look at the Counter class we made earlier:

Command Query Separation Example


 1 <?php
 2 
 3 class Counter
 4 {
 5     /** @var int */
 6     private $counter = 0;
 7 
 8     /**
 9      * This method is a COMMAND since it updates the state
10      * and doesn't return a value.
11      */
12     public function incrementCounter()
13     {
14         $this->counter++;
15     }
16 
17     /**
18      * This method is a QUERY since it returns a value
19      * but does not alter the object's state.
20      *
21      * @return int
22      */
23     public function getCount()
24     {
25         return $this->counter;
26     }
27 
28     /**
29      * This method alerts the state and returns a value so it
30      * is not a separate COMMAND or QUERY.
31      *
32      * Such methods should be avoided.
33      *
34      * @return int
35      */
36     public function getCountAndIncrement()
37     {
38         return $this->counter++;
39     }
40 }

CQS means we can repeatedly query our object (to make assertions, display, or what ever other reason), while being confident that we are not inadvertently making changes to its state in the process. Generally, with the objects inside your model this is a good approach to try to adhere to.

What might seem an exception to this rule is, methods working in a functional way. However, since the state they modify is not used again, it does not actually break this rule.

Naming

When writing code, you have to decide on the names of many things. These include variables, classes and methods. Choosing the names of these carefully, makes the difference between code which is easily understandable, and which is completely indecipherable.

When choosing names, make them descriptive, so that the intent of your code is clear. If your code is well written and the names are chosen well, there should be no need for any comments in your code. Robert C. Martin goes as far as saying that choosing to adding a comment to your code, is accepting that you have failed as a programmer to solve the problem clearly. That does sound a bit harsh, but the underlying message is that your code should be self descriptive. It’s OK to use comments when something cannot be made clear in code, but those situations should be very, very rare!

One very simple rule for naming is: use nouns for variable and class names and use verbs for method names. It’s not quite as black and white as that, but it’s a very good place to start.

For some more interesting talk on naming I thoroughly recommend having a read of Mathias Verraes’ blog.

Make Method Names Describe Intent

When creating methods, make the intent of the method’s purpose clear in terms of the business language.

Say for example: a customer moves house and needs to have their address updated in the system. What might seem like an obvious approach would be to add a setAddress method to the Customer class. This works but it’s not as informative as it could be. A better method name might be ‘moveHouse’.

So far so good, but what if the customer’s address was entered into the system incorrectly and it just needs to be amended? Does it make sense to call moveHouse to update it? Of course not! So we add a amendPostalAddress method also:

Good method names


 1 <?php
 2 
 3 class Customer
 4 {
 5     /** @var string */
 6     private $name;
 7 
 8     /** @var EmailAddress */
 9     private $emailAddress;
10 
11     /** @var PostalAddress */
12     private $postalAddress;
13 
14     /** @param string $name */
15     public function __construct(
16         $name,
17         EmailAddress $emailAddress
18         PostalAddress $postalAddress
19     ) {
20         $this->name          = $name;
21         $this->emailAddress  = $emailAddress;
22         $this->postalAddress = $postalAddress;
23     }
24 
25     public function moveHouse(PostalAddress $newAddress)
26     {
27         $this->postalAddress = $newAddress;
28     }
29 
30     public function amendPostalAddress(PostalAddress $amendedAddress)
31     {
32         $this->postalAddress = $amendedAddress;
33     }
34 
35     /** @return string */
36     public function getName()
37     {
38         return $this->name;
39     }
40 
41     /** @return EmailAddress */
42     public function getEmailAddress()
43     {
44         return $this->emailAddress;
45     }
46 }

This is definitely more descriptive, but it’s essentially 2 methods which do the same thing - surely there’s no point in that you might think. But there is! The 2 action are actually 2 separate tasks, by separating them we make it very clear to anyone reading the code that there are 2 different events which result in the change of a customer’s address data. This also makes it possible to easily extend the system: say, for example, we are told that emails should be sent to the customer when their address changes:

  • When they move house, we need to send them an email congratulating them on moving into a new home.
  • When amending the address, we just want to notify them that their details have been updated.

Because we’ve separated the 2 actions, this is very easy to add on. For this example let’s use the Decorator pattern1:

Emailing decorator


 1 <?php
 2 
 3 class NotifyingCustomerDecorator extends Customer
 4 {
 5     /** @var Customer */
 6     private $customer;
 7 
 8     /** @var Mailer */
 9     private $mailer;
10 
11     public function __construct(Customer $customer, Mailer $mailer)
12     {
13         $this->customer = $customer;
14         $this->mailer   = $mailer;
15     }
16 
17     public function moveHouse(PostalAddress $newAddress)
18     {
19         $this->customer->moveHouse($newAddress);
20 
21         $this->mailer->send(
22             $this->customer,
23             'Congratulations on moving into your new house!',
24             '...'
25         );
26     }
27 
28     public function amendPostalAddress(PostalAddress $newAddress)
29     {
30         $this->customer->amendPostalAddress($newAddress);
31 
32         $this->mailer->send(
33             $this->customer,
34             'We have updated your details on our system',
35             '...'
36         );
37     }
38 
39     /** @return string */
40     public function getName()
41     {
42         return $this->customer->getName();
43     }
44 
45     /** @return EmailAddress */
46     public function getEmailAddress()
47     {
48         return $this->customer->getEmailAddress();
49     }
50 }

Pretty neat huh? Once again we have easily extended the system to add new functionality, without modifying the existing code. Therefore, we are obeying the Open Closed Principle.

Refactoring

Refactoring is the process of restructuring your code without changing its external behaviour. The purpose of refactoring is to try to make the code easier to understand, manage and extend. As programmers, we should be refactoring all the time while we write our code.

While you can get quite a long way refactoring your code by just using common sense, all the common refactorings have been named and catalogued. To learn more about refactoring I don’t think there’s any better recommendation than to read Martin Fowler’s book titled Refactoring.

Also, much like with design patterns, lots of information can be found about the different refactorings online. In fact, Martin Fowler also has website called http://refactoring.com/ which has a catalogue of refactorings on it.

As I write this book I’ll be refactoring all the example code as I go. Sadly you’ll often not get to see this process as the book will just contain the finished, refactored result. That said you will see the code evolve throughout the book as functionality is added, and that will include some refactoring. I’ll also cover it a bit more in the next chapter.

Object Calisthenics

Object Calisthenics is an idea suggested by Jeff Bay in The ThoughtWorks Anthology book. It consists of 9 rules to help write better Object Oriented code.

These rules are:

Only One Level Of Indentation Per Method
Code with multiple indents gets tricky to read and follow. Also, there’s a greater chance of having to scroll the page to the right which is a nuisance. This can be avoided by extracting methods and using guard clauses.
Don’t Use The ELSE Keyword
There are some cases where else can be useful, but more often than not you can find a neater way. This again, produces code which is easier to read.
Wrap All Primitives And Strings
This pretty much means: use value objects instead of scalar types in PHP. As I’ve already said, this is particularly useful in PHP when combined with typehinting. Always question the use of a scalar property in a domain object.
First Class Collections
Rather than having arrays properties in your classes, create a collection object. Quite often there are actions which you want to apply across a collection, these actions really belong as part of the collection rather than the containing class. Doing this also makes collections reusable.
One Dot Per Line
In PHP this should really be Two Arrows Per Line since we use -> instead of ., and the $this-> must be used inside methods to access things in class scope. What this rule actually means is - don’t call methods on objects returned from other methods - creating a chain of method calls like so: $this->getX()->doY()->doZ(). This rule ties in very tightly with the Law of Demeter.
Don’t Abbreviate
Use descriptive names for everything, so other people (or yourself in 6 months time) reading the code can clearly understand its intent. This ties in with the previous Naming section.
Keep All Entities Small
Simply put - don’t let your classes get to long. If they are starting to get big then there are probably more classes inside which can be extracted out.
No Classes With More Than Two Instance Variables
Nice idea but a bit extreme in my opinion! Still it’s worth keeping in mind as if you’re adding lots of properties to your classes, then are probably some composite types hiding in there which should be extracted.
No Getters/Setters/Properties
The idea here is to tell the class to perform an action and let it get on with it; rather than getting values out, changing them and setting them again - often referred to as tell, don’t ask. Sometimes a getter or setter is needed, but always try your best to find a better way.

I can’t say I stick to all of these rules 100% of the time. But, by trying to follow them as much as possible, you will write much cleaner and more manageable, Object Oriented code.

For more details on these rules take a look at William Durand’s blog post titled Object Calisthenics.

Also, Guilherme Blanco’s slides on the subject are worth a look if you want to see the rules applied in PHP.

Automated Testing

Automated tests are simply tests which can be run to confirm the logic in your program is behaving as expected.

Automated test can be:

  • Test code which executes and verifies the code being tested.
  • Scripts written in a test language, which executes and verifies the code via a testing framework.
  • Code which automates interaction with the user interface or API.
  • Scripts written in a test language, which automate interaction with the user interface or API via a testing framework.

There are different types of test. These are categorised depending on what they are testing. For example you have:

Name Purpose
Unit Tests Test small, isolated units of code.
Integration Tests Test the way that several units of code work together.
Acceptance Tests Tests which prove to the stakeholder that the required functionality has been implemented.

Tests provide confidence in your codebase, and confidence in the ability to add to and modify the code. Also, when refactoring, tests let you know that you haven’t made a mistake and broken the logic. When adding new or modifying existing functionality, tests give you confidence that you haven’t broken a different feature in the process.

Tests are great! You should have them! One often cited argument for not writing tests, is the extra time is takes to write them. What people who say this don’t know about, is all the debugging time it saves. Also, if you use TDD then the process of creating the tests is not separate from the writing of the code, so it’s not an extra task which has to be done.

Test Driven Development (TDD)

I’m going to be very brief here as the next chapter is going to go into it in much more depth.

Simply put, Test Driven Development is a discipline which involves using the tests to guide what production code is actually written - rather than writing the code, then working out how to test it. Through this process, TDD encourages you to write much cleaner and more modular code than you might write without it. It also gives you much higher confidence in the coverage of your test suite.

If you’re new to TDD and want to start learning how to apply it, then the next chapter will get you started. Also, someone really worth checking out is Chris Hartjes aka The Grumpy Programmer - he preaches TDD to PHP programmers, has written a great book called The Grumpy Programmer’s Guide to Building Testable Applications to PHP, and has videos available from http://grumpy-learning.com/

Behaviour Driven Development (BDD)

Behaviour Driven Development is an extension to TDD. It uses testing tools which encourage the language used in the tests to be written in a declarative way - conveying intent from a business perspective. Throughout this book we will be using BDD extensively.

Uncle Bob’s Clean Code

Robert C. Martin, aka Uncle Bob, is a very outspoken and published programmer who has strong ideals about how high quality code should be written. His books include:

  • Clean Code: A Handbook of Agile Software Craftsmanship
  • The Clean Coder: A Code of Conduct for Professional Programmers
  • Agile Software Development, Principles, Patterns, and Practices

He also has a fantastic video series called Clean Code.

Through his books and videos he covers all the topics we’ve looked at in this chapter in a lot more depth. If you really want to improve the way you work he is definitely someone to whom you should be paying attention.

Domain Driven Design (DDD)

Domain Driven Design is much more than how to write code. It includes the full process from understanding the business (domain), to translating that into software. As the name implies, DDD’s driving factor is the domain (the business we are modelling), and the fact that as developers we have to accept that no one understands the domain as much as the domain experts (the people who understand and use the business we are modelling). When doing DDD we do not try to squeeze the domain we are modelling into our software development world’s terms. Rather, we aim to transfer the domain language into our software’s code.

The first stage of DDD, is sitting down with the domain experts and starting to learn about their domain. During this time, we start to crate a ubiquitous language. This is made up of the words and phrases that we can use to discuss the domain in the domain expert’s terms. This ubiquitous language should then be used in all following discussions, as well as being transferred into the actual source code of the application.

While DDD is about the full process, from analysing and understanding the domain through to actually modelling it, there is a certain style of code and set of design patterns which it makes use of. These include use of value objects, entities, aggregates, the repository pattern and more.

Since DDD has a far broader scope than just the writing of the code, this book doesn’t really cover it in any depth. However, the code produced in this book is heavily influence by this style of design.

If you really want to understand DDD, you want to start off by reading Eric Evans’ book Domain-Driven Design.

Another person to keep an eye on regarding this subject in the PHP community is Mathias Verraes.

Command Query Responsibility Segregation (CQRS)

A lot of the techniques I have talked about have about so far, have been about building a rock solid domain model which cannot be broken by creating objects in invalid states. All these careful checks are very important when state is being changed and manipulated. However, often we just want to view the state. In this circumstance the construction of a complex domain model may be considered unnecessarily computationally expensive. For this reason we could consider a bomb proof domain model to be optimised for change.

Now consider this: most web applications have far more hits where state is just viewed, than they do when state is being updated. Take a basic web shop, you view tens of pages of search results, lists, products and reviews, before adding the product you want to the cart then checking out. Here the adding to the cart and checkout processes are the parts which actually update state, all the browsing actions are read only. We could assume that maybe only 1 in 5 hits change state, and we’ve already established that building a complex model for reading only is overly expensive. This is where CQRS comes in.

Before I explain CQRS let me introduce one more point about application architecture. I’ve already introduced how a robust domain model is the key, central part to an application. However, I’ve not said how it is interacted with. On top of the domain layer you might typically build a layer of application service, use case or transaction classes, which talk to the domain model to perform a specific action.

As an example, you might have a ChangeCustomersEmail transaction which loads up a Customer entity from the storage, changes the email address, then stores it. You might also might have a ListCustomers transaction which returns a list of customers on the system.

Now let’s say the site is getting busy and growing, and it’s getting slower and slower. It needs to scale, but how? Well since it’s running on a domain model which is optimised for changing, and we also know that most hits are read only, it would make sense to make those actions optimised for reading. To do this you could separate out all transactions which are read only, and instead of building a complicated model from a complex data store for them. You could create a thin read layer, which reads it’s information from a version of the data store which is optimised for the required queries. The result of this is you would have some transactions which modify state by talking to the complex domain model and updating the master data store. We call these commands. Then you have another set of transactions, which read from a denormalised version of the data store, to display the information quickly for reading only. We call these queries.

That’s it, CQRS is all about splitting your application in half. One half is optimised for updating, the other for reading. There is more to CQRS regarding scaling across multiple servers, but what we have just talked about is the main gist of it from the software architecture point of view.

In this book we will not be building a full CQRS implementation (maybe that could be the sequel). However, I do feel that it is worthwhile making the distinction between the command and query transactions in our application. My reason for this is, that without the extra effort of building a full CQRS solution, we still make it clear which transactions change state. Should the day come that the application needs to be scaled up in a big way and the decision to implement CQRS is taken, this will make it just that little bit easier.

If you want to learn more about CQRS there’s a few great articles by Greg Young in the documents section of http://cqrs.wordpress.com/

Agile

Agile is an approach to software development which is embodied in methodologies such as Extreme Programming (XP) and SCRUM. It accepts the fact that, getting from the stakeholder’s idea to the final product, is not something that can be set as a rigid path from the beginning. As the project progresses, the stakeholder’s ideas evolve and technical challenges might affect the way the project progresses.

With agile development, the stakeholder is heavily involved with the development process, and the project is broken down into manageable sized tasks. The stakeholder prioritises the tasks, then the development team works in small bursts of time, to get the tasks completed and delivered to the stakeholder - in order of priority. In XP these bursts of time are called iterations, whereas in SCRUM they’re known as sprints. After each iteration/sprint, the stakeholder and development team review what has been done and decide what to tackle next.

Agile is about the approach to work and the idea that things can change as they develop. In this book I won’t be discussing this any further, but I will be presenting the code examples as if we’re working in an Agile environment. What this means is: the code I present in an earlier chapter may well change, be replaced or even be deleted in a later chapter. The reason for this is that I don’t just want to present an application architecture as an end product of the book. Rather, I want to go through the process of how we get to that point.

A great book to check out on Agile style development is Kent Beck’s Extreme Programming Explained.

User Stories

A user story is a short description of one of the tasks that a user will do when interacting with the system:

A customer can view their previous orders.

These are created as part of the planning and analysis process. They are often written on small cards called story cards. Acceptance tests are then decided on for a story, then that feature can be implemented.

One thing to note is that a story is not a specification! It’s intentionally vague and it’s purpose is to exist as a request for conversation. When it is time to implement a story, the team (which includes the stakeholder) should discuss the story and decide on the details - this will result in the generation of the acceptance tests. For the purpose of this book, I’ll provide the story and tests as though this conversation has already taken place, I’ll do this for each part of the application we implement.

Creating user stories is not something I will be covering. For this I really recommend Mike Cohn’s rather fantastic book on the subject: User Stories Applied.

  1. The reason I chose to use the Decorator pattern here instead of just extending Customer was just to introduce the pattern. The actual reason why you would choose to use this pattern, would be if you wanted to wrap the Customer class when extensions which could be stacked on top of each other.

An Introduction to Testing and TDD

In this chapter I’m going to introduce some testing tools which we will be using, as well as give a brief introduction to TDD. This is an optional chapter so if you’re already familiar with these tools and TDD then feel free to skip it. However, if you are new to TDD, or have not been doing it for long, then this chapter is definitely worth reading.

Like most of the things I’ve covered so far, this chapter is just here to serve as a brief introduction. It aims to give you what you will need to work through the rest of this book. As always, I recommend you research further in to everything covered here - there are many wonderful resources available.

Types of Test

The 2 main types of test which we will be using during the process of building our application are: acceptance tests and unit tests.

Acceptance Tests

Acceptance tests are high level tests which confirm to the developer and the stakeholder, that the required features have been implemented and are working properly. Since these tests are about producing the features that the stakeholder requests, they are ideally produced with the stakeholder’s presence and input and in a form which they can understand.

A typical example might be to write something down like this:

Listing customers when there are none will return an empty list

Given there are no customers

When I ask to list customers

Then I should get an empty list

These simple rules could then be converted easily into automated tests using any assert based test framework, like so:

xUnit style acceptance test example:


 1 function test_that_listing_customers_when_there_are_none_will_return_an_empty_li\
 2 st()
 3 {
 4     // Given there are no customers
 5     $customerRepository = new CustomerRepository();
 6     $customerRepository->clear();
 7 
 8     // When I ask to list customers
 9     $lister = new CustomerLister($customerRepository);
10     $customers = $lister->listCustomers();
11 
12     // Then I should get an empty list
13     $this->assertEquals([], $customers);
14 }

This works. The comments are there to explain the test in terms the stakeholder can understand, and the code checks the conditions are met. That said, it does mix up the stakeholder’s language with the programmer’s, and it relies on the comments being present and correct. Therefore, if you are working with the stakeholder to produce acceptance tests, then there is a better tool for the job. It’s called Cucumber, and in PHP it’s implemented by a tool called Behat.

Cucumber scripts are tests written in a language that the stakeholder can read and write in also. Tests are grouped as features, which are a collection of scenarios. These scenarios look very much like the original test rules we started with:

Behat acceptance test example


1 Feature: List customers
2     In order to view a list of customers on the system
3     As an administrator
4     I need to be able to see lists of the customers information
5 
6     Scenario: Listing customers when there are none will return an empty list
7         Given there are no customers
8         When I ask to list customers
9         Then I should get an empty list

The language used in the Behat tests can include any phrases that you want. The meanings of these phases (called snippets) are then implemented in PHP in classes know as contexts. Here’s an example:

Behat context example


 1 <?php
 2 
 3 use Behat\Behat\Tester\Exception\PendingException;
 4 use Behat\Behat\Context\SnippetAcceptingContext;
 5 use Behat\Gherkin\Node\PyStringNode;
 6 use Behat\Gherkin\Node\TableNode;
 7 
 8 /**
 9  * Behat context class.
10  */
11 class FeatureContext implements SnippetAcceptingContext
12 {
13     /**
14      * @var CustomerRepository
15      */
16     private $customerRepository;
17 
18     /**
19      * @var mixed
20      */
21     private $result;
22 
23     /**
24      * Initializes context.
25      *
26      * Every scenario gets its own context object.
27      * You can also pass arbitrary arguments to the context constructor through
28      * behat.yml.
29      */
30     public function __construct()
31     {
32         $this->customerRepository = new CustomerRepository();
33     }
34 
35     /**
36      * @Given there are no customers
37      */
38     public function thereAreNoCustomers()
39     {
40         $this->customerRepository->clear();
41     }
42 
43     /**
44      * @When I ask to list customers
45      */
46     public function iAskToListCustomers()
47     {
48         $lister = new CustomerLister($this->customerRepository);
49         $this->result = $lister->listCustomers();
50     }
51 
52     /**
53      * @Then I should get an empty list
54      */
55     public function iShouldGetAnEmptyList()
56     {
57         if ([] !== $this->result) {
58             throw new Exception('Result was not an empty array.');
59         }
60     }
61 }

The different snippets can then be reused in other scenarios and features.

In this book, I will be providing the features for each new bit of functionality that we add. We’ll then use Behat to run the tests.

Unit Tests

Unit tests are for the development team’s benefit. They are not written with the stakeholder’s help; in fact they may event not know they exist. Instead, they are created by the developer as the code is written, and they test little bits of code as isolated units. A unit is a small piece of code which performs a specific task. Often, we treat each class as a unit, but there are situations where multiple classes, or a subsection of a single class, could be considered a unit. Saying that, PHPSpec (the main tool we will be using for unit testing) does enforce that each class is a unit. As a result, this will be the way that we shall mostly be working.

When doing TDD, the tests are actually written before each new bit of code is written. This process, when used properly, actually influences what code is written. Sometimes producing surprisingly elegant solutions.

There are 2 main types of unit testing tools, these are: xUnit style tools and BDD style tools.

xUnit Frameworks

xUnit test tools are call so because each language has at least one of these tools available and they are generally named SomethingUnit (e.g. JUnit for Java, CppUnit for C++). The origin of these names comes from Smalltalk’s SUnit, which was created by Kent Beck and was the first testing framework of this kind. Of course, PHP has such a framework, and as expected it is called PHPUnit. PHPUnit is probably PHP’s most well used unit testing framework and was created by Sebastian Bergmann.

xUnit frameworks are based on assertions. Each framework provides a set of available assertion functions. These are used to check that the results our code produces are what we expect. Some examples of the assertions functions available in PHPUnit are:

PHPUnit assertions example


1 $this->assertEquals(7, $subject->getValue());
2 $this->assertSame($expectedOwner, $subject->getOwner());
3 $this->assertFalse($subject->isBroken());
4 $this->assertTrue($subject->isWonderful());
5 $this->assertNull($subject->getNothing());
6 // ...

A full list of PHPUnit’s assertions can be found in Appendix A of the manual.

While we will not be using PHPUnit as the main unit testing framework in this book, we will be making use of it at some point for certain tests. We will also make use if its assertion library in our Behat Contexts for simplicity.

BDD Frameworks

The second type of unit testing frameworks are BDD spec frameworks. These are used in a very similar way to xUnit frameworks, but the language used in a bit different. Instead of asserting a test’s expectations, they are described using the word should. The idea is that the tests describe the functionality of a unit, rather than just check it’s functionality. I will be using PHPSpec which is a great, but highly opinionated, BDD unit testing tool for PHP.

Using PHPSpec, the assertions we looked at for PHPUnit would written like this instead:

PHPSpec tests example


1 $this->getValue()->shouldReturn(7);
2 $this->getOwner()->shouldReturn($expectedOwner);
3 $this->shouldNotBeBroken();
4 $this->shouldBeWonderful();
5 $this->getNothing()->shouldReturn(null);

The first difference you should notice is that they simply read as better sentences than the PHPUnit assertions.

There is a second difference though: assertions allow you to assert the values of anything. Whereas, PHPSpec’s should* methods only work on return values from the unit being tested or on test double methods. This means that you are much more limited in how you can test with PHPSpec, however, this is not necessarily a bad thing: it forces you to write good code and I like this (it’s not for everyone though).

Red, Green, Refactor: The TDD Unit Testing Process

When doing TDD, there is a process that defines the order in which things should be done. This order is known as Red, Green, Refactor:

Red
Red means that when we run our test suite we see a failing test. This is the first step in writing code: write a failing test. The test we write should be next smallest step we can take in our implementation which will cause the test suite to fail. Once the test is written, you must run the test suite and you must see it fail.
Green
The green step is making the failing test pass. In order to do this you only write the smallest amount of code needed to make the failing test pass. Then we run the test suite again and see that all tests pass.
Refactor
The refactor step is the point at which the code can, and should, be refactored. No functionality should be altered here, you simply tidy up the code. After any refactorings have been made, you must run the test suite to make sure you’ve not broken anything.

After the Refactor step you go back to the Red step and write the next failing test. This process is repeated until the solution is complete.

The Red, Green, Refactor Cycle

The Red, Green, Refactor Cycle

I will run though a demonstration of this process shortly in the Unit Testing With PHPSpec section.

The Double Feedback Loop

Acceptance tests and unit tests support the development process in a double feedback loop. Acceptance tests come from the stakeholder in order of priority. The developers then implement the features using unit tests with the red, green, refactor cycle, until the acceptance tests pass. At this point, the feature can be delivered to the stakeholder and the next set of acceptance tests will be produced.

The Double Feedback Loop

The Double Feedback Loop

Given, When, Then

We’ve already seen the use of these 3 words earlier in the Acceptance Tests section. However, these 3 steps apply to all types of tests. The given part sets up the preconditions, the when part performs the action being tested, and the then part checks the result. Whenever you are writing a test, it is a good idea to maintain clear grouping into these 3 stages.

We’ve seen this in Behat already. It’s highlighted and enforce by the Cucumber language. Now lets take a look an example in a PHPUnit and a PHPSpec test:

Given, When, Then example using PHPUnit


 1 // Inside AgeCalcuatorTest
 2 function test_calculate_the_age_of_a_customer()
 3 {
 4     // Given there is a customer whose date of birth is 1982-03-15
 5     // And today is 2014-09-03
 6     $customer = new Customer('customer name', Date::fromDate('1982-03-15'));
 7     $today = Date::fromDate('2014-09-03');
 8 
 9     // When I calcuate the age of the customer
10     $calculator = new AgeCalculator($today);
11     $age = $calculator->calculateAge($customer);
12 
13     // Then the result should be 32
14     $this->assertEquals(32, $age);
15 }

Given, When, Then example using PHPSpec


 1 // Inside AgeCalcuatorSpec
 2 function it_can_calculate_the_age_of_a_customer()
 3 {
 4     // Given there is a customer whose date of birth is 1982-03-15
 5     // And today is 2014-09-03
 6     $customer = new Customer('customer name', Date::fromDate('1982-03-15'));
 7     $this->beConstructedWith(Date::fromDate('2014-09-03'));
 8 
 9     // When I calcuate the age of the customer
10     $age = $calculator->calculateAge($customer);
11 
12     // Then the result should be 32
13     $age->shouldBe(32);
14 }

The comments are not actually necessary, and it’s also fine to compound the various expressions (particularly the when and then) but the point is not to mix up the order of these stages. I like to use vertical whitespace to separate the setting up of the preconditions, from the tests. A more condensed version of the PHPSpec example would be:

Condensed Given, When, Then example using PHPSpec


1 // Inside AgeCalcuatorSpec
2 function it_can_calculate_the_age_of_a_customer()
3 {
4     $customer = new Customer('customer name', Date::fromDate('1982-03-15'));
5     $this->beConstructedWith(Date::fromDate('2014-09-03'));
6 
7     $calculator->calculateAge($customer)->shouldReturn(32);
8 }

I think that looks pretty neat and is very easy to read and understand what is supposed to happen.

Acceptance Testing with Behat

We’ve already seen Behat and what Cucumber tests look like. Now let’s have a go at setting up a project using them. To start off create a new folder for the project and cd into it:

1 $ mkdir behat-example
2 $ cd behat-example

Next up, let’s add Behat to the project. We’ve already seen how to set up the composer.json file but there is a simpler way: instead, we can create the composer.json, add Behat to it, and run composer update, all in one command like so:

1 $ composer require behat/behat:3.* --dev

Once it has finished, Behat will be installed in the project and the behat command will be available to us. Next, we need to tell Behat to initialise the project - to do this simply run:

1 $ behat --init

This command creates a directory called features. This is where we’ll put the tests. It also creates directory inside features called bootstrap, which contains a file called FeatureContext.php. This is the default context, and is where we can add our snippets.

Now let’s add a feature by creating a file called features/list-books.feature:

features/list-books.feature


1 Feature: List books
2     In order to list books
3     As a reader
4     I must be able to view a list of all books stored on the system
5 
6     Scenario: Display an empty list
7         Given there are no books
8         When I list all books
9         Then I should see an empty list

Next, run Behat:

1 $ behat

This should produce the following output:

 1 Feature: List books
 2     In order to list books
 3     As a reader
 4     I must be able to view a list of all books stored on the system
 5 
 6   Scenario: Display an empty list   # features/list-books.feature:6
 7     Given there are no books
 8     When I list all books
 9     Then I should see an empty list
10 
11 1 scenario (1 undefined)
12 3 steps (3 undefined)
13 0m0.03s (9.00Mb)
14 
15 --- FeatureContext has missing steps. Define them with these snippets:
16 
17     /**
18      * @Given there are no books
19      */
20     public function thereAreNoBooks()
21     {
22         throw new PendingException();
23     }
24 
25     /**
26      * @When I list all books
27      */
28     public function iListAllBooks()
29     {
30         throw new PendingException();
31     }
32 
33     /**
34      * @Then I should see an empty list
35      */
36     public function iShouldSeeAnEmptyList()
37     {
38         throw new PendingException();
39     }

This is Behat saying that it doesn’t understand the snippets which we have used in the test. It also gives some template code which can be copied and pasted into our feature context to implement these snippets. We could do that, but we can actually get Behat to do this for us by running:

1 $ behat --append-snippets

If you look in features/bootstrap/FeatureContext.php after this command has run, you will see the template code has been added for the 3 new snippets. At this point we can run Behat again:

1 $ behat

This time it informs us that the first snippet has no content and needs to be implemented (the others have been skipped). Let’s implement the first snippet.

Update features/bootstrap/FeatureContext.php so that it looks like this:

features/bootstrap/FeatureContext.php


 1 <?php
 2 
 3 use Behat\Behat\Tester\Exception\PendingException;
 4 use Behat\Behat\Context\SnippetAcceptingContext;
 5 use Behat\Gherkin\Node\PyStringNode;
 6 use Behat\Gherkin\Node\TableNode;
 7 
 8 use BehatExample\BookList;
 9 
10 /**
11  * Behat context class.
12  */
13 class FeatureContext implements SnippetAcceptingContext
14 {
15     /**
16      * @var BookList
17      */
18     private $bookList;
19 
20     /**
21      * Initializes context.
22      *
23      * Every scenario gets its own context object.
24      * You can also pass arbitrary arguments to the context constructor through
25      * behat.yml.
26      */
27     public function __construct()
28     {
29         $this->bookList = new BookList();
30     }
31 
32     /**
33      * @Given there are no books
34      */
35     public function thereAreNoBooks()
36     {
37         $this->bookList->clear();
38     }
39 
40     /**
41      * @When I list all books
42      */
43     public function iListAllBooks()
44     {
45         throw new PendingException();
46     }
47 
48     /**
49      * @Then I should see an empty list
50      */
51     public function iShouldSeeAnEmptyList()
52     {
53         throw new PendingException();
54     }
55 }

You can try running Behat again, but it will fail since there is no BookList class. To create this quickly set up the autoloader by updating the composer.json to look like this:

composer.json


 1 {
 2     "require-dev": {
 3         "behat/behat": "3.*"
 4     },
 5     "autoload": {
 6         "psr-0": {
 7             "BehatExample\\": "src/"
 8         }
 9     }
10 }

Next, create the directory for the source code and update Composer:

1 $ mkdir -p src/BehatExample
2 $ composer update

Then, create the BookList class:

src/BehatExample/BookList.php


 1 <?php
 2 
 3 namespace BehatExample;
 4 
 5 class BookList
 6 {
 7     public function clear()
 8     {
 9     }
10 }

Running Behat at this point, will show the first snippet passing and inform that the second snippet needs to be implemented. Let’s implement the last 2 snippets at once: update the features/bootstrap/FeatureContext.php to contain the following:

features/bootstrap/FeatureContext.php


 1 <?php
 2 
 3 use Behat\Behat\Tester\Exception\PendingException;
 4 use Behat\Behat\Context\SnippetAcceptingContext;
 5 use Behat\Gherkin\Node\PyStringNode;
 6 use Behat\Gherkin\Node\TableNode;
 7 
 8 use BehatExample\BookList;
 9 
10 /**
11  * Behat context class.
12  */
13 class FeatureContext implements SnippetAcceptingContext
14 {
15     /**
16      * @var BookList
17      */
18     private $bookList;
19 
20     /**
21      * @var mixed
22      */
23     private $result;
24 
25     /**
26      * Initializes context.
27      *
28      * Every scenario gets its own context object.
29      * You can also pass arbitrary arguments to the context constructor through
30      * behat.yml.
31      */
32     public function __construct()
33     {
34         $this->bookList = new BookList();
35     }
36 
37     /**
38      * @Given there are no books
39      */
40     public function thereAreNoBooks()
41     {
42         $this->bookList->clear();
43     }
44 
45     /**
46      * @When I list all books
47      */
48     public function iListAllBooks()
49     {
50         $this->result = $this->bookList->getBooks();
51     }
52 
53     /**
54      * @Then I should see an empty list
55      */
56     public function iShouldSeeAnEmptyList()
57     {
58         if ([] !== $this->result) {
59             throw new Exception('Result was incorrect.');
60         }
61     }
62 }

Again, we’ve not implemented BookList::getBooks() so let’s do that too:

src/BehatExample/BookList.php


 1 <?php
 2 
 3 namespace BehatExample;
 4 
 5 class BookList
 6 {
 7     public function clear()
 8     {
 9     }
10 
11     /** @return array */
12     public function getBooks()
13     {
14         return [];
15     }
16 }

Run Behat and see the test pass:

 1 $ behat
 2 Feature: List books
 3     In order to list books
 4     As a reader
 5     I must be able to view a list of all books stored on the system
 6 
 7   Scenario: Display an empty list
 8     Given there are no books
 9     When I list all books
10     Then I should see an empty list
11 
12 1 scenario (1 passed)
13 3 steps (3 passed)
14 0m0.01s (9.10Mb)

Before we move on, let’s quickly add another test to the feature by appending the following to features/list-books.feature:

features/list-books.feature


 1     Scenario: Books are listed in alphabetical order
 2         Given there is a book called "Domain Driven Design" by "Eric Evans"
 3         And there is a book called "Refactoring" by "Martin Fowler"
 4         And there is a book called "Design Patterns" by "The Gang of Four"
 5         When I list all books
 6         Then I should see:
 7             | title                | author           |
 8             | Design Patterns      | The Gang of Four |
 9             | Domain Driven Design | Eric Evans       |
10             | Refactoring          | Martin Fowler    |

Again, if you run Behat it will say that there are new, unknown snippets. As before, add these by running:

1 $ behat --append-snippets

Open up features/bootstrap/FeatureContext.php again, and update the 2 new methods which have been added to the class, so that they look like this:

features/bootstrap/FeatureContext.php


 1     /**
 2      * @Given there is a book called :title by :author
 3      */
 4     public function thereIsABookCalledBy($title, $author)
 5     {
 6         $this->bookList->add($title, $author);
 7     }
 8 
 9     /**
10      * @Then I should see:
11      */
12     public function iShouldSee(TableNode $table)
13     {
14         if ($table->getHash() !== $this->result) {
15             throw new Exception('Result was incorrect.');
16         }
17     }

Finally, update BehatExample\BookList to contain a working implementation:

src/BehatExample/BookList.php


 1 <?php
 2 
 3 namespace BehatExample;
 4 
 5 class BookList
 6 {
 7     /** @var array */
 8     private $books = [];
 9 
10     public function clear()
11     {
12         $this->books = [];
13     }
14 
15     /**
16      * @param string $title
17      * @param string $author
18      */
19     public function add($title, $author)
20     {
21         $this->books[] = [
22             'title'  => $title,
23             'author' => $author
24         ];
25     }
26 
27     /** @return array */
28     public function getBooks()
29     {
30         $list = $this->books;
31 
32         usort($list, function ($a, $b) {
33             return $a['title'] > $b['title'];
34         });
35 
36         return $list;
37     }
38 }

Then run Behat to see the tests pass:

 1 $ behat
 2 Feature: List books
 3     In order to list books
 4     As a reader
 5     I must be able to view a list of all books stored on the system
 6 
 7   Scenario: Display an empty list
 8     Given there are no books
 9     When I list all books
10     Then I should see an empty list
11 
12   Scenario: Books are listed in alphabetical order
13     Given there is a book called "Domain Driven Design" by "Eric Evans" 
14     And there is a book called "Refactoring" by "Martin Fowler"
15     And there is a book called "Design Patterns" by "The Gang of Four" 
16     When I list all books                                               
17     Then I should see:                                                  
18       | title                | author           |
19       | Design Patterns      | The Gang of Four |
20       | Domain Driven Design | Eric Evans       |
21       | Refactoring          | Martin Fowler    |
22 
23 2 scenarios (2 passed)
24 8 steps (8 passed)
25 0m0.02s (9.15Mb)

Mink

AUTHOR NOTE: Coming soon…

The Mink Context

AUTHOR NOTE: Coming soon…

Which Language to use in Interface Tests

AUTHOR NOTE: Coming soon…

Unit Testing with PHPSpec

Now let’s take a look at unit testing. We’ll use PHPSpec for this. As we work through building the application in the next section of this book, I’ll be showing the process of acceptance testing. However, I will not be showing the process of unit testing in the examples (except in certain circumstances where there is something to learn from it). The reason for this is, that it would be a long winded, pointless and excessive process to document, and it would detract from the topic of this book. That said, all the example code will have been written using the full TDD process, and you should do the same. This also means, that all the example code for this book will contain complete unit tests which you can study for yourself.

Since we’re not going to be highlighting the unit testing process when building the application, we’ll go through an example now to get familiar with the process.

Example

For our TDD example we’ll create an algorithm which finds the greatest common divisor of 2 numbers.

Setup

Let’s start by creating a new project:

1 $ mkdir phpspec-example
2 $ cd phpspec-example

And configure Composer for the project:

composer.json


 1 {
 2     "require-dev": {
 3         "phpspec/phpspec": "2.*@dev"
 4     },
 5     "autoload": {
 6         "psr-0": {
 7             "PhpspecExample\\": "src/"
 8         }
 9     }
10 }

1 $ composer install

Now we can start the TDD Cycle:

First of all, we’ll tell PHPSpec to create a new Spec file. To do this run:

1 $ phpspec desc PhpspecExample\\GreatestCommonDivisorFinder

This will create a test file called spec/PhpspecExample/GreatestCommonDivisorFinderSpec.php. To run it use:

1 $ phpspec run --format=pretty

PHPSpec will say it can’t find the PhpspecExample\GreatestCommonDivisorFinder class and offer to create it, say Yes and run will create it and run the tests again. This time the test should pass.

Output Formatting

The --format=pretty option is not necessary. I have added it because it produces nice output which I can paste into this book.

There are other formats available, these are: progress (the default), html, pretty, junit and dot.

At this point 2 files have been created for us. The test:

spec/PhpspecExample/GreatestCommonDivisorFinderSpec.php


 1 <?php
 2 
 3 namespace spec\PhpspecExample;
 4 
 5 use PhpSpec\ObjectBehavior;
 6 use Prophecy\Argument;
 7 
 8 class GreatestCommonDivisorFinderSpec extends ObjectBehavior
 9 {
10     function it_is_initializable()
11     {
12         $this->shouldHaveType('PhpspecExample\GreatestCommonDivisorFinder');
13     }
14 }

And the class we are going to implement:

src/PhpspecExample/GreatestCommonDivisorFinder.php


1 <?php
2 
3 namespace PhpspecExample;
4 
5 class GreatestCommonDivisorFinder
6 {
7 }

The it_is_initializable test has served it’s purpose now so you can remove that from the test.

Red

Now we need to think what the simplest condition we can test is, which will make progress towards the final goal.

Let’s start with the condition that when both numbers are the same, then that number is the greatest common divisor.

Add the following test to the spec file:

spec/PhpspecExample/GreatestCommonDivisorFinderSpec.php


1     function it_returns_the_number_if_both_values_are_that_number()
2     {
3         $this->findGreatestDivisor(5, 5)->shouldReturn(5);
4     }

Now we have to see this fail, so run:

1 $ phpspec run --format=pretty

Again PHPSpec says that the findGreatestDivisor method does not exist and offers to create it. Say yes, this will add the empty method to PhpspecExample\GreatestCommonDivisorFinder and run it again. At this point you should see some red:

 1 $ phpspec run --format=pretty
 2 
 3       PhpspecExample\GreatestCommonDivisorFinder
 4 
 5   10  x returns the number if both values are that number
 6         expected [integer:5], but got null.
 7 
 8 ----  failed examples
 9 
10         PhpspecExample/GreatestCommonDivisorFinder
11   10  x returns the number if both values are that number
12         expected [integer:5], but got null.
13 
14 
15 1 specs
16 1 examples (1 failed)
17 11ms

This tells us that the test was expecting the value 5 to be returned, but null was returned instead. Time to make make this test go green…

Green

Remember that in the green stage, we must only add the smallest amount of code to make the test pass. In this case all we need to do is return the value 5. Update the PhpspecExample\GreatestCommonDivisorFinder::findGreatestDivisor() method and re-run the tests:

src/PhpspecExample/GreatestCommonDivisorFinder.php


1     public function findGreatestDivisor($a, $b)
2     {
3         return 5;
4     }

This time we see the green result:

 1 $ phpspec run --format=pretty
 2 
 3       PhpspecExample\GreatestCommonDivisorFinder
 4 
 5   10  ✓ returns the number if both values are that number
 6 
 7 
 8 1 specs
 9 1 examples (1 passed)
10 9ms
Refactor

This is the point when we do our refactoring. However, right now there’s not much to refactor, so let’s move straight on to the next failing test.

Red

For this next test, let’s check that when the first number is a divisor of the second number, then the first number should be returned. To do this add the following test:

spec/PhpspecExample/GreatestCommonDivisorFinderSpec.php


1     function it_returns_the_first_number_if_it_is_a_divisor_of_the_second()
2     {
3         $this->findGreatestDivisor(3, 9)->shouldReturn(3);
4     }

Now run PHPSpec to see red:

 1 $ phpspec run --format=pretty
 2 
 3      PhpspecExample\GreatestCommonDivisorFinder
 4 
 5   10  ✓ returns the number if both values are that number
 6   15  x returns the first number if it is a divisor of the second
 7         expected [integer:3], but got [integer:5].
 8 
 9 ----  failed examples
10 
11         PhpspecExample/GreatestCommonDivisorFinder
12   15  x returns the first number if it is a divisor of the second
13         expected [integer:3], but got [integer:5].
14 
15 
16 1 specs
17 2 examples (1 passed, 1 failed)
18 12ms

The first test continues to pass, but the second one does not since our implementation currently only returns the integer 5.

Green

Again, using the smallest change possible, we can easily change this to green by just returning the first number:

src/PhpspecExample/GreatestCommonDivisorFinder.php


1     public function findGreatestDivisor($a, $b)
2     {
3         return $a;
4     }

Now when running PHPSpec we see that both tests are successfully passing:

 1 $ phpspec run --format=pretty
 2 
 3       PhpspecExample\GreatestCommonDivisorFinder
 4 
 5   10  ✓ returns the number if both values are that number
 6   15  ✓ returns the first number if it is a divisor of the second
 7 
 8 
 9 1 specs
10 2 examples (2 passed)
11 11ms
Refactor

There’s still nothing to refactor yet. So on to the next failing test…

Red

Let’s now try the previous test the other way around: when the second number is a divisor of the first, the second number should be returned.

spec/PhpspecExample/GreatestCommonDivisorFinderSpec.php


1     function it_returns_the_second_number_if_it_is_a_divisor_of_the_first()
2     {
3         $this->findGreatestDivisor(9, 3)->shouldReturn(3);
4     }

Run PHPSpec again (you have to see it fail!):

 1 $ phpspec run --format=pretty
 2 
 3       PhpspecExample\GreatestCommonDivisorFinder
 4 
 5   10  ✓ returns the number if both values are that number
 6   15  ✓ returns the first number if it is a divisor of the second
 7   20  x returns the second number if it is a divisor of the first
 8         expected [integer:3], but got [integer:9].
 9 
10 ----  failed examples
11 
12         PhpspecExample/GreatestCommonDivisorFinder
13   20  x returns the second number if it is a divisor of the first
14         expected [integer:3], but got [integer:9].
15 
16 
17 1 specs
18 3 examples (2 passed, 1 failed)
19 13ms
Green

To make this one pass we can simply return the smaller of the two numbers:

src/PhpspecExample/GreatestCommonDivisorFinder.php


1     public function findGreatestDivisor($a, $b)
2     {
3         return min($a, $b);
4     }

Yet again, we run the tests and see the successful results:

 1 $ phpspec run --format=pretty
 2 
 3       PhpspecExample\GreatestCommonDivisorFinder
 4 
 5   10  ✓ returns the number if both values are that number
 6   15  ✓ returns the first number if it is a divisor of the second
 7   20  ✓ returns the second number if it is a divisor of the first
 8 
 9 
10 1 specs
11 3 examples (3 passed)
12 10ms
Refactor

Still nothing to refactor so let’s move on…

Red

How about if there’s no common divisor other than then number 1? Let’s write a test for that:

spec/PhpspecExample/GreatestCommonDivisorFinderSpec.php


1     function it_returns_1_if_there_is_no_greater_divisor()
2     {
3         $this->findGreatestDivisor(3, 5)->shouldReturn(1);
4     }

As always, run the tests and see it fail:

 1 $ phpspec run --format=pretty
 2 
 3       PhpspecExample\GreatestCommonDivisorFinder
 4 
 5   10  ✓ returns the number if both values are that number
 6   15  ✓ returns the first number if it is a divisor of the second
 7   20  ✓ returns the second number if it is a divisor of the first
 8   25  x returns 1 if there is no greater divisor
 9         expected [integer:1], but got [integer:3].
10 
11 ----  failed examples
12 
13         PhpspecExample/GreatestCommonDivisorFinder
14   25  x returns 1 if there is no greater divisor
15         expected [integer:1], but got [integer:3].
16 
17 
18 1 specs
19 4 examples (3 passed, 1 failed)
20 13ms
Green

This one is a tiny bit more complicated. To solve it let’s say that if the lower of the 2 numbers is not a factor of one of the numbers, then return 1:

src/PhpspecExample/GreatestCommonDivisorFinder.php


 1     public function findGreatestDivisor($a, $b)
 2     {
 3         $divisor = min($a, $b);
 4 
 5         if ($a % $divisor !== 0 || $b % $divisor !== 0) {
 6             $divisor = 1;
 7         }
 8 
 9         return $divisor;
10     }

Run the tests:

 1 $ phpspec run --format=pretty
 2 
 3       PhpspecExample\GreatestCommonDivisorFinder
 4 
 5   10  ✓ returns the number if both values are that number
 6   15  ✓ returns the first number if it is a divisor of the second
 7   20  ✓ returns the second number if it is a divisor of the first
 8   25  ✓ returns 1 if there is no greater divisor
 9 
10 
11 1 specs
12 4 examples (4 passed)
13 11ms

So far, so good!

Refactor

Finally, something to refactor! There is a duplication of the logic to check if the $divisor variable is a factor of a variable. Let’s extract it out with the extract method refactoring like so:

src/PhpspecExample/GreatestCommonDivisorFinder.php


 1 <?php
 2 
 3 namespace PhpspecExample;
 4 
 5 class GreatestCommonDivisorFinder
 6 {
 7     private $divisor;
 8 
 9     public function findGreatestDivisor($a, $b)
10     {
11         $this->divisor = min($a, $b);
12 
13         if (!$this->divisorIsFactorOf($a) || !$this->divisorIsFactorOf($b)) {
14             $this->divisor = 1;
15         }
16 
17         return $this->divisor;
18     }
19 
20     private function divisorIsFactorOf($target)
21     {
22         return $target % $this->divisor === 0;
23     }
24 }

Now run the tests to make sure they still pass:

 1 $ phpspec run --format=pretty
 2 
 3       PhpspecExample\GreatestCommonDivisorFinder
 4 
 5   10  ✓ returns the number if both values are that number
 6   15  ✓ returns the first number if it is a divisor of the second
 7   20  ✓ returns the second number if it is a divisor of the first
 8   25  ✓ returns 1 if there is no greater divisor
 9 
10 
11 1 specs
12 4 examples (4 passed)
13 11ms
Red

OK. Next let’s try a divisor that is not 1, or either of the numbers themselves:

spec/PhpspecExample/GreatestCommonDivisorFinderSpec.php


1     function it_returns_a_divisor_of_both_numbers()
2     {
3         $this->findGreatestDivisor(6, 9)->shouldReturn(3);
4     }

Watch the test fail:

 1 $ phpspec run --format=pretty
 2 
 3       PhpspecExample\GreatestCommonDivisorFinder
 4 
 5   10  ✓ returns the number if both values are that number
 6   15  ✓ returns the first number if it is a divisor of the second
 7   20  ✓ returns the second number if it is a divisor of the first
 8   25  ✓ returns 1 if there is no greater divisor
 9   30  x returns a divisor of both numbers
10         expected [integer:3], but got [integer:1].
11 
12 ----  failed examples
13 
14         PhpspecExample/GreatestCommonDivisorFinder
15   30  x returns a divisor of both numbers
16         expected [integer:3], but got [integer:1].
17 
18 
19 1 specs
20 5 examples (4 passed, 1 failed)
21 14ms
Green

We actually only have to make a very small change here to make this pass: we simply change the if to a while, and decrement the divisor in the loop:

spec/PhpspecExample/GreatestCommonDivisorFinderSpec.php


 1     public function findGreatestDivisor($a, $b)
 2     {
 3         $this->divisor = min($a, $b);
 4 
 5         // leanpub-insert-start
 6         while (!$this->divisorIsFactorOf($a) || !$this->divisorIsFactorOf($b)) {
 7             $this->divisor--;
 8         }
 9         // leanpub-insert-end
10 
11         return $this->divisor;
12     }

Run the tests:

 1 $ phpspec run --format=pretty
 2 
 3       PhpspecExample\GreatestCommonDivisorFinder
 4 
 5   10  ✓ returns the number if both values are that number
 6   15  ✓ returns the first number if it is a divisor of the second
 7   20  ✓ returns the second number if it is a divisor of the first
 8   25  ✓ returns 1 if there is no greater divisor
 9   30  ✓ returns a divisor of both numbers
10 
11 
12 1 specs
13 5 examples (5 passed)
14 11ms

Everything has passed! And, if you study the code you should see we’ve reached a final solution to find the greatest common divisor or 2 numbers.

If you really want to double check it, you could add this extra test, but it will pass straight away:

spec/PhpspecExample/GreatestCommonDivisorFinderSpec.php


1     function it_returns_the_greatest_divisor_of_both_numbers()
2     {
3         $this->findGreatestDivisor(12, 18)->shouldReturn(6);
4     }

Refactor

Looking at the code that we’ve produced, I’d say it’s pretty neat already, and doesn’t require any additional refactoring. Maybe we could just add some docblocks for type information.

The Result

Here is this final result. A complete solution to our original problem, achieved by TDD:

src/PhpspecExample/GreatestCommonDivisorFinder.php


 1 <?php
 2 
 3 namespace PhpspecExample;
 4 
 5 class GreatestCommonDivisorFinder
 6 {
 7     /** @var int */
 8     private $divisor;
 9 
10     /**
11      * @param int $a
12      * @param int $b
13      *
14      * @return int
15      */
16     public function findGreatestDivisor($a, $b)
17     {
18         $this->divisor = min($a, $b);
19 
20         while (!$this->divisorIsFactorOf($a) || !$this->divisorIsFactorOf($b)) {
21             $this->divisor--;
22         }
23 
24         return $this->divisor;
25     }
26 
27     /**
28      * @param int $target
29      *
30      * @return bool
31      */
32     private function divisorIsFactorOf($target)
33     {
34         return $target % $this->divisor === 0;
35     }
36 }

Test Doubles

I’ve already mentioned test doubles, and how they can be used to help test units of code in isolation by replacing the unit’s dependencies. Now let’s take a look at how this is actually done.

Types of Test Doubles

Test doubles take on different forms depending on how the are used. Each of these different types are used to solve a different problem. Let’s take a look at the different types.

Dummy

A dummy is the simplest test double. It simply serves as a place holder for a dependency. It’s essentially an empty class which implements the dependency’s interface. Dummies are used when the unit being tested has a required dependency, but the dependency is not needed for the functionality being tested.

Dummy test double example


 1 /**
 2  * Method to be tested.
 3  *
 4  * @param number $a
 5  * @param number $b
 6  *
 7  * @return number
 8  */
 9 public function addValues(Writer $writer, $a, $b)
10 {
11     $writer->write("Adding $a and $b");
12 
13     return $a + $b;
14 }
15 
16 /**
17  * The test.
18  *
19  * Here we only want to test the addition takes place and don't care
20  * about the writer. However, the writer is required, so we provide a dummy in
21  * its place.
22  */
23 function test_dummy()
24 {
25     $writer = new DummyWriter();
26     $examples = new Examples();
27 
28     $this->assertEquals(5, $examples->addValues($writer, 2, 3));
29 }
30 
31 /**
32  * The dummy writer.
33  *
34  * No functionality is requried, it just needs to implement the Writer
35  * interface.
36  */
37 final class DummyWriter implements \Writer
38 {
39     public function write($string)
40     {
41     }
42 }

Stub

A stub is the next simplest test double. It simply returns constant values from the methods in the public interface. Stubs are used to isolate the unit under test, from the complexity of its dependency, or for testing an interface or abstract class which has no implementation available.

Stub test double example


 1 /**
 2  * The method being tested.
 3  *
 4  * @return int
 5  */
 6 public function doubleInput(Reader $reader)
 7 {
 8     return $reader->readInt() * 2;
 9 }
10 
11 /**
12  * The test.
13  *
14  * We don't want to use a real Reader to check the logic, so we use a stub
15  * which returns a constant value, which we can reliably check.
16  */
17 function test_stub()
18 {
19     $reader = new StubReader();
20     $examples = new Examples();
21 
22     $this->assertEquals(14, $examples->doubleInput($reader));
23 }
24 
25 /**
26  * The stub reader.
27  *
28  * There is no logic in a stub, it simply returns constant values.
29  */
30 final class StubReader implements Reader
31 {
32     public function readInt($src = self::STDIN)
33     {
34         return 7;
35     }
36 }

Fake

A fake contains logic which emulates a simplified and reliable version of the dependency. Fakes are used when the dependency is suitably complex, that a stub is not powerful enough.

Fake test double example


 1 /**
 2  * The method being tested.
 3  *
 4  * Here Reader::readInt() is called multiple times with different parameters.
 5  */
 6 public function addFromInputAndFile(Reader $reader, $filename)
 7 {
 8     return $reader->readInt(Reader::STDIN) + $reader->readInt($filename);
 9 }
10 
11 /**
12  * The test.
13  *
14  * We're using a fake as we want different values to be returned depending
15  * on the parameters provided.
16  */
17 function test_fake()
18 {
19     $reader = new FakeReader();
20     $examples = new Examples();
21 
22     $this->assertEquals(
23         7,
24         $examples->addFromInputAndFile($reader, 'file.txt')
25     );
26 }
27 
28 /**
29  * The fake reader.
30  *
31  * Here we return a 2 if the reader is instructed to read from STDIN, otherwise
32  * it returns 5.
33  */
34 final class FakeReader implements Reader
35 {
36     public function readInt($src = self::STDIN)
37     {
38         return $src == self::STDIN ? 2 : 5;
39     }
40 }

Mock

A mock is like a fake, but unlike a fake mocks are aware that they are part of a test suite. Rather than being just a simplified implementation of the dependency’s interface, they contain testing related logic and code.

When crafting test doubles by hand the situation for creating a mock comes up very rarely. However, as we’ll see in a moment, test doubles can be created automatically using mocking frameworks. In this case all test doubles are technically mocks, regardless of the actual way they are being used. For this reason, the term mock is often used interchangeably with test double.

Spy

A spy is a type of mock which records the actions which have been performed on it. After executing the code under test, a spy can be asked if it was interacted with as expected. Spies are used to verify a dependency has be used in the correct way.

Spy test double example


 1 /**
 2  * Method being tested.
 3  *
 4  * @param number $a
 5  * @param number $b
 6  *
 7  * @return number
 8  */
 9 public function addValues(Writer $writer, $a, $b)
10 {
11     $writer->write("Adding $a and $b");
12 
13     return $a + $b;
14 }
15 
16 /**
17  * The test.
18  *
19  * This time, we want to make sure that the writer was instructed to write a
20  * message.
21  */
22 function test_spy()
23 {
24     $writer = new SpyWriter();
25     $examples = new Examples();
26 
27     $examples->addValues($writer, 2, 3);
28 
29     $this->assertTrue(
30         $writer->hasWriteBeenCalledWith('Adding 2 and 3'),
31         '$writer->write("Adding 2 and 3") should have been called'
32     );
33 }
34 
35 /**
36  * The spy write test double.
37  *
38  * The spy records the message that the write function was called with.
39  */
40 final class SpyWriter implements \Writer
41 {
42     private $message;
43 
44     public function write($message)
45     {
46         $this->message = $message;
47     }
48 
49     /**
50      * @param string $message
51      *
52      * @return bool
53      */
54     public function hasWriteBeenCalledWith($message)
55     {
56         return $this->message == $message;
57     }
58 }

Expectations

Expectations serve a similar purpose to spies, except rather than recording what methods have been called so they can be checked later, the methods required to be called are defined first. Not all mocking framework’s provide both spies and expectations, but generally they will support at least one of these features.

The one thing which using expectations does, is mix up the given, when, then order. For this reason, I prefer to use spies when possible.

Mocking Frameworks

There are many mocking frameworks available for PHP. PHPUnit has one built in, PhpSpec uses one called Prophecy, and there are others available too. The main reasons for using a different framework are, either because it provides some extra features, or because they produce tests which you think are easier to understand.

Some examples of other mocking frameworks are Mockery, Phake and Facebook’s FBMock.

Now, let’s quickly take a look at the previous test double examples, this time using PHPUnit’s and PHPSpec’s Prophecy framework’s mocking facilities.

PHPUnit

PHPUnit’s built in mocking facilities are quite verbose, and often considered to not be the easiest to read. It also doesn’t support spies, so you have to use expectations. For these reasons, alternative mocking frameworks are often chosen when working with PHPUnit.

Here’s the examples with PHPUnit:

tests/MockExampleTest.php


 1 <?php
 2 
 3 namespace tests;
 4 
 5 use Examples;
 6 use Reader;
 7 
 8 class MockExampleTest extends \PHPUnit_Framework_TestCase
 9 {
10     function test_dummy()
11     {
12         $examples = new Examples();
13 
14         $writer = $this->getMock('Writer');
15 
16         $this->assertEquals(5, $examples->addValues($writer, 2, 3));
17     }
18 
19     function test_stub()
20     {
21         $examples = new Examples();
22 
23         $reader = $this->getMock('Reader');
24 
25         $reader->expects($this->any())
26                ->method('readInt')
27                ->will($this->returnValue(7));
28 
29         $this->assertEquals(14, $examples->doubleInput($reader));
30     }
31 
32     function test_fake()
33     {
34         $examples = new Examples();
35 
36         $reader = $this->getMock('Reader');
37 
38         $reader->expects($this->at(0))
39                ->method('readInt')
40                ->with($this->equalTo(Reader::STDIN))
41                ->will($this->returnValue(2));
42 
43         $reader->expects($this->at(1))
44                ->method('readInt')
45                ->with($this->equalTo('file.txt'))
46                ->will($this->returnValue(5));
47 
48         $this->assertEquals(
49             7,
50             $examples->addFromInputAndFile($reader, 'file.txt')
51         );
52     }
53 
54     function test_expectation()
55     {
56         $examples = new Examples();
57 
58         $writer = $this->getMock('Writer');
59 
60         $writer->expects($this->once())
61                ->method('write')
62                ->with($this->equalTo('Adding 2 and 3'));
63 
64         $examples->addValues($writer, 2, 3);
65     }
66 }

PHPSpec & Prophecy

Prophecy is very much a part of PHPSpec. By using PHPSpec, you are choosing to use Prophecy also. That said, Prophecy doesn’t have to be used with PHPSpec and can be used with other test frameworks also.

PHPSpec makes mocking exceptionally simple. You don’t need to call any special methods to create a mock, rather you just provide a typehinted parameter to the test method, and PHPSpec will create and inject the mock automatically.

Here’s the same examples with PHPSpec:

spec/ExamplesSpec.php


 1 <?php
 2 
 3 namespace spec;
 4 
 5 use PhpSpec\ObjectBehavior;
 6 use Reader;
 7 use Writer;
 8 
 9 class ExamplesSpec extends ObjectBehavior
10 {
11     function it_uses_mock_as_dummy(Writer $writer)
12     {
13         $this->addValues($writer, 2, 3)->shouldReturn(5);
14     }
15 
16     function it_uses_mock_as_stub(Reader $reader)
17     {
18         $reader->readInt()->willReturn(7);
19 
20         $this->doubleInput($reader)->shouldReturn(14);
21     }
22 
23     function it_uses_mock_as_fake(Reader $reader)
24     {
25         $reader->readInt(Reader::STDIN)->willReturn(2);
26         $reader->readInt('file.txt')->willReturn(5);
27 
28         $this->addFromInputAndFile($reader, 'file.txt')->shouldReturn(7);
29     }
30 
31     function it_uses_mock_as_spy(Writer $writer)
32     {
33         $this->addValues($writer, 2, 3);
34 
35         $writer->write('Adding 2 and 3')->shouldHaveBeenCalled();
36     }
37 
38     function it_can_set_expectations_on_mocks(Writer $writer)
39     {
40         $writer->write('Adding 2 and 3')->shouldBeCalled();
41 
42         $this->addValues($writer, 2, 3);
43     }
44 }

Katas

In order to develop and hone your programming skills, the concept of katas has become a popular way to practice them. A kata (like a martial arts kata) is a sequence of steps which are performed repeatedly in order to drill and perfect the skills and techniques which they contain.

Some popular katas are Prime Factors, The Bowling Game, String Calculator and Roman Numerals. You can easily find the details and demonstrations of these katas in many languages with a quick web search. That said Ciaran McNulty has put up excellent videos of the Prime Factors and Roman Numerals katas using PHPSpec on Vimeo. I think these are well worth a watch.

Building the Application

This is the main part of the book. Here we’ll work through the complete process of building a robust, extensible and scalable application from scratch.

Getting Started

The Application

A brief description of the application we are going to build is as follows:

The aim is to produce a website, which allows users of the site to view and rate cocktail recipes submitted by other users. They can also submit their own.

Any visitors to the site can view the list of recipes sorted by rating. However, a visitor must register as a user, with a username, email and password, in order to rate or submit recipes.

A recipe consists of the cocktail name, the method and the list of measured ingredients, which consists of the ingredient and amount. The recipe must also keep track of the user who submitted it.

Ratings will be star ratings, with users being able to rate a recipe with 1 to 5 stars.

Quantities can be entered as either millilitres (ml), fluid ounces (fl oz), teaspoons (tsp) or just a number.

The cocktail ingredients available are limited to a selection which can only be added to by an administrator.

Now we’ve got a basic understanding of the application we are going to build, let’s take a quick look at the list of user stories. These are presented in order of priority.

  • A visitor can view a list of recipes
  • A visitor can view a recipe
  • A visitor can register and become a user
  • A visitor can login to become a user
  • A user can rate a recipe
  • A user can add a recipe
  • An administrator can add an ingredient

We will proceed to implement each of these stories in order. This may seem like a very basic application, but it will provide enough functionality to give a good example of how to start building a well designed, extensible application. Also, because we will be emulating an agile process while building the application, details and requirements may change as it progresses, and extra features may be requested.

Creating the Project

Before jumping in, let’s quickly set up a project. Start by creating a directory to build the application in:

1 $ mkdir cocktail-rater
2 $ cd cocktail-rater

Then add the following composer.json

composer.json


 1 {
 2     "require": {
 3         "php": ">=5.5"
 4     },
 5     "require-dev": {
 6         "behat/behat": "3.*",
 7         "phpunit/phpunit": "4.2.*",
 8         "phpspec/phpspec": "2.*@dev"
 9     },
10     "autoload": {
11         "psr-4": {
12             "CocktailRater\\": "src/"
13         }
14     }
15 }

We’re using a PSR-4 autoloader here. Using PSR-4 means everything can exist in a CocktailRater top level namespace, but we can avoid creating an extra directory level for it.

PHPSpec Version

You may have noticed that the PHPSpec requirement is for a development version. The reason for this is: there are some features which we will be using which are not in the stable release yet. When this changes I will update the book.

Now run Composer to install the test tools:

1 $ composer install

We can also configure it to format its output using the pretty formatter by default. That way we don’t need to put it on the command line every time we run it. To do this, create a file called phpspec.yml with the following contents:

phpspec.yml


1 formatter.name: pretty

Finally, initialise Behat so we’re ready to start development:

1 $ behat --init

All done! Now we can start.

The First Story

Let’s look at the first story. Here’s the card:

A visitor can view a list of recipes

  • Displays an empty list if there are no recipes
  • Recipes display the name of the cocktail, the rating and the name of the user who submitted it
  • The list should be presented in descending order of rating

From this information, we can add the following feature file to the project:

features/visitors-can-list-recipes.feature


 1 Feature: A visitor can view a list of recipes
 2     In order to view a list of recipes
 3     As a visitor
 4     I need to be able get a list of recipes
 5 
 6     Scenario: View an empty list of recipes
 7         Given there are no recipes
 8         When I request a list of recipes
 9         Then I should see an empty list
10 
11    Scenario: Viewing a list with 1 recipe
12         Given there's a recipe for "Mojito" by user "tom" with 5 stars
13         When I request a list of recipes
14         Then I should see a list of recipes containing:
15             | name   | rating | user |
16             | Mojito | 5.0    | tom  |
17 
18     Scenario: Recipes are sorted by rating
19         Given there's a recipe for "Daquiri" by user "clare" with 4 stars
20         And there's a recipe for "Pina Colada" by user "jess" with 2 stars
21         And there's a recipe for "Mojito" by user "tom" with 5 stars
22         When I request a list of recipes
23         Then I should see a list of recipes containing:
24             | name        | rating | user  |
25             | Mojito      | 5.0    | tom   |
26             | Daquiri     | 4.0    | clare |
27             | Pina Colada | 2.0    | jess  |

If you try to run Behat with this feature, it will say that the context has missing steps. To add the required snippets run:

1 $  behat --append-snippets

Now we can start working to get these scenarios to pass.

Application Structure

Before jumping straight into writing code, let’s just take a small moment to take a look at the structure we plan to use to build the application.

Proposed Application Structure

Proposed Application Structure

The core part of the application will be the domain model, this will consist of our modelled interpretation of the business rules. It will have no knowledge of how or where the data is stored, the user interface or any non-business related implementation details. To achieve this level of separation we’ll use inversion of control to let the other layers plug in to the domain layer.

Behind the domain model there will be a storage implementation layer for our chosen storage system. The storage system has not yet been decided so we’ll make use of SQLite until we have chosen which one to use. The reasons for using SQLite are that, it allows the use of a database file without needing to set up a database server, and it’s easier to use than writing our own file-based storage system.

In chapter 3 I introduced CQRS and stated that while we are not going to implement it in our application, we will make a distinction between command and query interactions within the application. Therefore, in front of the domain model we’ll have a layer of commands and queries. All interactions with the domain model from the UI will go through these.

Finally, we’ll have the UI website. We’ll start off by mocking this up with some basic HTML, but as our application becomes more complete, we can make use of a modern MVC1 framework. Again, we won’t worry about which one until later on.

Scenario: View an empty list of recipes

Let’s start off by getting the first scenario to pass. As a quick reminder here it is:

View an empty list of recipes


1     Scenario: View an empty list of recipes
2         Given there are no recipes
3         When I request a list of recipes
4         Then I should see an empty list

We’re going to use TDD to create our code from the outside in. What I mean by this is: rather than trying to build the model and then get it to do what we need it to do, we’ll start with what we want it to do and let that help create the model.

Fleshing out the FeatureContext

Behat has already added the required snippet templates to the FeatureContext, so let’s try to pencil in what we want to happen. Take a look at the code I have added first, then I’ll explain it:

features/bootstrap/FeatureContext.php


 1 <?php
 2 
 3 use Behat\Behat\Context\SnippetAcceptingContext;
 4 use Behat\Behat\Tester\Exception\PendingException;
 5 use Behat\Gherkin\Node\PyStringNode;
 6 use Behat\Gherkin\Node\TableNode;
 7 use CocktailRater\Application\Query\ListRecipes;
 8 use CocktailRater\Application\Query\ListRecipesHandler;
 9 use CocktailRater\Application\Query\ListRecipesQuery;
10 use CocktailRater\Application\Query\ListRecipesQueryHandler;
11 use CocktailRater\Testing\Repository\TestRecipeRepository;
12 use PHPUnit_Framework_Assert as Assert;
13 
14 /**
15  * Behat context class.
16  */
17 class FeatureContext implements SnippetAcceptingContext
18 {
19     /** @var RecipeRepository */
20     private $recipeRepository;
21 
22     /** @var mixed */
23     private $result;
24 
25     /**
26      * Initializes context.
27      *
28      * Every scenario gets its own context object.
29      * You can also pass arbitrary arguments to the context constructor through
30      * behat.yml.
31      */
32     public function __construct()
33     {
34     }
35 
36     /**
37      * @BeforeScenario
38      */
39     public function beforeScenario()
40     {
41         $this->recipeRepository = new TestRecipeRepository();
42     }
43 
44     /**
45      * @Given there are no recipes
46      */
47     public function thereAreNoRecipes()
48     {
49         $this->recipeRepository->clear();
50     }
51 
52     /**
53      * @When I request a list of recipes
54      */
55     public function iRequestAListOfRecipes()
56     {
57         $query = new ListRecipesQuery();
58         $handler = new ListRecipesHandler($this->recipeRepository);
59 
60         $this->result = $handler->handle($query);
61     }
62 
63     /**
64      * @Then I should see an empty list
65      */
66     public function iShouldSeeAnEmptyList()
67     {
68         $recipes = $this->result->getRecipes();
69 
70         Assert::assertInternalType('array', $recipes);
71         Assert::assertEmpty($recipes);
72     }
73 
74     /**
75      * @Given there's a recipe for :arg1 by user :arg2 with :arg3 stars
76      */
77     public function theresARecipeForByUserWithStars($arg1, $arg2, $arg3)
78     {
79         throw new PendingException();
80     }
81 
82     /**
83      * @Then I should see a list of recipes containing:
84      */
85     public function iShouldSeeAListOfRecipesContaining(TableNode $table)
86     {
87         throw new PendingException();
88     }
89 }

The thinking I have used here goes something like this:

In order to list recipes we’ll create a query object, then somehow we’ll process that query to get the result. This process will involve fetching all existing recipes and returning the result.

The first line of our test states: “Given there are no recipes”. We’re going to use the Repository design pattern for the storing of objects. So, to make this test pass, we’ve got to ensure that the Repository for storing recipes is empty. I’ve also stated that we’re not going to worry about what storage system we will be using until later. So in the mean time, we can create a simple test repository, which we’ll use to emulate the repository functionality. I’ve decided to name this CocktailRater\Testing\Repository\TestRecipeRepository.

With this information, the first thing we need to do is create an instance of this repository. I’ve done this in the beforeScenario method in the FeatureContext.

Annotations

You may have noticed that I’ve added @BeforeScenario to the docblock for this method. This is known as an annotation and is required to inform Behat to run this method before it runs each scenario.

Annotation strings in the docblock start with the @ symbol. Behat uses annotations for several things - you will see that each snippet function has a @Given, @When or @Then annotation. Again, this is not just a comment, but is actually required by Behat in order to work.

Then, in the thereAreNoRecipes method, we clear the repository to ensure there are no recipes currently stored.

The next line of the test states: “When I request a list of recipes”. For this we create the query object, run it and store the result. I’ve decided that the running of the query will be done by a query handler, and therefore, we’ll use the verb handle to run it. Also, we know that the query handler will need to fetch recipes from the repository, so we pass this to the handler via the constructor. All this is put into action in the iRequestAListOfRecipes method in the FeatureContext.

Finally, the last line of the test says: “Then I should see an empty list”. To make this pass, we’ll simple check the value in the query result. In order to make a Behat snippet fail, it must throw an exception. However, rather than writing our own checking methods, we can make use of the assert methods provided by PHPUnit. For this test we’ve used 2 asserts, one to check the result is an array, and the second to check it’s empty.

At this point, if you try to run Behat you’ll see PHP error messages saying we’ve referenced classes which don’t exist. To fix this lets add the classes…

Writing the Code

The first line of the test requires the repository, and that it has a method called clear. Let’s start by creating that:

src/Testing/Repository/TestRecipeRepository.php


 1 <?php
 2 
 3 namespace CocktailRater\Testing\Repository;
 4 
 5 use CocktailRater\Domain\Repository\RecipeRepository;
 6 
 7 final class TestRecipeRepository
 8 {
 9     public function clear()
10     {
11     }
12 }

Final

You may have noticed the use of the final keyword. For now I’m just going to say that I add this to my classes by default, this is not required but is my preference. I’ll explain the reason for this a bit later on.

Next up let’s create the ListRecipesQuery. A query class will contain the parameters for the query. In this case there are none, so the class simply looks like this:

src/Application/Query/ListRecipesQuery.php


1 <?php
2 
3 namespace CocktailRater\Application\Query;
4 
5 final class ListRecipesQuery
6 {
7 }

Now for the interesting bit: the ListRecipesHandler. From looking at the FeatureContext, this needs to take a repository as a constructor parameter, the query as a parameter to the handle method, and return some object which has a getRecipes method.

Here we don’t want to depend on our test repository, so we’ll create an interface which will be used in its place. For the return value, we’ll create a class called CocktailRater\Application\Query\ListRecipesResult.

Without further ado, here it is:

src/Application/Query/ListRecipesHandler.php


 1 <?php
 2 
 3 namespace CocktailRater\Application\Query;
 4 
 5 use CocktailRater\Domain\Repository\RecipeRepository;
 6 
 7 final class ListRecipesHandler
 8 {
 9     public function __construct(RecipeRepository $repository)
10     {
11     }
12 
13     /** @return ListRecipesResult */
14     public function handle(ListRecipesQuery $query)
15     {
16         return new ListRecipesResult();
17     }
18 }

At this point we’ve created all the classes that were referenced from the FeatureContext, but this last one has just introduced 2 more: the RecipeRepository and the ListRecipesResult. Let’s add them to the project also (this is what I was referring to when I said we’d work from the outside in):

src/Application/Query/ListRecipesResult.php


 1 <?php
 2 
 3 namespace CocktailRater\Application\Query;
 4 
 5 final class ListRecipesResult
 6 {
 7     /** @return array */
 8     public function getRecipes()
 9     {
10         return [];
11     }
12 }

src/Domain/Repository/RecipeRepository.php


1 <?php
2 
3 namespace CocktailRater\Domain\Repository;
4 
5 interface RecipeRepository
6 {
7 }

The ListRecipesResult class simply returns an empty list from getRecipes. This is all it needs to do to make the test pass.

The RecipeRepository interface currently has no methods. This is because the only method currently existing in our test repository is clear, however this method is only relevant for the tests so there is no requirement for it in the actual application.

Now there’s only one thing left to do. The ListRecipesHandler class requires a RecipeRepository to be provided to the constructor, but in the FeatureContext we’ve provided a TestRecipeRepository. To make this work we need to make the test repository implement the interface:

src/Testing/Repository/TestRecipeRepository.php


 1 <?php
 2 
 3 namespace CocktailRater\Testing\Repository;
 4 
 5 use CocktailRater\Domain\Repository\RecipeRepository;
 6 
 7 final class TestRecipeRepository implements RecipeRepository
 8 {
 9     public function clear()
10     {
11     }
12 }

At this point, we should be able to run Behat and see the first scenario pass:

 1 $ behat
 2 Feature: A visitor can view a list of recipes
 3     In order to view a list of recipes
 4     As a visitor
 5     I need to be able get a list of recipes
 6 
 7   Scenario: View an empty list of recipes
 8     Given there are no recipes
 9     When I request a list of recipes
10     Then I should see an empty list
11 
12   Scenario: Viewing a list with 1 recipe
13     Given there's a recipe for "Mojito" by user "tom" with 5 stars
14       TODO: write pending definition
15     When I request a list of recipes
16     Then I should see a list of recipes containing:
17       | name   | rating | user |
18       | Mojito | 5.0    | tom  |
19 
20   Scenario: Recipes are sorted by rating
21     Given there's a recipe for "Daquiri" by user "clare" with 4 stars
22       TODO: write pending definition
23     And there's a recipe for "Pina Colada" by user "jess" with 2 stars
24     And there's a recipe for "Mojito" by user "tom" with 5 stars
25     When I request a list of recipes
26     Then I should see a list of recipes containing:
27       | name        | rating | user  |
28       | Mojito      | 5.0    | tom   |
29       | Daquiri     | 4.0    | clare |
30       | Pina Colada | 2.0    | jess  |
31 
32 3 scenarios (1 passed, 2 pending)
33 11 steps (3 passed, 2 pending, 6 skipped)
34 0m0.36s (9.95Mb)

Scenario: View a list with 1 recipe

We got the first scenario to pass without adding any real logic. To get the next one to pass we need to start filling in some of the blanks that we’ve created.

Updating the FeatureContext

Just like last time, we can start by adding some content to our 2 remaining methods in the FeatureContext. Here I’d just like to point out that you may find it easier to work with one at a time, but for the sake of not making this book too long, I’m condensing the processes down a bit.

features/bootstrap/FeatureContext.php


 1 <?php
 2 
 3 use Behat\Behat\Context\SnippetAcceptingContext;
 4 use Behat\Behat\Tester\Exception\PendingException;
 5 use Behat\Gherkin\Node\PyStringNode;
 6 use Behat\Gherkin\Node\TableNode;
 7 use CocktailRater\Application\Query\ListRecipes;
 8 use CocktailRater\Application\Query\ListRecipesHandler;
 9 use CocktailRater\Application\Query\ListRecipesQuery;
10 use CocktailRater\Application\Query\ListRecipesQueryHandler;
11 use CocktailRater\Domain\CocktailName;
12 use CocktailRater\Domain\Rating;
13 use CocktailRater\Domain\Recipe;
14 use CocktailRater\Domain\User;
15 use CocktailRater\Domain\Username;
16 use CocktailRater\Testing\Repository\TestRecipeRepository;
17 use PHPUnit_Framework_Assert as Assert;
18 
19 /**
20  * Behat context class.
21  */
22 class FeatureContext implements SnippetAcceptingContext
23 {
24     // ...
25 
26     /**
27      * @Given there's a recipe for :name by user :user with :rating stars
28      */
29     public function theresARecipeForByUserWithStars($name, $user, $rating)
30     {
31         $this->recipeRepository->store(
32             new Recipe(
33                 new CocktailName($name),
34                 new Rating($rating),
35                 new User(new Username($user))
36             )
37         );
38     }
39 
40     /**
41      * @Then I should see a list of recipes containing:
42      */
43     public function iShouldSeeAListOfRecipesContaining(TableNode $table)
44     {
45         $callback = function ($recipe) {
46             return [
47                 (string) $recipe['name'],
48                 (float) $recipe['rating'],
49                 (string) $recipe['user']
50             ];
51         };
52 
53         Assert::assertEquals(
54             array_map($callback, $this->result->getRecipes()),
55             array_map($callback, $table->getHash())
56         );
57     }
58 }

In theresARecipeForByUserWithStars we’re creating a new Recipe object. The Recipe needs a name, rating and user, so we can add what we think look like sensible dependencies via the constructor. We also store this new object in the repository.

In the iShouldSeeAListOfRecipesContaining method, we compare the results returned from the query, with the table of expected results, using PHPUnit’s assertEquals. I’ve also used array_map to ensure both arrays contain the same types since all values in Behat tables are strings.

Adding new Classes to the Model

Unit Tests

Before continuing I’d just like to point out that up until this point I’ve not created any unit tests. From this point on I’ll be using them for all development in the domain model. However, I won’t be showing them or the process of creating them, as it would take up too many pages. However, they’re all available in the example code for the book if you want to study them.

Let’s start off by adding the new classes to the model:

src/Domain/Recipe.php


 1 <?php
 2 
 3 namespace CocktailRater\Domain;
 4 
 5 final class Recipe
 6 {
 7     /** @param string $name */
 8     public function __construct(CocktailName $name, Rating $rating, User $user)
 9     {
10     }
11 }

src/Domain/CocktailName.php


 1 <?php
 2 
 3 namespace CocktailRater\Domain;
 4 
 5 final class CocktailName
 6 {
 7     /** @var string $value */
 8     public function __construct($value)
 9     {
10     }
11 }

src/Domain/Rating.php


 1 <?php
 2 
 3 namespace CocktailRater\Domain;
 4 
 5 final class Rating
 6 {
 7     /** @var float $value */
 8     public function __construct($value)
 9     {
10     }
11 }

src/Domain/User.php


 1 <?php
 2 
 3 namespace CocktailRater\Domain;
 4 
 5 final class User
 6 {
 7     /** @var string $username */
 8     public function __construct(Username $username)
 9     {
10     }
11 }

src/Domain/Username.php


 1 <?php
 2 
 3 namespace CocktailRater\Domain;
 4 
 5 final class Username
 6 {
 7     /** @param string $value */
 8     public function __construct($value)
 9     {
10     }
11 }

We also need to add the store method to the repository interface:

src/Domain/Repository/RecipeRepository.php


 1 <?php
 2 
 3 namespace CocktailRater\Domain\Repository;
 4 
 5 use CocktailRater\Domain\Recipe;
 6 
 7 interface RecipeRepository
 8 {
 9     public function store(Recipe $recipe);
10 }

This also means that we need to add the method to the TestRecipeRepository:

src/Testing/Repository/TestRecipeRepository.php


 1 <?php
 2 
 3 namespace CocktailRater\Testing\Repository;
 4 
 5 use CocktailRater\Domain\Recipe;
 6 use CocktailRater\Domain\Repository\RecipeRepository;
 7 
 8 final class TestRecipeRepository implements RecipeRepository
 9 {
10     public function store(Recipe $recipe)
11     {
12     }
13 
14     public function clear()
15     {
16     }
17 }

Making the Scenario Pass

At this point, only the last line of the scenario should be failing. We’ve got the template of the model laid out, so we just need to fill in the details. To start with, let’s take a look at how the query handler will work:

src/Application/Query/ListRecipesHandler.php


 1 <?php
 2 
 3 namespace CocktailRater\Application\Query;
 4 
 5 use CocktailRater\Domain\Repository\RecipeRepository;
 6 
 7 final class ListRecipesHandler
 8 {
 9     /** @var RecipeRepository */
10     private $repository;
11 
12     public function __construct(RecipeRepository $repository)
13     {
14         $this->repository = $repository;
15     }
16 
17     /** @return ListRecipesResult */
18     public function handle(ListRecipesQuery $query)
19     {
20         $result = new ListRecipesResult();
21 
22         foreach ($this->repository->findAll() as $recipe) {
23             $result->addRecipe(
24                 $recipe->getName()->getValue(),
25                 $recipe->getRating()->getValue(),
26                 $recipe->getUser()->getUsername()->getValue()
27             );
28         }
29 
30         return $result;
31     }
32 }

It’s quite simple really: it fetches all recipes from the repository, adds the details of each one to the result object, then returns the result. This looks good, but we’ve got a bit of work to do to get it all working. First up let’s update the classes in the domain model:

src/Domain/Recipe.php


 1 <?php
 2 
 3 namespace CocktailRater\Domain;
 4 
 5 final class Recipe
 6 {
 7     /** @var CocktailName */
 8     private $name;
 9 
10     /** @var Rating */
11     private $rating;
12 
13     /** @var User */
14     private $user;
15 
16     /** @param string $name */
17     public function __construct(CocktailName $name, Rating $rating, User $user)
18     {
19         $this->name   = $name;
20         $this->rating = $rating;
21         $this->user   = $user;
22     }
23 
24     /** @return CocktailName */
25     public function getName()
26     {
27         return $this->name;
28     }
29 
30     /** @return Rating */
31     public function getRating()
32     {
33         return $this->rating;
34     }
35 
36     /** @return User */
37     public function getUser()
38     {
39         return $this->user;
40     }
41 }

src/Domain/CocktailName.php


 1 <?php
 2 
 3 namespace CocktailRater\Domain;
 4 
 5 use Assert\Assertion;
 6 
 7 final class CocktailName
 8 {
 9     /** @var string */
10     private $value;
11 
12     /** @param string $value */
13     public function __construct($value)
14     {
15         Assertion::string($value);
16 
17         $this->value = $value;
18     }
19 
20     /** @return string */
21     public function getValue()
22     {
23         return $this->value;
24     }
25 }

src/Domain/Rating.php


 1 <?php
 2 
 3 namespace CocktailRater\Domain;
 4 
 5 use Assert\Assertion;
 6 use CocktailRater\Domain\Exception\OutOfBoundsException;
 7 
 8 final class Rating
 9 {
10     /** @var float */
11     private $value;
12 
13     /**
14      * @var float $value
15      *
16      * @throws OutOfBoundsException
17      */
18     public function __construct($value)
19     {
20         Assertion::numeric($value);
21 
22         $this->assertValueIsWithinRange($value);
23 
24         $this->value = (float) $value;
25     }
26 
27     /** @return float */
28     public function getValue()
29     {
30         return $this->value;
31     }
32 
33     /**
34      * @var float $value
35      *
36      * @throws OutOfBoundsException
37      */
38     private function assertValueIsWithinRange($value)
39     {
40         if ($value < 1 || $value > 5) {
41             throw OutOfBoundsException::numberIsOutOfBounds($value, 1, 5);
42         }
43     }
44 }

src/Domain/User.php


 1 <?php
 2 
 3 namespace CocktailRater\Domain;
 4 
 5 final class User
 6 {
 7     /** @var Username */
 8     private $username;
 9 
10     /**
11      * @param string $username
12      *
13      * @return User
14      */
15     public static function fromValues($username)
16     {
17         return new self(new Username($username));
18     }
19 
20     /** @var string $username */
21     public function __construct(Username $username)
22     {
23         $this->username = $username;
24     }
25 
26     /** @return Username */
27     public function getUsername()
28     {
29         return $this->username;
30     }
31 }

src/Domain/Username.php


 1 <?php
 2 
 3 namespace CocktailRater\Domain;
 4 
 5 use Assert\Assertion;
 6 
 7 final class Username
 8 {
 9     /** @var string */
10     private $value;
11 
12     /** @param string $value */
13     public function __construct($value)
14     {
15         Assertion::string($value);
16 
17         $this->value = $value;
18     }
19 
20     /** @param */
21     public function getValue()
22     {
23         return $this->value;
24     }
25 }

In the domain model, we’ve started to make use of Benjamin Eberlei’s Assert library. For this to work we need to install the dependency with Composer by running:

1 $ composer require beberlei/assert:@stable

Using 3rd Party Libraries in the Domain Model

Adding a dependency to a 3rd party library is something that should not be done without serious consideration. A better approach is to use Inversion of Control to make the model depend on the library via a layer of abstraction. The Adapter design pattern is a very good tool for this job.

So, with that said, why am I using the Assert library from within the domain model? The reason is: firstly it’s a well-used and stable library made up of utility methods which have no side effects. Secondly, and more importantly, I’m using it in a way which adds, what I think, is a missing feature in the PHP language: namely typehints for scalar types and arrays.

There is an interesting discussion with Mathais Verraes on the DDDinPHP Google Group about adding dependencies to 3rd party libraries to your domain model. However, the bottom line here is: before doing this you should exercise extreme consideration of what you are about to do.

One thing which may have caught your eye in the User class is the fromValues static method. This is known as a named constructor. It’s a way in which we can provide alternate constructors for classes, and is one of the few valid uses of the static keyword. Since it maintains no state, and works in a purely functional way, it is a safe use of static. At this point fromValues has only been used in the unit tests, even so, I felt the neater tests were a good enough reason to add it.

Another thing we have done here, is restricted the value allowed for a rating to be between 1 and 5. If it falls outside of this range, we throw an exception. The appropriate exception to be throw here is PHP SPL’s OutOfBoundsException. However, rather than throw it directly, we’ve extended it so that it can be tracked down as coming from our application. Let’s take a quick look at it:

src/Domain/Exception/OutOfBoundsException.php


 1 <?php
 2 
 3 namespace CocktailRater\Domain\Exception;
 4 
 5 class OutOfBoundsException extends \OutOfBoundsException
 6 {
 7     /**
 8      * @param number $number
 9      * @param number $min
10      * @param number $max
11      *
12      * @return OutOfBoundsException
13      */
14     public static function numberIsOutOfBounds($number, $min, $max)
15     {
16         return new static(sprintf(
17             'The number %d is out of bounds, expected a number between %d and %d\
18 .',
19             $number,
20             $min,
21             $max
22         ));
23     }
24 }

Again you’ll notice the use of a named constructor. I think this is a really neat way to keep the exception messages neat and tidy, and in a relevant place.

Next, let’s quickly update the ListRecipesResult class:

src/Application/Query/ListRecipesResult.php


 1 <?php
 2 
 3 namespace CocktailRater\Application\Query;
 4 
 5 final class ListRecipesResult
 6 {
 7     /** @var array */
 8     private $recipes = [];
 9 
10     /**
11      * @param string $name
12      * @param float  $rating
13      * @param string $username
14      */
15     public function addRecipe($name, $rating, $username)
16     {
17         $this->recipes[] = [
18             'name'     => $name,
19             'rating'   => $rating,
20             'user' => $username
21         ];
22     }
23 
24     /** @return array */
25     public function getRecipes()
26     {
27         return $this->recipes;
28     }
29 }

Finally, we need to update the functionality of the repository to return the list of recipes stored:

src/Domain/Repository/RecipeRepository.php


 1 <?php
 2 
 3 namespace CocktailRater\Domain\Repository;
 4 
 5 use CocktailRater\Domain\Recipe;
 6 
 7 interface RecipeRepository
 8 {
 9     public function store(Recipe $recipe);
10 
11     /** @return Recipe[] */
12     public function findAll();
13 }

src/Testing/Repository/TestRecipeRepository.php


 1 <?php
 2 
 3 namespace CocktailRater\Testing\Repository;
 4 
 5 use CocktailRater\Domain\Recipe;
 6 use CocktailRater\Domain\Repository\RecipeRepository;
 7 
 8 final class TestRecipeRepository implements RecipeRepository
 9 {
10     /** @var Recipe[] */
11     private $recipes = [];
12 
13     public function store(Recipe $recipe)
14     {
15         $this->recipes[] = $recipe;
16     }
17 
18     public function findAll()
19     {
20         return $this->recipes;
21     }
22 
23     public function clear()
24     {
25     }
26 }

As you can see, we’ve created an in-memory test repository. This is good enough for what we need so far.

You can now run Behat and watch the second scenario pass.

 1 $ behat
 2 Feature: A visitor can view a list of recipes
 3     In order to view a list of recipes
 4     As a visitor
 5     I need to be able get a list of recipes
 6 
 7   Scenario: View an empty list of recipes
 8     Given there are no recipes
 9     When I request a list of recipes
10     Then I should see an empty list
11 
12   Scenario: Viewing a list with 1 recipe
13     Given there's a recipe for "Mojito" by user "tom" with 5 stars
14     When I request a list of recipes
15     Then I should see a list of recipes containing:
16       | name   | rating | user |
17       | Mojito | 5.0    | tom  |
18 
19   Scenario: Recipes are sorted by rating
20     Given there's a recipe for "Daquiri" by user "clare" with 4 stars
21     And there's a recipe for "Pina Colada" by user "jess" with 2 stars
22     And there's a recipe for "Mojito" by user "tom" with 5 stars
23     When I request a list of recipes
24     Then I should see a list of recipes containing:
25       | name        | rating | user  |
26       | Mojito      | 5.0    | tom   |
27       | Daquiri     | 4.0    | clare |
28       | Pina Colada | 2.0    | jess  |
29       Failed asserting that two arrays are equal.
30       --- Expected
31       +++ Actual
32       @@ @@
33        Array (
34            0 => Array (
35       +        0 => 'Mojito'
36       +        1 => 5.0
37       +        2 => 'tom'
38       +    )
39       +    1 => Array (
40                0 => 'Daquiri'
41                1 => 4.0
42                2 => 'clare'
43            )
44       -    1 => Array (
45       +    2 => Array (
46                0 => 'Pina Colada'
47                1 => 2.0
48                2 => 'jess'
49       -    )
50       -    2 => Array (
51       -        0 => 'Mojito'
52       -        1 => 5.0
53       -        2 => 'tom'
54            )
55        )
56 
57 --- Failed scenarios:
58 
59     features/visitors-can-list-recipes.feature:18
60 
61 3 scenarios (2 passed, 1 failed)
62 11 steps (10 passed, 1 failed)
63 0m0.05s (10.60Mb)

Scenario: Recipes are sorted by rating

You may have already noticed, that when you run Behat now most of our final scenario already passes, The only thing which fails is the order in which the recipes are listed. To fix this we can go straight into the ListRecipesHandler, and sort the recipes there:

src/Application/Query/ListRecipesHandler.php


 1 <?php
 2 
 3 namespace CocktailRater\Application\Query;
 4 
 5 use CocktailRater\Domain\Repository\RecipeRepository;
 6 use CocktailRater\Domain\Recipe;
 7 
 8 final class ListRecipesHandler
 9 {
10     /** @var RecipeRepository */
11     private $repository;
12 
13     public function __construct(RecipeRepository $repository)
14     {
15         $this->repository = $repository;
16     }
17 
18     /** @return ListRecipesResult */
19     public function handle(ListRecipesQuery $query)
20     {
21         $result = new ListRecipesResult();
22 
23         foreach ($this->getAllRecipesSortedByRating() as $recipe) {
24             $result->addRecipe(
25                 $recipe->getName()->getValue(),
26                 $recipe->getRating()->getValue(),
27                 $recipe->getUser()->getUsername()->getValue()
28             );
29         }
30 
31         return $result;
32     }
33 
34     private function getAllRecipesSortedByRating()
35     {
36         $recipes = $this->repository->findAll();
37 
38         usort($recipes, function (Recipe $a, Recipe $b) {
39             return $a->isHigherRatedThan($b) ? -1 : 1;
40         });
41 
42         return $recipes;
43     }
44 }

We also need to add new comparison methods to both the Recipe and Rating classes:

src/Domain/Recipe.php


 1 <?php
 2 
 3 namespace CocktailRater\Domain;
 4 
 5 use Assert\Assertion;
 6 
 7 final class Recipe
 8 {
 9     // ...
10 
11     /** @return bool */
12     public function isHigherRatedThan(Recipe $other)
13     {
14         return $this->rating->isHigherThan($other->rating);
15     }
16 }

src/Domain/Rating.php


 1 <?php
 2 
 3 namespace CocktailRater\Domain;
 4 
 5 use Assert\Assertion;
 6 use CocktailRater\Domain\Exception\OutOfBoundsException;
 7 
 8 final class Rating
 9 {
10     // ...
11 
12     /** @return bool */
13     public function isHigherThan(Rating $other)
14     {
15         return $this->value > $other->value;
16     }
17 }

That’s it, the first feature is done!

 1 $ behat
 2 Feature: A visitor can view a list of recipes
 3     In order to view a list of recipes
 4     As a visitor
 5     I need to be able get a list of recipes
 6 
 7   Scenario: View an empty list of recipes
 8     Given there are no recipes
 9     When I request a list of recipes
10     Then I should see an empty list
11 
12   Scenario: Viewing a list with 1 recipe
13     Given there's a recipe for "Mojito" by user "tom" with 5 stars
14     When I request a list of recipes
15     Then I should see a list of recipes containing:
16       | name   | rating | user |
17       | Mojito | 5.0    | tom  |
18 
19   Scenario: Recipes are sorted by rating
20     Given there's a recipe for "Daquiri" by user "clare" with 4 stars
21     And there's a recipe for "Pina Colada" by user "jess" with 2 stars
22     And there's a recipe for "Mojito" by user "tom" with 5 stars
23     When I request a list of recipes
24     Then I should see a list of recipes containing:
25       | name        | rating | user  |
26       | Mojito      | 5.0    | tom   |
27       | Daquiri     | 4.0    | clare |
28       | Pina Colada | 2.0    | jess  |
29 
30 3 scenarios (3 passed)
31 11 steps (11 passed)
32 0m0.04s (10.48Mb)

Tidying Up

Now the feature is complete, let’s take a little look and see if there’s anything we can do to make the code a bit better.

The main thing which needs to be improved here is chaining of methods in the query handler. We’ve created have ugly lines of code like this:

1 $recipe->getUser()->getUsername()->getValue()

Big chains of method calls like this violate the Law of Demeter which states: you should only talk to your immediate friends. This means you should only call methods or access properties of objects which are: properties of the current class, are parameters to the current method, or have been created inside the method. This law is pretty much stating the same thing as the one dot per line rule of Object Calisthenics. Note that PHP requires the use of $this-> to call methods and access properties, so it’s actually two arrows per line.

So, how to this issue? One approach might be to ask the top level class (aggregate) to ask the next level down to return the value, repeating down the hierarchy. Here’s an example:

 1 class Recipe
 2 {
 3     // ...
 4 
 5     public function getUsername()
 6     {
 7         return $this->user->getUsernameValue();
 8     }
 9 }
10 
11 class User
12 {
13     // ...
14 
15     public function getUsernameValue()
16     {
17         return $this->username->getValue();
18     }
19 }

However, if you’re going to do this for more than 2 or 3 values, the interface is going to start to get pretty bloated. Another way might be to add a method to the Recipe class to return all its values as an array or value object. There are other ways you could do this, but for this project let’s use a combination of these 2 methods. If only 1 or 2 getters are required we’ll consider using them, otherwise we’ll use a read method to return an object (I prefer objects to arrays because, even though they require extra code, the content is well defined and they can be immutable, However, using an array or object with public properties, might be appropriate for your project).

Exposing Recipe Values

With this in mind, let’s expose the contents of the Recipe class via a details value object. We do this by creating 2 new classes, one for Recipe and one for User:

src/Domain/RecipeDetails.php


 1 <?php
 2 
 3 namespace CocktailRater\Domain;
 4 
 5 final class RecipeDetails
 6 {
 7     /** @var CocktailName */
 8     private $name;
 9 
10     /** @var UserDetails */
11     private $user;
12 
13     /** @var Rating */
14     private $rating;
15 
16     public function __construct(
17         CocktailName $name,
18         UserDetails $user,
19         Rating $rating
20     ) {
21         $this->name   = $name;
22         $this->user   = $user;
23         $this->rating = $rating;
24     }
25 
26     /** @return string */
27     public function getName()
28     {
29         return $this->name->getValue();
30     }
31 
32     /** @return string */
33     public function getUsername()
34     {
35         return $this->user->getUsername();
36     }
37 
38     /** @return float */
39     public function getRating()
40     {
41         return $this->rating->getValue();
42     }
43 }

src/Domain/UserDetails.php


 1 <?php
 2 
 3 namespace CocktailRater\Domain;
 4 
 5 final class UserDetails
 6 {
 7     /** @var Username */
 8     private $username;
 9 
10     public function __construct(Username $username)
11     {
12         $this->username = $username;
13     }
14 
15     /** @return Username */
16     public function getUsername()
17     {
18         return $this->username->getValue();
19     }
20 }

And add the following method to User and Recipe:

CocktailRater/Domain/Recipe.php


1     /** @return RecipeDetails */
2     public function getDetails()
3     {
4         return new RecipeDetails(
5             $this->name
6             $this->user->getDetails(),
7             $this->rating
8         );
9     }

CocktailRater/Domain/User.php


1     /** @return UserDetails */
2     public function getDetails()
3     {
4         return new UserDetails($this->username);
5     }

Then we can update our query handler to use these like so:

CocktailRater/Application/Query/ListRecipesHandler.php


 1     /** @return ListRecipesResult */
 2     public function handle(ListRecipesQuery $query)
 3     {
 4         $result = new ListRecipesResult();
 5 
 6         foreach ($this->getAllRecipesSortedByRating() as $recipe) {
 7             $details = $recipe->getDetails();
 8 
 9             $result->addRecipe(
10                 $details->getName(),
11                 $details->getRating(),
12                 $details->getUsername()
13             );
14         }
15 
16         return $result;
17     }

At this point, we can also remove getUsername from the User class and getName, getRating and getUser from the Recipe class.

Already this is looking a lot neater, but we’re still violating the law of demeter at 2 levels in the handler. Firstly, we’re calling getDetails on a Recipe objects which are not an immediate friends of the handler (since they fetched from a repository). Secondly, we’re calling the get methods on the details object returned from the Recipe objects. Considering this is happening just at the application layer, I don’t really think this is the biggest crime and therefore could be left as is. That said, let’s still try to tidy it up some more.

To do this, let’s get rid of all the calls to the getters on the details objects. We can do this by simply passing in the details object to the result class constructor. The problem with this is that is adds a dependency on the domain model from anywhere that a result object is used. When using a language like Java, C++ or C#, this becomes something that really needs to be fixed, since separate packages need to be able to be compiled and deployed independently. However, PHP doesn’t work like that (maybe one day it will). Even so, it’s probably still good practice to work this way. Also, since we don’t want any other layers which talk to the application, to create result objects, let’s make the result into an interface. Then we can have a concrete result Data Transfer Object, which can know about the details class. Because the dependency from outside is now on the interface only, it’s decoupled form the domain.

Here’s the updated code:

src/Application/Query/ListRecipesResult.php


1 <?php
2 
3 namespace CocktailRater\Application\Query;
4 
5 interface ListRecipesResult
6 {
7     /** @return array */
8     public function getRecipes();
9 }

src/Application/Query/ListRecipesResultData.php


 1 <?php
 2 
 3 namespace CocktailRater\Application\Query;
 4 
 5 use Assert\Assertion;
 6 use CocktailRater\Domain\RecipeDetails;
 7 
 8 final class ListRecipesResultData implements ListRecipesResult
 9 {
10     /** @var RecipeDetails[] */
11     private $recipes = [];
12 
13     public function __construct(array $recipes)
14     {
15         Assertion::allIsInstanceOf($recipes, RecipeDetails::class);
16 
17         $this->recipes = $recipes;
18     }
19 
20     /** @return array */
21     public function getRecipes()
22     {
23         return array_map(
24             function (RecipeDetails $recipe) {
25                 return [
26                     'name'   => $recipe->getName(),
27                     'rating' => $recipe->getRating(),
28                     'user'   => $recipe->getUsername()
29                 ];
30             },
31             $this->recipes
32         );
33     }
34 }

CocktailRater/Application/Query/ListRecipesHandler.php


 1     /** @return ListRecipesResult */
 2     public function handle(ListRecipesQuery $query)
 3     {
 4         return new ListRecipesResultData(
 5             array_map(function (Recipe $recipe) {
 6                 return $recipe->getDetails();
 7             },
 8             $this->getAllRecipesSortedByRating())
 9         );
10     }

That’s almost done! The handler is much neater. But we’ve still not quite conformed to the Law of Demeter, because it still gets the recipe from the repository. In most circumstances, particularly in the domain model, I’m very diligent about obeying the Law of Demeter. However, in this circumstance, I feel we’ve done enough. A good exercise is, to consider how to obey it completely in the handler, but for now I’m going to leave it as it is.

Have we gone too far?

You might be thinking to yourself that this is all a bit excessive. That we have an aggregate, which returns a details value object, which is then copied into a results DTO, which looks almost the same as the value object, and we have an extra interface to describe the result DTO. You might also think that simply passing back the details value object from the handler would be sufficient. Or, that even that would be too much, and the details class is overkill, and a simple associative array would have done. You may even be thinking this looks far too much like Java.

If you are thinking any of these things you are right! None of this is necessary. But, depending on the scale of the project, how many people are going to be working with the code, the growth expectancy of the project, and even the budget, this level of detail may be extremely valuable. What we’ve done here is apply best practices, we’ve made the code as explicit and self documented as possible. As a result future developers (and our future selves) will thank us for this.

What Next?

So far we’ve managed to get the first feature’s tests to pass. However, we’ve done it in quite an isolated way by considering this single query on its own. In the next chapter we’ll quickly add the second feature, then we can analyse the two to find similarities. We’ll then use this knowledge to refactor what we have into a more generic form. After that we’ll try to display the application’s output on a page.

  1. The Model View Controller design pattern.