Mastering PHP Design Patterns

5 (7 reviews total)
By Junade Ali
  • Instant online access to over 8,000+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Why "Good PHP Developer" Isnt an Oxymoron

About this book

Design patterns are a clever way to solve common architectural issues that arise during software development. With an increase in demand for enhanced programming techniques and the versatile nature of PHP, a deep understanding of PHP design patterns is critical to achieve efficiency while coding.

This comprehensive guide will show you how to achieve better organization structure over your code through learning common methodologies to solve architectural problems. You’ll also learn about the new functionalities that PHP 7 has to offer.

Starting with a brief introduction to design patterns, you quickly dive deep into the three main architectural patterns: Creational, Behavioral, and Structural popularly known as the Gang of Four patterns. Over the course of the book, you will get a deep understanding of object creation mechanisms, advanced techniques that address issues concerned with linking objects together, and improved methods to access your code.

You will also learn about Anti-Patterns and the best methodologies to adopt when building a PHP 7 application. With a concluding chapter on best practices, this book is a complete guide that will equip you to utilize design patterns in PHP 7 to achieve maximum productivity, ensuring an enhanced software development experience.

Publication date:
September 2016
Publisher
Packt
Pages
270
ISBN
9781785887130

 

Chapter 1. Why "Good PHP Developer" Isnt an Oxymoron

Back in 2010, MailChimp published a post on their blog, entitled Ewww, You Use PHP? In this blog post, they described the horror when they explained their choice of PHP to developers who consider the phrase good PHP programmer an oxymoron. In their rebuttal they argued that their PHP wasn't your grandfathers PHP and that they use a sophisticated framework. I tend to judge the quality of PHP on the basis of, not only how it functions, but how secure it is and how it is architected. This book focuses on ideas of how you should architect your code. The design of software allows for developers to ease the extension of the code beyond its original purpose, in a bug-free and elegant fashion.

As Martin Fowler put it:

"Any fool can write code that a computer can understand. Good programmers write code that humans can understand."

This isn't just limited to code style, but how developers architect and structure their code. I've encountered many developers with their noses constantly stuck in the documentation, copying and pasting bits of code until it works; hacking snippets together until it works. Moreover, I far too often see the software development process rapidly deteriorate as developers ever more tightly couple their classes with functions of ever increasing length.

Software engineers mustn't just code software; they must know how to design it. Indeed often a good software engineer, when interviewing other software engineers will ask questions about the design of the code itself. It is trivial to get a piece of code that will execute, and it is also benign to question a developer as to whether strtolower or str2lower is the correct name of a function (for the record, it's strtolower). Knowing the difference between a class and an object doesn't make you a competent developer; a better interview question would, for example, be how one could apply subtype polymorphism to a real software development challenge. Failure to assess software design skills dumbs down an interview and results in there being no way to differentiate between those who are good at it, and those who aren't. These advanced topics will be discussed throughout this book, by learning these tactics, you will better understand what the right questions to ask are when discussing software architecture.

Moxie Marlinspike once tweeted the following:

"As a software developer, I envy writers, musicians, and filmmakers. Unlike software, when they create something it is really done, forever".

When developing software, we mustn't forget we are authors, not just of instructions for a machine, but we are also authoring something that we later expect others to extend upon. Therefore, our code mustn't just be targeted at machines, but humans also. Code isn't just poetry for a machine, it should be poetry for humans also.

This is, of course, better said than done. In PHP, this may be found especially difficult given the freedom PHP offers developers on how they may architect and structure their code. By the very nature of freedom, it may be both used and abused, so it is true with the freedom offered in PHP.

Therefore, it is increasingly important that developers understand proper software design practices to ensure their code maintains the long term maintainability. Indeed, another key skill lies in refactoring code, improving the design of existing code to make it easier to extend in the long term.

Technical debt, the eventual consequence of poor system design, is something that I've found comes with the career of a PHP developer. This has been true for me whether it has been dealing with systems that provide advanced functionality or simple websites. It usually arises because a developer elects to implement a bad design for a variety of reasons; this is when adding functionality to an existing codebase or taking poor design decisions during the initial construction of software. Refactoring can help us address these issues.

SensioLabs (the creators of the Symfony framework) have a tool called  Insight that allows developers to calculate the technical debt in their own code. In 2011, they did an evaluation of technical debt in various projects using this tool; rather unsurprisingly they found that WordPress 4.1 topped the chart of all platforms they evaluated with them claiming it would take 20.1 years to resolve the technical debt that the project contains.

Those familiar with the WordPress core may not be surprised by this, but this issue of course is not only associated to WordPress. In my career of working with PHP, from working with security critical cryptography systems to working with systems that work with mission critical embedded systems, dealing with technical debt comes with the job. Dealing with technical debt is not something to be ashamed of for a PHP developer, indeed some may consider it courageous. Dealing with technical debt is no easy task, especially in the face of an ever more demanding user base, client, or project manager; constantly demanding more functionality without being familiar with the technical debt the project has associated to it.

I recently e-mailed the PHP Internals group as to whether they should consider deprecating the error suppression operator @. When any PHP function is prepended by an @ symbol, the function will suppress an error returned by it. This can be brutal, especially where that function renders a fatal error that stops the execution of the script, making debugging a tough task. If the error is suppressed, the script may fail to execute without providing developers a reason as to why this is. Usage of this operator may be described as an anti-pattern in some situations, something we will cover in Chapter 4, Structural Design Patterns.

Despite the fact that no one objected to the fact that there were better ways of handling errors (try/catch, proper validation) than abusing the error suppression operator and that deprecation should be an eventual aim of PHP, it is the case that some functions return needless warnings even though they already have a success/failure value. This means that due to technical debt in the PHP core itself, this operator cannot be deprecated until a lot of other prerequisite work is done. In the meantime, it is down to developers to decide the best methodologies of handling errors. Until the inherent problem of unnecessary error reporting is addressed, this operator cannot be deprecated. Therefore, it is down to developers to be educated as to the proper methodologies that should be used to address error handling and not to constantly resort to using an @ symbol.

Fundamentally, technical debt slows down development of a project and often leads to code being deployed that is broken as developers try and work on a fragile project.

When starting a new project, never be afraid to discuss architecture as architecture meetings are vital to developer collaboration; as one Scrum Master I've worked with said in the face of criticism that "meetings are a great alternative to work", he said "meetings are work...how much work would you be doing without meetings?".

In the rest of this chapter, we will cover the following points:

  • Coding style - the PSR standards

  • Revising object-oriented programming

  • Setting up the environment with Composer

  • Who are the Gang of Four?

 

Coding style - the PSR standards


When it comes to coding style, I would like to introduce you to the PSR standards created by the PHP Framework Interop Group. Namely, the two standards that apply to coding standards are PSR-1 (Basic Coding Style) and PSR-2 (Coding Style Guide). In addition to this, there are PSR standards that cover additional areas, for example, as of today; the PSR-4 standard is the most up-to-date autoloading standard published by the group. You can find out more about the standards at http://www.php-fig.org/.

Coding style being used to enforce consistency throughout a code base is something I strongly believe in. It does make a difference to your code readability throughout a project. It is especially important when you are starting a project (chances are you may be reading this book to find out how to do that right) as your coding style determines the style the developers following you in working on this project will adopt. Using a global standard such as PSR-1 or PSR-2 means that developers can easily switch between projects without having to reconfigure their code style in their IDE. Good code style can make formatting errors easier to spot. Needless to say that coding styles will develop as time progresses, to date I elect to work with the PSR standards.

I am a strong believer in the phrase: always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. It isn't known who wrote this phrase originally, but it's widely thought that it could have been John Woods or potentially Martin Golding.

I would strongly recommend familiarizing yourself with these standards before proceeding in this book.

 

Revising object-oriented programming


Object-oriented programming is more than just classes and objects; it's a whole programming paradigm based around objects (data structures) that contain data fields and methods. It is essential to understand this; using classes to organize a bunch of unrelated methods together is not object orientation.

Assuming you're aware of classes (and how to instantiate them), allow me to remind you of a few different bits and pieces.

Polymorphism

Polymorphism is a fairly long word for a fairly simple concept. Essentially, polymorphism means the same interface is used with a different underlying code. So multiple classes could have a draw function, each accepting the same arguments, but at an underlying level, the code is implemented differently.

In this section, I would like to talk about Subtype Polymorphism in particular (also known as Subtyping or Inclusion Polymorphism).

Let's say we have animals as our supertype; our subtypes may well be cats, dogs, and sheep.

In PHP, interfaces allow you to define a set of functionality that a class that implements it must contain, as of PHP 7 you can also use scalar type hints to define the return types we expect.

So for example, suppose we defined the following interface:

interface Animal 
{ 
  public function eat(string $food) : bool; 
 
  public function talk(bool $shout) : string; 
} 

We could then implement this interface in our own class, as follows:

class Cat implements Animal { 
} 

If we were to run this code without defining the classes we would get an error message as follows:

Class Cat contains 2 abstract methods and must therefore be declared abstract or implement the remaining methods (Animal::eat, Animal::talk) 

Essentially, we are required to implement the methods we defined in our interface, so now let's go ahead and create a class that implements these methods:

class Cat implements Animal 
{ 
  public function eat(string $food): bool 
  { 
    if ($food === "tuna") { 
      return true; 
    } else { 
      return false; 
    } 
  } 
 
  public function talk(bool $shout): string 
  { 
    if ($shout === true) { 
      return "MEOW!"; 
    } else { 
      return "Meow."; 
    } 
  } 
} 

Now that we've implemented these methods, we can then just instantiate the class we are after and use the functions contained in it:

$felix = new Cat();echo
$felix->talk(false);

So where does polymorphism come into this? Suppose we had another class for a dog:

class Dog implements Animal 
{ 
  public function eat(string $food): bool 
  { 
    if (($food === "dog food") || ($food === "meat")) { 
      return true; 
    } else { 
      return false; 
    } 
  } 
 
  public function talk(bool $shout): string 
  { 
    if ($shout === true) { 
      return "WOOF!"; 
    } else { 
      return "Woof woof."; 
    } 
  } 
} 

Now let's suppose we have multiple different types of animals in a pets array:

$pets = array( 
  'felix'     => new Cat(), 
  'oscar'     => new Dog(), 
  'snowflake' => new Cat() 
); 

We can now actually go ahead and loop through all these pets individually in order to run the talk function. We don't care about the type of pet because the talk method that is implemented in every class we get is by virtue of us having extended the Animals interface.

So let's suppose we wanted to have all our animals run the talk method. We could just use the following code:

foreach ($pets as $pet) { 
  echo $pet->talk(false); 
} 

No need for unnecessary switch/case blocks in order to wrap around our classes, we just use software design to make things easier for us in the long-term.

Abstract classes work in a similar way, except for the fact that abstract classes can contain functionality where interfaces cannot.

It is important to note that any class that defines one or more abstract classes must also be defined as abstract. You cannot have a normal class defining abstract methods, but you can have normal methods in abstract classes. Let's start off by refactoring our interface to be an abstract class:

abstract class Animal 
{ 
  abstract public function eat(string $food) : bool; 
 
  abstract public function talk(bool $shout) : string; 
 
  public function walk(int $speed): bool { 
    if ($speed > 0) { 
      return true; 
    } else { 
      return false; 
    } 
  } 
} 

You might have noticed that I have also added a walk method as an ordinary, non-abstract method; this is a standard method that can be used or extended by any classes that inherit the parent abstract class. They already have their implementation.

Note that it is impossible to instantiate an abstract class (much like it's not possible to instantiate an interface). Instead, we must extend it.

So, in our Cat class let's remove the following:

class Cat implements Animal 

We will replace it with the following code:

class Cat extends Animal 

That's all we need to refactor in order to get classes to extend the Animal abstract class. We must implement the abstract functions in the classes as we outlined for the interfaces, plus we can use the ordinary functions without needing to implement them:

$whiskers = new Cat();
$whiskers->walk(1);

As of PHP 5.4 it has also become possible to instantiate a class and access a property of it in one system. PHP.net advertised it as: Class member access on instantiation has been added, e.g. (new Foo)->bar(). You can also do it with individual properties, for example, (new Cat)->legs. In our example, we can use it as follows:

(new \IcyApril\ChapterOne\Cat())->walk(1); 

Just to recap a few other points about how PHP implemented OOP, the final keyword before a class declaration or indeed a function declaration means that you cannot override such classes or functions after they've been defined.

So, let's try extending a class we have named as final:

final class Animal 
{ 
  public function walk() 
  { 
    return "walking..."; 
  } 
} 
 
class Cat extends Animal 
{ 
} 

This results in the following output:

Fatal error: Class Cat may not inherit from final class (Animal) 

Similarly, let's do the same except at a function level:

class Animal 
{ 
  final public function walk() 
  { 
    return "walking..."; 
  } 
} 
 
class Cat extends Animal 
{ 
  public function walk () { 
    return "walking with tail wagging..."; 
  } 
} 

This results in the following output:

Fatal error: Cannot override final method Animal::walk() 

Traits (multiple inheritance)

Traits were introduced in PHP as a mechanism for introducing Horizontal Reuse. PHP conventionally acts as a single inheritance language, because of the fact that you can't inherit more than one class into a script.

Traditional multiple inheritance is a controversial process that is often looked down upon by software engineers.

Let me give you an example of using Traits first hand; let's define an abstract Animal class that we want to extend into another class:

class Animal 
{ 
  public function walk() 
  { 
    return "walking..."; 
  } 
} 
 
class Cat extends Animal 
{ 
  public function walk () { 
    return "walking with tail wagging..."; 
  } 
} 

So now let's suppose we have a function to name our class, but we don't want it to apply to all our classes that extend the Animal class, we want it to apply to certain classes irrespective of whether they inherit the properties of the abstract Animal class or not.

So we've defined our functions like so:

function setFirstName(string $name): bool 
{ 
  $this->firstName = $name; 
  return true; 
} 
 
function setLastName(string $name): bool 
{ 
  $this->lastName = $name; 
  return true; 
} 

The problem now is that there is no place we can put them without using Horizontal Reuse, apart from copying and pasting different bits of code or resorting to using conditional inheritance. This is where Traits come to the rescue; let's start off by wrapping these methods in a Trait called Name:

trait Name 
{ 
  function setFirstName(string $name): bool 
  { 
    $this->firstName = $name; 
    return true; 
  } 
 
  function setLastName(string $name): bool 
  { 
    $this->lastName = $name; 
    return true; 
  } 
} 

So now that we've defined our Trait, we can just tell PHP to use it in our Cat class:

class Cat extends Animal 
{ 
  use Name; 
 
  public function walk() 
  { 
    return "walking with tail wagging..."; 
  } 
} 

Notice the use of the Name statement? That's where the magic happens. Now you can call the functions in that Trait without any problems:

$whiskers = new Cat();
$whiskers->setFirstName('Paul');
echo $whiskers->firstName;

All put together, the new code block looks as follows:

trait Name 
{ 
  function setFirstName(string $name): bool 
  { 
    $this->firstName = $name; 
    return true; 
  } 
 
  function setLastName(string $name): bool 
  { 
    $this->lastName = $name; 
    return true; 
  } 
} 
 
class Animal 
{ 
  public function walk() 
  { 
    return "walking..."; 
  } 
} 
 
class Cat extends Animal 
{ 
  use Name; 
 
  public function walk() 
  { 
    return "walking with tail wagging..."; 
  } 
} 
 
$whiskers = new Cat(); 
$whiskers->setFirstName('Paul'); 
echo $whiskers->firstName;  

Scalar type hints

Let me take this opportunity to introduce you to a PHP 7 concept known as scalar type hinting; it allows you to define the return types (yes, I know this isn't strictly under the scope of OOP; deal with it).

Let's define a function, as follows:

function addNumbers (int $a, int $b): int 
{ 
  return $a + $b; 
} 

Let's take a look at this function; firstly you will notice that before each of the arguments we define the type of variable we want to receive; in this case, it's int (or integer). Next up, you'll notice there's a bit of code after the function definition : int, which defines our return type so our function can only receive an integer.

If you don't provide the right type of variable as a function argument or don't return the right type of the variable from the function; you will get a TypeError exception. In strict mode, PHP will also throw a TypeError exception in the event that strict mode is enabled and you also provide the incorrect number of arguments.

It is also possible in PHP to define strict_types; let me explain why you might want to do this. Without strict_types, PHP will attempt to automatically convert a variable to the defined type in very limited circumstances. For example, if you pass a string containing solely numbers it will be converted to an integer, a string that's non-numeric, however, will result in a TypeError exception. Once you enable strict_types this all changes, you can no longer have this automatic casting behavior.

Taking our previous example, without strict_types, you could do the following:

echo addNumbers(5, "5.0");

Trying it again after enabling strict_types, you will find that PHP throws a TypeError exception.

This configuration only applies on an individual file basis, putting it before you include other files will not result in this configuration being inherited to those files. There are multiple benefits of why PHP chose to go down this route; they are listed very clearly in version 0.5.3 of the RFC that implemented scalar type hints called PHP RFC: Scalar Type Declarations. You can read about it by going to http://www.wiki.php.net (the wiki, not the main PHP website) and searching for scalar_type_hints_v5.

In order to enable it, make sure you put this as the very first statement in your PHP script:

declare(strict_types=1); 

This will not work unless you define strict_types as the very first statement in a PHP script; no other usages of this definition are permitted. Indeed, if you try to define it later on, your script PHP will throw a fatal error.

Of course, in the interests of the rage-induced PHP core fanatic reading this book in its coffee stained form, I should mention that there are other valid types that can be used in type hinting. For example, PHP 5.1.0 introduced this with arrays and PHP 5.0.0 introduced the ability for a developer to do this with their own classes.

Let me give you a quick example of how this would work in practice, suppose we had an Address class:

class Address 
{ 
  public $firstLine; 
  public $postcode; 
  public $country; 
 
  public function __construct(string $firstLine, string $postcode, string $country) 
  { 
    $this->firstLine = $firstLine; 
    $this->postcode = $postcode; 
    $this->country = $country; 
  } 
} 

We can then type the hint of the Address class that we inject into a Customer class:

class Customer 
{ 
  public $name; 
  public $address; 
 
  public function __construct($name, Address $address) 
  { 
    $this->name = $name; 
    $this->address = $address; 
  } 
} 

And this is how it all can come together:

$address = new Address('10 Downing Street', 'SW1A 2AA', 'UK');
$customer = new Customer('Davey Cameron', $address);
var_dump($customer);

Limiting debug access to private/protected properties

If you define a class which contains private or protected variables, you will notice an odd behavior if you were to var_dump the object of that class. You will notice that when you wrap the object in a var_dump it reveals all variables; be they protected, private, or public.

PHP treats var_dump as an internal debugging function, meaning all data becomes visible.

Fortunately, there is a workaround for this. PHP 5.6 introduced the __debugInfo magic method. Functions in classes preceded by a double underscore represent magic methods and have special functionality associated with them. Every time you try to var_dump an object that has the __debugInfo magic method set, the var_dump will be overridden with the result of that function call instead.

Let me show you how this works in practice, let's start by defining a class:

class Bear { 
  private $hasPaws = true; 
} 

Let's instantiate this class:

$richard = new Bear();

Now, if we were to try and access the private variable that is hasPaws, we would get a fatal error:

echo $richard->hasPaws;

The preceding call would result in the following fatal error being thrown:

Fatal error: Cannot access private property Bear::$hasPaws

That is the expected output, we don't want a private property visible outside its object. That being said, if we wrap the object with a var_dump as follows:

var_dump($richard); 

We would then get the following output:

object(Bear)#1 (1) { 
   ["hasPaws":"Bear":private]=> 
   bool(true) 
} 

As you can see, our private property is marked as private, but nevertheless it is visible. So how would we go about preventing this?

So, let's redefine our class as follows:

class Bear { 
  private $hasPaws = true; 
  public function __debugInfo () { 
    return call_user_func('get_object_vars', $this); 
  } 
} 

Now, after we instantiate our class and var_dump the resulting object, we get the following output:

object(Bear)#1 (0) {  
} 

The script all put together looks like this now, you will notice I've added an extra public property called growls, which I have set to true:

<?php 
class Bear { 
  private $hasPaws = true; 
  public $growls = true; 
   
  public function __debugInfo () { 
    return call_user_func('get_object_vars', $this); 
  } 
} 
$richard = new Bear(); 
var_dump($richard); 

If we were to var_dump this script (with both public and private property to play with), we would get the following output:

object(Bear)#1 (1) { 
  ["growls"]=> 
  bool(true) 
} 

As you can see, only the public property is visible. So what is the moral of the story from this little experiment? Firstly, that var_dumps exposes private and protected properties inside objects, and secondly, that this behavior can be overridden.

 

Setting up the environment with Composer


Composer is a dependency manager for PHP, strongly inspired by Node's NPM and Bundler. It has now become integral to multiple PHP projects, including Laravel and Symfony. Why it is useful for us, however, is that it contains autoload functionality that is compliant with the PSR-0 and PSR-4 standards. You can download and install Composer from http://getcomposer.org.

Note

In order to install Composer globally on Mac OS X or Linux, first you can run the installer:

curl -sS https://getcomposer.org/installer | php

And then you can move Composer to install it globally:

mv composer.phar /usr/local/bin/composer

If the command preceding fails due to a permissions issue, rerun the command except putting sudo at the very start. You'll be asked to enter your password after you type the command, just enter it and hit Enter.

Once you've installed Composer by following the preceding steps, you can run it simply by running the composer command.

In order to install Composer on Windows it is easiest to just run the installer on the Composer website; currently you can find it at:

https://getcomposer.org/Composer-Setup.exe.

Composer is fairly easy to update, just run this command:

Composer self-update

Composer works by using the configuration in a file called composer.json, where you can outline external dependencies and your autoloading style. Once Composer has installed dependencies listed in this file, it writes a composer.lock file that details the exact versions it has installed. When using version control it is important that you commit this file (alongside the composer.json file), don't add it to your .gitignore file if you're on Git. This is very important because the lock file details the exact version of a package that was installed at a particular time in your version control system. You can, however, exclude a directory called vendor, I'll explain what that does later.

Let's start off by creating a file called composer.json in our project directory. This file is structured in JSON, so let me just remind you of how JSON works:

  • JSON consists of key/value pairs of data, think of it like a set of variables being defined in a file

  • A key value pair is comma separated, for example, "key" : "value"

  • Curly brackets hold objects

  • Square brackets hold arrays

  • Multiple pieces of data must be comma separated, without leaving a trailing comma at the end of the data

  • Keys and values that include strings must be wrapped in quotes

  • A backslash \ is the escape key

So now we can add the following markup to the composer.json file:

{ 
  "autoload": { 
    "psr-4": { 
      "IcyApril\\ChapterOne": "src/" 
    } 
  } 
} 

So let me explain what this file does; it tells Composer to autoload everything in the src/ directory into the IcyApril\ChapterOne namespace using the PSR-4 standard.

So, the next step is to create our src directory where we include the code we want to autoload. Done that? Right, now let's open up our command line and move into the directory where we've put our composer.json file.

In order to install everything in the composer.json file in your project just run the composer install command. For subsequent updates, the composer update command will update to the latest versions of all dependencies as defined in composer.json. If you don't want to do this, though, there is an alternative; running the composer dump-autoload command will solely regenerate the list of the PSR-0/PSR-4 classes that need to be included in the project (for example, you add, delete, or rename some of your classes).

Now let me cover how you will actually go about creating a class. So, let's create an src directory in our project and in that src directory create a new class called Book. You can do this by creating a file called Book.php. In that file, add something like this:

<?php 
namespace IcyApril\ChapterOne; 
 
class Book 
{ 
  public function __construct() 
  { 
    echo "Hello world!"; 
  } 
} 

This is a standard class, except we're just defining a constructor that will echo Hello world! when the class is instantiated.

As you may have noticed, we've followed a few naming conventions; firstly, the PSR-1 standard declares that class names must be declared in StudlyCaps. PSR-2 has a few extra requirements; to name a few: four spaces instead of a tab, one blank space after a namespace or use declarations, and placing brackets on new lines. It's definitely worth taking the time to read these standards if you haven't already. You might not agree with every standard, you might have a subjective preference to how you format your own code; my advice is to put these preferences aside for the greater good. Having code that is standardized by means of utilizing the PSR standards offers great advantages when collaborating on common code bases. The benefit of having an external standard, built by an organization such as the PHP-FIG group, is that you have your configuration pre-built into your IDE (for example, PHPStorm supports PSR-1/PSR-2 out of the box). Not only this but, when it comes to formatting arguments you have a concrete impartial document that outlines how things should be done, which is great for stopping religious code formatting arguments during code reviews.

Now that we've created the class we can go ahead and run the composer dump-autoload command in order to refresh our autoloader script.

So, we've configured our Composer autoloader and we've also got a test class to play around with, but the next question is how we can implement this. So, let's go ahead and implement this. In the same directory where we've implemented our composer.json file, let's add our index.php file.

The line after you put in your PHP opening tag, we need to pull in our autoloader script:

require_once('vendor/autoload.php'); 

Then we can instantiate our Book class:

new \IcyApril\ChapterOne\Book(); 

Set up your web server, point your document root to the folder we created, direct your web browser to your chosen web server and you should see Hello world! pop up on screen. Now you can take apart the code and play around with it.

The completed code sample is available alongside this book, so you can open it up and play around with it directly from there, just in case you need any help debugging your code.

Whether your classes are abstract classes or mere interfaces, when autoloading we treat them all as classes.

 

The Gang of Four (GoF)


The architect Christopher Alexander, who mentioned how patterns can be used to address common design issues, originally documented the concept. The idea came about from Alexander; he proposes that design issues can be documented rigorously, alongside their proposed solution. Design patterns have most notably been applied to resolving architectural issues in software design.

In Christopher Alexander's own words:

"The elements of this language are entities called patterns. Each pattern describes a problem that occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice."

Alexander wrote his own book, predating the Gang of Four called, A Pattern Language. In this book, Alexander created his own language, he coined the phrase pattern language to describe this; this language was formed from the building blocks of Architectural patterns. By utilizing these Architectural patterns the book proposes that ordinary people can use this language as a framework to improve their neighborhoods and towns.

One such pattern that is documented in the book is Pattern 12, known as the Community of 7000; the book documents this pattern by stating the following:

"Individuals have no effective voice in any community of more than 5,000-10,000 persons."

By using problems such as this one with their documented solution; the book ultimately forms patterns, these patterns seek to act as the building blocks for making communities better.

As I mentioned, Alexander predated the Gang of Four; but his work was essential for sowing the seeds for software design patterns.

Now, let's turn directly on to the authors known as The Gang of Four.

Nope, we're not referring to the 1981 defectors from the British Labour party or an English post-punk band; but we are talking about the authors of a book called Design Patterns: Elements of Reusable Object-Oriented Software. This book has been highly influential in the realm of software development and is well known in the software engineering field.

In the first chapter of the book, the authors discuss object-oriented software development from their own personal experience; this includes arguing how software developers should program for an interface and not an implementation. This leads to code ultimately utilizing central functions of object-oriented programming.

It is a common misconception that the book contains only four design patterns, this isn't true; it covers 23 design patterns from three fundamental categories.

Let's cover what these categories are:

  • Creational

  • Structural

  • Behavioral

So let's break each one of these down.

Creational design patterns

Creational design patterns concern the creation of objects themselves. Basic instantiation of classes without using a design pattern can result in needless complexity, but also in significant design problems.

The main usage of Creational design patterns is to separate the instantiation of a class from the usage of that instance. Failure to use Creational design patterns can mean your code is harder to understand and test.

Dependency injection

Dependency injection is the process whereby you can actually input dependencies that your application needs directly into the object itself.

John Munsch left an answer on Stack Overflow called Dependency injection for five year olds, this answer was republished in the book Mark Seeman's Dependency Injection in .NET:

Tip

When you go and get things out of the refrigerator for yourself, you can cause problems. You might leave the door open, you might get something Mommy or Daddy doesn't want you to have. You might even be looking for something we don't even have or which has expired.

Tip

What you should be doing is stating a need, "I need something to drink with lunch," and then we will make sure you have something when you sit down to eat.

When writing a class, it's natural to use other dependencies; perhaps a database model class. So with dependency injection, instead of a class having its database model created in itself, you can create it outside that object and inject it in. In short, we separate our client's behavior from our client's dependencies.

When thinking of dependency injection, let's outline the four separate roles involved:

  • The service to be injected

  • The client that depends on the service being injected

  • The interface that determines how the client can use the service

  • The injector that is responsible for instantiating the service and injecting it into the client

Structural design patterns

Structural design patterns are fairly easy to explain, they act as interconnectors between entities. It serves as a blueprint for how basic classes can be combined to form bigger entities, all Structural design patterns involve the interconnections between objects.

Behavioral design patterns

Behavioral design patterns work to explain how objects interact with each other; how they can send messages between each of the objects and how you can divide the steps of various tasks up among classes.

Structural patterns describe the static architecture of a design; Behavioral patterns are more fluid and describe a flowing process.

Architectural patterns

This is not strictly a design pattern (but the Gang of Four didn't cover Architectural patterns in their book); but it is incredibly relevant for PHP developers due to the web-oriented nature of PHP. Architectural patterns address various different constraints in computer systems through addressing performance limitations, high availability, and also minimization of business risk.

Most developers will be familiar with the Model-View-Controller architecture when it comes to web frameworks, more recently other architectures have started to emerge; for example, a microservices architecture works by a set of RESTful APIs that are independent and interconnected. Some people believe microservices move problems from the software development layer to the systems architecture layer. The opposite of microservices often referred to as a monolithic architecture, is where all the code is together in one application.

 

Summary


In this chapter, we revised some PHP principles, including OOP principles. We also revised some PHP syntax basics. We have seen how you can use Composer for dependency management in PHP. In addition to this, we also discussed PSR standards and how you can implement them in your own code to make your code more readable by others, and also comply with some other important standards (be they autoloading or HTTP messaging). Finally, we introduced design patterns and the Gang of Four with the history behind design patterns.

About the Author

  • Junade Ali

    Junade Ali was a technical lead at some of the UK's leading digital agencies and has also worked using PHP in mission-critical road-safety systems. He loves pushing PHP to its innovative limits. Having started his career as a web development apprentice, he still remains engaged in the academic computer science community.

    Junade, an avid contributor to the PHP community, has also spoken at PHPTek and the Lead Developer Conference. In addition to this, Junade was interviewed by Cal Evans for Voices of the ElePHPant, and he has appeared on the PHP Roundtable. In this spirit, Junade is proud of his local PHP user group: PHPWarks. Currently, Junade works at CloudFlare as a polymath, and helps make the Internet more secure and faster.

    Outside of development, Junade has an interest in law and political campaigns and is a published author on constitutional law.

    Browse publications by this author

Latest Reviews

(7 reviews total)
Read only 10% of the book, but it seems to be good!
Awesome and very useful book!
Alway's have a good purcahse with Packt

Recommended For You

Book Title
Access this book and the full library for just $5/m.
Access now