YOUR DECOUPLING TOOLBOX - The Clean Architecture in PHP (2015)

The Clean Architecture in PHP (2015)

YOUR DECOUPLING TOOLBOX

We’ve uncovered various ways in which poor design decisions can lead to code that is hard to maintain, hard to refactor, and hard to test. Now we’re going to look at some guiding principles and design patterns that will help us alleviate these problems and help us write better code. Later, when we talk about architecture, we’ll apply these principles further to discover how to create truly uncoupled, refactorable, and easily testable code.

Design Patterns, A Primer

A design pattern is a specific solution to a commonly occurring problem in software development. These design patterns form a common language among software developers that can be used to discuss problems and describe solutions. They are transferable across languages and are not specific to PHP.

Design patterns as we know them today are heavily influenced by “the Gang of Four” who were instrumental in their popularization starting in 1994 with their book Design Patterns: Elements of Reusable Object-Oriented Software. The GoF are: Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides.

In their book, the GoF described twenty three design patterns organized into three categories: Creational, Structural, and Behavioral. It would be impossible to cover all of these patterns in any detail in this book, however, as they are instrumental to nearly every chapter that follows, we’re going to briefly cover a few of them here.

1. Factory: An object responsible for instantiating other objects

2. Repository: Not actually a GoF design pattern, this is an object responsible for transitioning data to and from its storage

3. Adapter: An object that encapsulates another object to make it conform to a desired API

4. Strategy: Encapsulates a behavior or a set of behaviors, allowing them to be used interchangeably

For a lighter, and maybe funner approach to design patterns, you can also checkout Head First Design Patterns by Freeman, Bates, Sierra, and Robson.

The Factory Patterns

Factories are objects that are responsible for creating other objects when needed, just like factories in real life are responsible for creating tangible things.

In real life, a Car Factory is responsible for creating cars. If we wanted this concept in code, it’d be the same. We’d have a CarFactory object that would create Car objects for us.

Factories in code can be applied to things that generally wouldn’t make sense in real life, such as a CustomerFactory or ConnectionStrategyFactory.

Typically, if we wanted to create a Customer object, we’d just instantiate one:

$customer = new Customer();

And this is fine for very simple classes with little configuration. But what if we had to bootstrap our Customer object, so to speak? Let’s say, for instance, that by default, a Customer has a $0 credit limit, is of status “pending” and is randomly assigned an account manager. Do we really want to litter our code with this logic in all the places we might create a new Customer object? What happens when these business rules change?

Of course, we’re going to use a factory to handle creating Customers for us:

class CustomerFactory {

protected $accountManagerRepo;

public function __construct(AccountManagerRepository $repo) {

$this->accountManagerRepo = $repo;

}

public function createCustomer($name) {

$customer = new Customer();

$customer->setName($name);

$customer->setCreditLimit(0);

$customer->setStatus('pending');

$customer->setAccountManager(

$this->accountManagerRepo->getRandom()

);

return $customer;

}

}

The business logic for creating new Customer objects is encapsulated within the CustomerFactory object.

There are several benefits to using factories:

1. Reusable code. Any place you have to create an object, the same logic is applied. No duplicate logic.

2. Testable code. Factories make creational logic easy to test. If this code were directly within some other class somewhere, it wouldn’t be possible to test in isolation.

3. Easy to change. If the logic ever changes, the change only needs to occur in one place.

Static Factories

Often, you’ll see factories in the wild setup as “static classes” (i.e.: classes with only static methods):

class CustomerFactory {

public static function createCustomer($name) {

$customer = new Customer();

$customer->setName($name);

$customer->setCreditLimit(0);

$customer->setStatus('pending');

return $customer;

}

}

Which would be called simply:

$customer = CustomerFactory::createCustomer('ACME Corp');

At first, this seems much cleaner and easier to use than instantiating the factory every time we need it. However, our first CustomerFactory had additional dependencies it needed to create Customer objects, namely the AccountRepository. We could pass this dependency to the method each time we call it, but that would be a mess to cleanup if we ever changed the name of AccountRepository or switched to another paradigm for data management.

I’ll leave it up to you whether you want to use static factories or not. For simple factories, there’s probably no negatives to doing so. For involved factories, especially those with dependencies, it can lead to some pretty smelly code.

Types of Factories

The CustomerFactory is typically how repositories are thought of by many, but it’s not exactly how the Factory Pattern was described in the Gang of Four design patterns book. In fact, they outlined two different types of factories.

Typically, the type of factory we created above is called a Simple Factory. A simple factory is a class responsible for creating another object.

Let’s look at the two factories patterns defined by the GoF:

1. The Factory Method pattern

2. The Abstract Factory pattern

Factory Method Pattern

According to the Gang of Four, the intent of the Factory Method Pattern is to:

Define an interface for creating an object, but let subclasses decide which class to instantiate.

This type of factory isn’t standalone like the Simple Factory we describe above. Instead, it’s embedded in either an abstract class or interface, or even within a concrete class. Whatever class needs to define a subordinate class can have a factory method.

class Document {

public function createPage() {

return new Page();

}

}

In this example, we have a simple createPage() method on Document which returns a new page.

However, if we want to be able to create multiple different types of documents, we could make this an abstract class:

abstract class AbstractDocument {

public function render() {

$this->addPage(1, $this->createPage());

}

public function addPage(1, AbstractPage) {

// ...

}

abstract public function createPage();

}

Now if we wanted to create a ResumeDocument and a PortfolioDocument:

class ResumeDocument extends AbstractDocument {

public function createPage() {

return new ResumePage();

}

}

class PortfolioDocument extends AbstractDocument {

public function createPage() {

return new PortfolioPage();

}

}

Of course, we need those subordinate objects being created by the factory methods:

interface PageInterface {}

class ResumePage implements PageInterface {}

class PortfolioPage implements PageInterface {}

The benefit of using a factory method like this is that it allows us to keep the bulk of our common functionality within the AbstractDocument class, as it’s inherent to both ResumeDocument and PortfolioDocument, but not have AbstractDocument reliant on the actual concrete document it’s working with.

Whenever AbstractDocument needs to generate a new page for whatever concrete it’s part of, it simply calls createDocument() and gets one.

The factory pattern works best when a class doesn’t know which type of objects it is working with and needs to create.

Abstract Factory Pattern

According to the Gang of Four, the intent of the Abstract Factory Pattern is to:

Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

With the Abstract Factory pattern, we’re interested in devising a solution to handle the creation of multiple different related objects, when the type of objects that need to be created isn’t known.

The Abstract Factory Pattern typically has several different players:

1. Client Code, which is an object or code that needs to use the factory to create other objects

2. Object Interface, which defines the structure of the actual objects to be created

3. Concrete Objects, which implement the Object Interface with specific implementation details

4. An Abstract Factory, which declares an interface to define how objects (Object Interfaces) should be created

5. Concrete Factories, which implement the Abstract Factory interface and create specific types of objects (Concrete Objects)

Let’s say we are writing some code to generate various different makes and models of cars, but we want the code to be adaptable to anything we throw at it.

Let’s say we have a Building class that is responsible for generating a specific car manufacturer’s line. This is our Client Code:

class Building {

public function createCars() {}

public function createTrucks() {}

}

We want this Building to be able to create Cars and Trucks as necessary. The first thing we need to do for the Abstract Factory Pattern to work is create an interface that defines these objects. These are our Object Interfaces:

interface CarInterface {}

interface TruckInterface {}

Let’s say we want to create both Ford and Chevrolet vehicles. We’ll need to define a concrete class for each manufacturer and each vehicle type. These are our Concrete Objects:

class ChevyMalibu implements CarInterface {}

class ChevySilverado implements TruckInterface {}

class FordFiesta implements CarInterface {}

class FordF250 implements TruckInterface {}

We’re going to need an assembly line to create each of these, so let’s define an interface for that too. This assembly line will be the basis for our actual factories. This interface is our Abstract Factory player.

interface AssemblyLineInterface {

public function createCar();

public function createTruck();

}

And of course, we’ll need some concrete classes of the AssemblyLineInterface to create each manufacturer’s line. These are our Concrete Factories:

class ChevyAssemblyLine implements AssemblyLineInterface {

public function createCar() {

return new ChevyMalibu();

}

public function createTruck() {

return new ChevySilverado();

}

}

class FordAssemblyLine implements AssemblyLineInterface {

public function createCar() {

return new FordFiesta();

}

public function createTruck() {

return new FordF250();

}

}

Now, our Building class can be supplied a specific AssemblyLineInterface, and start making vehicles:

class Building {

protected $assemblyLine;

protected $inventory = [];

public function __construct(

AssemblyLineInterface $assemblyLine

) {

$this->assemblyLine = $assemblyLine;

}

public function createCars() {

for ($i = 0; $i < 20; $i++) {

$this->inventory[] =

$this->assemlyLine->createCar();

}

}

public function createTrucks() {

for ($i = 0; $i < 15; $i++) {

$this->inventory[] =

$this->assemlyLine->createTruck();

}

}

}

We could call the code as such:

$building = new Building(new FordAssemblyLine());

$building->createCars();

The Abstract Factory pattern is useful when several different objects need to be created independent from the system that creates them. If we’re only concerned with created one object, then the Abstract Factory isn’t a very suitable solution.

information

Abstract Factory uses Factory Methods

You might have noticed that the create() methods in the assembly lines above look a lot like Factory Methods. That’s because they are! The Abstract Factory Pattern actually uses the Factory Method Pattern.

Repository Pattern

A Repository is an object that allows for the retrieval and persisting of data to a data store. The Repository Pattern is described in great detail in Eric Evan’s Domain-Driven Design: Tackling Complexity in the Heart of Software:

A REPOSITORY represents all objects of a certain type as a conceptual set (usually emulated). It acts like a collection, except with more elaborate querying capability.

Domain-Driven Design, Eric Evans, p. 151

When working with repositories, one stops thinking of getting data as “querying the database,” but instead thinks of the process as retrieving data from the repository.

Repositories usually have methods to retrieve data and methods to persist data. They’re usually called different things depending on the implementation.

Common retrieval methods include:

class MyRepository {

public function getById($id);

public function findById($id);

public function find($id);

public function retrieve($id);

}

I prefer either the get() or find() variants. You’ll often encounter other methods in repositories aimed at retrieving data in different ways:

class MyRepository {

public function getById($id);

public function getAll();

public function getBy(array $conditions);

}

Common persistence methods include:

class MyRepository {

public function persist($object);

public function save($object);

}

I prefer to use persist(), but these decisions are entirely up to you.

Repositories should only reference one object class. Thus, for each object you need to retrieve or persist, you should have a separate repository for them. If we’re working with a Customer object, we should have a CustomerRepository.

public function saveAction() {

$customer = $this->customerRepository->getById(1001);

$customer->setName('New Customer Name');

$this->customerRepository->persist($customer);

}

This client code is simple to use; it does not need to know the mechanics or language of the data store. It only needs to know how to use the repository, which it does through a simple API.

Repositories and Factories are often used together. The factory is responsible for created the object, and the repository is responsible for persisting it. When an object already exists in the data store, the repository is also responsible for retrieving a reference to it, and later likely responsible for saving changes made to it.

How does a Repository Work?

This is all well and good, but how exactly does a repository work?

Objects of the appropriate type are added and removed, and the machinery behind the REPOSITORY inserts them or deletes them from the database.

Domain-Driven Design, Eric Evans, p. 151

What is this machinery behind the repository? Making repositories work can be simple. Making repositories that work very well can be quite complicated. It’s best to rely on an already established framework, especially when you’re just starting out. Doctrine ORM provides a great Data Mapper implementation, while Eloquent ORM and Propel provide implementations of the Active Record pattern, and Zend Framework 2 provides a Table Data Gateway implementation.

However, if you really want to dive in with creating your own repository backend, I’d highly suggest reading Martin Fowler’s Patterns of Enterprise Application Architecture. This book covers how to properly implement various patterns that would sit behind a repository, including Data Mapper, Table Data Gateway, and Active Record.

Adapter Pattern

The Adapter Pattern allows for encapsulating the functionality of one object, and making it conform to the functionality of another object. This pattern is sometimes also referred to as the Wrapper Pattern, as it involves wrapping one object with another.

Let’s say we have one class whose interface looks something like this:

class GoogleMapsApi {

public function getWalkingDirections($from, $to) {}

}

We have an interface in our project that defines the structure of an object that gets us distances:

interface DistanceInterface {

public function getDistance($from, $to);

}

If we want to provide a DistanceInterface concrete class that gives the walking distance between two points, we can write an adapter to use the GoogleMapsApi class to do so:

class WalkingDistance implements DistanceInterface {

public function getDistance($from, $to) {

$api = new GoogleMapsApi();

$directions = $api->getWalkingDirections($from, $to);

return $directions->getTotalDistance();

}

}

This class inherits from our DistanceInterface, and properly returns the distance using the GoogleMapsApi class to first get the walking directions, and then return the distance contained in that result.

The Adapter Pattern allows us to take one object, and adapt it to fit the interface of another object, making them compatible in whatever context we’re trying to use them.

Adapters are discussed in more detail in the chapter Abstracting With Adapters, including some very valid use cases for this pattern.

Strategy Pattern

The Strategy Pattern allows the behavior of an algorithm to be determined during runtime of an application. Strategies are usually a family of classes that share a common interface, that each encapsulate separate behavior that can be interchangeable at runtime.

Let’s say we need to develop an invoicing process for our customers, who have the option of choosing between two methods of receiving their invoices: email or paper.

public function invoiceCustomers(array $customers) {

foreach ($customers as $customer) {

$invoice = $this->invoiceFactory->create(

$customer,

$this->orderRepository->getByCustomer($customer)

);

// send invoice...

}

}

Our InvoiceFactory takes care of generating an invoice from all the orders returned by our OrderRepository, so how do we go about sending those invoices?

Using the Strategy Pattern, we first define an interface that describes how all invoices should be sent, regardless of delivery method:

interface InvoiceDeliveryInterface {

public function send(Invoice $invoice);

}

We have two possible methods of delivering an invoice: email or print. Let’s define a strategy for each.

class EmailDeliveryStrategy implements InvoiceDeliveryInterface {

public function send(Invoice $invoice) {

// Use an email library to send it

}

}

class PrintDeliveryStrategy implements InvoiceDeliveryInterface {

public function send(Invoice $invoice) {

// Send it to the printer

}

}

exercise

Optimization Opportunity

How these two classes manage to delivery the invoice aren’t important for this exercise, but consider how you might use third party libraries to send emails and use some kind of printing service (maybe through an API).

Could the Adapter Pattern be a good way to bring those libraries into your code base and use them within these strategies?

Our calling code (the client) now needs to make a determination of which strategy to use:

public function invoiceCustomers(array $customers) {

foreach ($customers as $customer) {

$invoice = $this->invoiceFactory->create(

$customer,

$this->orderRepository->getByCustomer($customer)

);

switch ($customer->getDeliveryMethod()) {

case 'email':

$strategy = new EmailDeliveryStrategy();

break;

case 'print':

default:

$strategy = new PrintDeliveryStrategy();

break;

}

$strategy->send($invoice);

}

}

This code now delivers invoices using the two new strategies. The Strategy Pattern has allowed us to encapsulate the behavior and make a determination at runtime of which strategy to use.

The code isn’t perfect, though. Is this the correct place to make the determination of how to send an invoice to the customer? Could we maybe utilize one of these design patterns to make this code better? Of course!

Instantiating the correct strategy to use is the perfect place to use a factory.

class InvoiceDeliveryStrategyFactory {

public function create(Customer $customer) {

switch ($customer->getDeliveryMethod()) {

case 'email':

return new EmailDeliveryStrategy();

break;

case 'print':

default:

return new PrintDeliveryStrategy();

break;

}

}

}

The actual logic within the InvoiceDeliveryStrategyFactory class isn’t any different than what we had in the invoiceCustomers method, but now it’s reusable (if that were even necessary in this case), and it’s independently testable. It’s a great use of a factory.

This simple code example now shows the usage of repositories, factories, strategies, and, if you followed our tip, maybe even adapters!

public function invoiceCustomers(array $customers) {

foreach ($customers as $customer) {

$invoice = $this->invoiceFactory->create(

$customer,

$this->orderRepository->getByCustomer($customer)

);

$strategy = $this->deliveryMethodFactory->create(

$customer

);

$strategy->send($invoice);

}

}

Learning More Design Patterns

Design patterns help us write clean, understandable, concise code that makes refactoring, testing, and maintainability possible. It also gives us a common language to use when discussing ideas with other developers.

This chapter has only scratched the surface of the design patterns presented, and only presented a handful of the design patterns in the wild. Even beyond those introduced by the Gang of Four book, others have defined their own design patterns, and some of those have gained traction.

I highly recommend you pick up at least one of the two books mentioned in the beginning of this chapter:

1. Design Patterns: Elements of Reusable Object-Oriented Software

2. Head First Design Patterns

Design patterns are a great, tried-and-true way to solve common coding problems. We’ll use these patterns throughout the rest of this book.

SOLID Design Principles

Much like design patterns are a common language of constructs shared between developers, SOLID Design Principles are a common foundation employed across all types of applications and programming languages.

The SOLID Design Principles are a set of five basic design principles for object oriented programming described by Robert C. Martin. These principles define ways in which all classes should behave and interact with one another, as well as principles of how we organize those classes.

The SOLID principles are:

1. Single Responsibility Principle

2. Open/Closed Principle

3. Liskov Substitution Principle

4. Interface Segregation Principle

5. Dependency Inversion Principle

Single Responsibility Principle

The Single Responsibility Principle states that objects should have one, and only one, purpose. This is a principle that is very often violated, especially by new programmers. Often you’ll see code where a class is a jack of all trades, performing several tasks, within sometimes several thousand lines of code, all depending on what method was called.

To the new OOP developer, classes are often viewed at first as a collection of related methods and functionality. However, the SRP advocates against writing classes with more than one responsibility. Instead, it recommends condensed, smaller classes with a single responsibility.

What is a responsibility?

In his description of the Single Responsibility Principle, Robert Martin describes a responsibility as “a reason for change.” Any time we look at a given class and see more than one way in which we might change it, then that class has more than one responsibility.

Another way to look at a responsibility is to look at the behavior of a class. If it has more than one behavior, it is violating SRP.

Let’s look at a class that represents a User record stored in a database:

class User {

public function getName() {}

public function getEmail() {}

public function find($id) {}

public function save() {}

}

This User class has two responsibilities: it manages the state of the user, and it manages the retrieval from and persistence to the database. This violates SRP. Instead, we could refactor this into two classes:

class User {

public function getName() {}

public function getEmail() {}

}

class UserRepository {

public function find($id) {}

public function save(User $user) {}

}

The User class continues to manage the state of the user data, but now the UserRepository class is responsible for managing the retrieval and persistence to the database. These two concepts are now decoupled, and the two classes conform to SRP.

When we look at the UserRepository class, we can make a determination that retrieving and persisting data to the database are the same responsibility, as a change to one (such as changing where or how the data is stored) requires a change to the other.

Breaking up Classes

In order to apply the SRP principle to existing classes, or even when creating new classes, it’s important to analyze the responsibility of the class. Take for instance a customer invoicing class, like the one we looked at in the previous chapter:

class InvoicingService {

public function generateAndSendInvoices() {}

protected function generateInvoice($customer) {}

protected function createInvoiceFile($invoice) {}

protected function sendInvoice($invoice) {}

}

Already it’s plainly obvious that this class has more than one responsibility. Just looking at the method name of generateAndSendInvoices() reveals two. It’s not always readily apparent from class and method names how many responsibilities there are, though. Sometimes it requires looking at the actual code within those methods. After all, the method could have simply been named generateInvoices(), hiding the fact that it was also responsible for delivering those invoices.

There are at least four separate responsibilities of this class:

1. Figuring out which invoices to create

2. Generating invoice records in the database

3. Generating the physical representation of the invoice (i.e.: PDF, Excel, CSV, etc)

4. Sending the invoice to the customer via some means

In order to fix this class to conform to SRP, we’ll want to break it up into smaller, fine tuned classes, each representing one of the four responsibilities we identified above, plus the InvoicingService class that ties this all together.

class OrderRepository {

public function getOrdersByMonth($month);

}

class InvoicingService {

public function generateAndSendInvoices() {}

}

class InvoiceFactory {

public function createInvoice(Order $order) {}

}

class InvoiceGenerator {

public function createInvoiceFormat(

Invoice $invoice,

$format

) {}

}

class InvoiceDeliveryService {

public function sendInvoice(

Invoice $invoice,

$method

) {}

}

Our four classes here represent the responsibilities of the previous InvoicingService class. Ideally, we’d probably even have more than this: we’ll probably want strategy classes for each format needed for the InvoiceGenerator and strategy classes for each delivery method of theInvoiceDeliveryService. Otherwise, these classes end up having more than one responsibility as they’re either generating multiple file formats, or utilizing multiple delivery methods.

This is a lot of classes, almost seemingly a silly number of classes. What we’ve given up, however, is one very large, monolithic class with multiple responsibilities. Each time we need to make a change to one of those responsibilities, we potentially risk introducing an unintended defect in the rest of the seemingly unrelated code.

Why does SRP matter?

Why are we concerned with making sure a class only has one responsibility? Having more than one responsibility makes those responsibilities coupled, even if they are not related. This can make it harder to refactor the class without unintentionally breaking something else, whereas having a separate class for each responsibility shields the rest of the code from most of the risk.

It’s also much easier to test a class with only one responsibility: there’s only one thing to test, although with a potential for many different outcomes, and there’s much less code involved in that test.

Generally, the smaller the class, the easier it is to test, the easier it is to refactor, and the less likely it is to be prone to defects.

Open/Closed Principle

The Open/Closed Principle states that classes should be open to extension, but closed to modification. This means that future developers working on the system should not be allowed or encouraged to modify the source of existing classes, but instead find ways to extend the existing classes to provide new functionality.

The Strategy Pattern introduced in the previous chapter of Design Patterns provides a great example of how the Open/Closed Principle works. In it, we defined strategies for mechanisms to deliver invoices to customers. If we wanted to add a new delivery method, perhaps one via an EDI (Electronic Data Interchange), we could simply write a new adapter:

class EdiStrategy implements DeliveryInterface {

public function send(Invoice $invoice) {

// Use an EDI library to send this invoice

}

}

Now the invoice process has the ability to deliver invoices via EDI without us having to make modifications to the actual invoicing code.

The OCP in PHPUnit

The PHPUnit testing framework provides a great example of how a class can be open to extension, but closed for modification. The PHPUnit_Extensions_Database_TestCase abstract class requires that each individual test case provide a getDataSet() method, which should return an instance ofPHPUnit_Extensions_Database_DataSet_IDataSet, an interface. PHPUnit provides several implementations of this interface, including a CsvDataSet, XmlDataSet, YamlDataSet, etc.

If you decided you wanted to provide your data sets as plain PHP arrays, you could write your own data set provider class to do so, simply by implementing the IDataSet interface. Using this new class, we could provide the TestCase class with a data set, parsed from PHP arrays, that works and acts like any of the built-in PHPUnit data sets.

class MyTest extends DatabaseTestCase {

public function getDataSet() {

return new ArrayDataSet([]);

}

}

The internal code of PHPUnit has not been modified, but now it is able to process pure PHP arrays as data sets. 1

https://github.com/mrkrstphr/dbunit-fixture-arrays.

Why does OCP matter?

The benefit of the Open/Closed Principle is that it limits the direct modification of existing source code. The more often code is changed, the more likely it is to introduce unintended side effects and cause defects. When the code is extended as in the examples above, the scope for potential defects is limited to the specific code using the extension.

Liskov Substitution Principle

The Liskov Substitution Principle says that objects of the same interface should be interchangeable without affecting the behavior of the client program 2.

This principle sounds confusing at first, but is one of the easiest to understand. In PHP, interfaces give us the ability to define the structure of a class, and then follow that with as many different concrete implementations as we want. The LSP states that all of these concrete implementations should be interchangeable without affecting the behavior of the program.

So if we had an interface for greetings, with various implementations:

interface HelloInterface {

public function getHello();

}

class EnglishHello implements HelloInterface {

public function getHello() {

return "Hello";

}

}

class SpanishHello implements HelloInterface {

public function getHello() {

return "Hola";

}

}

class FrenchHello implements HelloInterface {

public function getHello() {

return "Bonjour";

}

}

These concrete Hello classes should be interchangeable. If we had a client class using them, the behavior shouldn’t be affected by swapping them for one another:

class Greeter {

public function sayHello(HelloInterface $hello) {

echo $hello->getHello() . "!\n";

}

}

$greeter = new Greeter();

$greeter->sayHello(new EnglishHello());

$greeter->sayHello(new SpanishHello());

$greeter->sayHello(new FrenchHello());

While the output may be different, which is desired in this example, the behavior is not. The code still says “hello” no matter which concrete instance of the interface we give it.

LSP in PHPUnit

We already discussed an example of the Liskov Substitution Principle when we discussed the Open/Closed Principle. The ArrayDataSet class we defined as an instance of PHPUnit’s IDataSet is returned from the getDataSet() method of DbUnit’s DatabaseTestCase abstract class.

class MyTest extends DatabaseTestCase {

public function getDataSet() {

return new ArrayDataSet([]);

}

}

The PHPUnit DatabaseTestCase class expects that the getDataSet() method will return an instance of IDataSet, but doesn’t necessarily care what implementation you give it, so long as it conforms to the interface. This is also referred to as design by contract, which we’ll talk about in much more detail in Dependency Injection.

The key point of the Liskov Substitution Principle is that the behavior of the client code shall remain unchanged. Regardless of what implementation of IDataSet we return from getDataSet(), it will result in the data set being loaded into the database for unit tests to be run against. It doesn’t matter if that data came from CSV, JSON, XML, or from our new PHP array class: the behavior of the unit tests remain the same.

Why does LSP matter?

In order for code to be easily refactorable, the Liskov Substitution Principle is key. It allows us to modify the behavior of the program, by providing a different instance of an interface, without actually modifying the code of the program. Any client code dependent upon an interface will continue to function regardless of what implementation is given.

In fact, as we’ve already seen, the Liskov Substitution Principle goes hand-in-hand with the Open/Closed Principle.

Interface Segregation Principle

The Interface Segregation Principle dictates that client code should not be forced to depend on methods it does not use3. The principle intends to fix the problem of “fat” interfaces which define many method signatures. It relates slightly to the Single Responsibility Principle in that interfaces should only have a single responsibility. If not, they’re going to have excess method baggage that client code must also couple with.

Consider for a moment the following interface:

interface LoggerInterface {

public function write($message);

public function read($messageCount);

}

This interface defines a logging mechanism, but leaves the details up to the concrete implementations. We have a mechanism to write to a log in write(), and a mechanism to read from the log file in read().

Our first implementation of this interface might be a simple file logger:

class FileLogger implements LoggerInterface {

protected $file;

public function __construct($file) {

$this->file = new \SplFileObject($file);

}

public function write($message) {

$this->file->fwrite($message);

}

public function read($messageCount)

{

$lines = 0;

$contents = [];

while (!$this->file->eof()

&& $lines < $messageCount) {

$contents[] = $this->file->fgets();

$lines++;

}

return $contents;

}

}

As we continue along, though, we decide we want to log some critical things by sending via email. So naturally, we add an EmailLogger to fit our interface:

class EmailLogger implements LoggerInterface {

protected $address;

public function __construct($address) {

$this->address = $address;

}

public function write($message) {

// hopefully something better than this:

mail($this->address, 'Alert!', $message);

}

public function read($messageCount)

{

// hmm...

}

}

Do we really want our application connecting to a mailbox to try to read logs? And how are we even going to sift through the email to find which are logs and which are, well, emails?

It makes sense when we’re doing a file logger that we can easily also write some kind of UI for viewing the logs within our application, but that doesn’t make a whole lot of sense for email.

But since LoggerInterface requires a read() method, we’re stuck.

This is where the Interface Segregation Principle comes into play. It advocates for “skinny” interfaces and logical groupings of methods within interfaces. For our example, we might define a LogWriterInterface and a LogReaderInterface:

interface LogWriterInterface {

public function write($message);

}

interface LogReaderInterface {

public function read($messageCount);

}

Now FileLogger can implement both LogWriterInterface and LogReaderInterface, while EmailLogger can implement only LogWriterInterface and doesn’t need to bother implementing the write() method.

Further, if we needed to sometimes rely on a logger that can read and write, we could define a LogManagerInterface:

interface LogManagerInterface

extends LogReaderInterface, LogWriterInterface {

}

Our FileLogger can then implement the LogManagerInterface and fulfill the needs of anything that has to both read and write log files.

Why does ISP matter?

The goal of the Interface Segregation Principle is to provide decoupled code. All client code that uses the implementation of an interface is coupled to all methods of that interface, whether it uses them or not, and can be subject to defects when refactoring within that interface occur, unrelated to what implementations it actually uses.

Dependency Inversion Principle

The Dependency Inversion Principle states that 4:

A. High level modules should not depend upon low level modules. Both should depend upon abstractions.

and that:

B. Abstractions should not depend upon details. Details should depend upon abstractions.

This principle is very core to The Clean Architecture, and we’ll discuss how it fits in great detail in that leading chapter.

Imagine a class that controls a simple game. The game is responsible for accepting user input, and displaying results on a screen. This GameManager class is a high level class responsible for managing several low level components:

class GameManager {

protected $input;

protected $video;

public function __construct() {

$this->input = new KeyboardInput();

$this->video = new ScreenOutput();

}

public function run() {

// accept user input from $this->input

// draw the game state on $this->video

}

}

This GameManager class is depending strongly on two low level classes: KeyboardInput and ScreenOutput. This presents a problem in that, if we ever want to change how input or output are handled in this class, such as switching to a joystick or terminal output, or switch platforms entirely, we can’t. We have a hard dependency on these two classes.

If we follow some guidelines of the Liskov Substitution Principle, we can easily devise a system in which we have a GameManager that allows for the input and outputs to be switched, without affecting the output of the GameManager class:

class GameManager {

protected $input;

protected $video;

public function __construct(

InputInterface $input,

OutputInterface $output

) {

$this->input = $input;

$this->video = $output;

}

public function run() {

// accept user input from $this->input

// draw the game state on $this->video

}

}

Now we’ve inverted this dependency to rely on InputInterface and OutputInterface, which are abstractions instead of concretions, and now our high level GameManager class is no longer tied to the low level KeyboardInput and ScreenOutput classes.

We can have the KeyboardInput and ScreenOutput classes extend from these interfaces, and add additional ones, such as JoystickInput and TerminalOutput that can be swapped at run time:

class KeyboardInput implements InputInterface {

public function getInputEvent() { }

}

class JoystickInput implements InputInterface {

public function getInputEvent() { }

}

class ScreenOutput implements OutputInterface {

public function render() { }

}

class TerminalOutput implements OutputInterface {

public function render() { }

}

We’re also utilizing what’s known as Dependency Injection here, which we’ll talk about in the next chapter, conveniently called Dependency Injection.

If we can’t modify the input and output classes to conform to our interfaces, if they’re maybe provided by the system, it would then be smart to utilize the Adapter Pattern we previously discussed to wrap these existing objects and make them conform to our interface.

Why does DIP matter?

In general, to reach a decoupled code base, one should get to a point where dependency only flows inward. Things that change frequently, which are the high level layers, should only depend on things that change rarely, the lower levels. And the lower levels should never depend on anything that changes frequently, which is the higher level layers.

We follow this philosophy to make it easier for change to happen in the future, and for that change to have as little impact upon the existing code as possible. When refactoring code, we only want the refactored code to be vulnerable to defects; nothing else.

Applying SOLID Principles

The SOLID principles work tightly together to enforce code that is easy to extend, refactor, and test, which ultimately leads to less defects and quicker turn around time on new features.

Just as we continued building on our Design Patterns in this chapter, we’ll continue building on the principles of SOLID as we discuss Inversion of Control and the Clean Architecture later. The SOLID principles are the founding principles that make the Clean Architecture work.

1. If you want to see a complete example of this concept in action, checkout

2. http://www.objectmentor.com/resources/articles/lsp.pdf

3. http://www.objectmentor.com/resources/articles/isp.pdf

4. http://www.objectmentor.com/resources/articles/dip.pdf

Dependency Injection

One of the worst forms of coupling we encounter in object oriented programming deals with instantiating classes directly within other classes. The quickest way to find instances of this is to simply look for the new operator:

class CustomerController {

public function viewAction() {

$repository = new CustomerRepository();

$customer = $repository->getById(1001);

return $customer;

}

}

In this CustomerController, there is a dependency on CustomerRepository. This is a hard, concrete dependency; without the existence of CustomerRepository, the CustomerController simply will not work without it.

Instantiating dependencies within classes introduces several problems:

1. It makes it hard to make changes later. Refactoring is difficult when classes manage their own dependencies. If we wanted to change the method by which we retrieved data from the database, such as switching out the underlying library, or switching to a different database storage, we’d have to find all the instances within our code where we declared a CustomerRepository and make those changes. This would be a tedious and error-prone process.

2. It makes it hard to test. In order for us to write any kind of unit tests for the CustomerController class, we have to make sure that not only CustomerRepository is available to the test, but all dependencies that CustomerRepository relies on – such as a database full with testable data – have to be available as well. Now we’re doing full stack testing instead of simple unit testing. Coupling makes it very hard to test components in isolation.

3. We have no control over dependencies. In some instances, we might want a class dependency to be configured differently, depending on various circumstances, when it is used within another class. This becomes very awkward to develop when a class is declaring and configuring the declaration of its own dependencies.

These can turn out to be some pretty big problems, especially in larger applications. It can severely inhibit a developer from making even small changes to an application in the future.

Inversion of Control

Inversion of control is the process by which the instantiation and configuration of dependencies is moved from the dependent class and given instead to some external means. There are several of these “external means,” and we’ll talk about two of the most popular: the service locator patternand dependency injection.

Using a Service Locator

One method of achieving inversion of control is to use the Service Locator pattern. A Service Locator is a registry of resources that the application can use to request dependencies without instantiating them directly. When using this pattern, our code simply pulls its dependencies out of the service locator registry.

public function viewAction() {

$repository = $this->serviceLocator->get('CustomerRepository');

$customer = $repository->getById(1001);

return $customer;

}

Now, instead of instantiating its own dependencies outright, this controller pulls the dependent object out of the service locator. Depending on the implementation or framework that you use, you’ll probably have some code that registers CustomerRepository with the service locator, so that the service locator knows what to return to the calling code:

$serviceLocator->setFactory('CustomerRepository', function($sl) {

return new Path\To\CustomerRepository(

$sl->get('Connection')

);

});

In this theoretical service locator, an anonymous function is registered with the key CustomerRepository, and that function is responsible for building and configuring the repository and returning it. Further, the CustomerRepository itself has a dependency on something called Connection that we’ll just assume is defined elsewhere. The point here is to know that dependencies can have dependencies of their own. When they do, instantiating them directly when needed becomes even more overwhelming.

This code provides a couple several benefits.

1. There is now only have one place that is responsible for instantiating a CustomerRepository so that whatever code needs it will always have a properly configured repository. If we ever need to change anything about how that repository is created, there is only one place to go to do so. This makes refactoring the code base much easier.

2. Another benefit is that it makes the CustomerController code much easier to test. When testing the controller above, the test code can simply give it a different implementation of the service locator, one that has a mocked repository that can control what data it returns.

$serviceLocator->setFactory('CustomerRepository', function() {

return new Path\To\MockCustomerRepository([

1001 => (new Customer())->setName('ACME Corp')

]);

});

This MockCustomerRepository simply returns the test data “stored” based on customer ID, so that when testing the controller, it will return a Customer object with the name of ACME Corp. The controller is now tested separately from the actual repository, and the test is now only concerned with what is returned, and not how it is retrieved.

This code is still only marginally better than the factory example and the direct instantiation of the original code:

1. It still requests its own dependencies as needed through the service locator. This is better than instantiating the dependencies directly as at least we have control over what is actually instantiated within the service locator, which should make refactoring and testing easier.

2. In order to test, we have to go through the cumbersome process of setting up a fake service locator and registering required services with it just to get the controller to work.

Using Dependency Injection

Dependency Injection is a process by which a dependency is injected into the object that needs it, rather than that object managing its own dependencies.

Another way to think of dependency injection is to call it “third-party binding,” as some third party code is directly responsible for providing the dependency to the class. As Nat Pryce describes it, the use of the term injection can be seen as a misnomer, as it isn’t really injected into the code, but instead declared as part of the code’s API.

There are two methods of dependency injection that we’ll discuss:

1. Setter injection - Using this method, dependencies can be provided to the object through a set method on the class, which would be stored for later use in a class member variable.

2. Constructor injection - Using this method, dependencies are provided to the object through its constructor, which would also be stored for later use in a class member variable.

Using Setter Injection

Using Setter Injection, we would update the mechanism responsible for instantiating the CustomerController object (either a routing or dispatching process in our framework) to call some new set methods and provide the object with its dependencies:

$controller = new CustomerController();

$controller->setCustomerRepository(new CustomerRepository());

$customer = $controller->viewAction();

And of course, the CustomerController would be updated to have this setCustomerRepository method:

class CustomerController {

protected $repository;

public function setCustomerRepository(CustomerRepository $repo) {

$this->repository = $repo;

}

public function viewAction() {

$customer = $this->repository->getById(1001);

return $customer;

}

}

By the time the viewAction() method is called, this class should have been injected an instance of CustomerRepository through the setCustomerRepository method. Now the processes of retrieving dependencies has been completely removed from the CustomerController class.

When testing, we can see how much easier it is to mock the repository to provide a stable testing state:

$repository = new MockCustomerRepository([

1001 => (new Customer())->setName('ACME Corp')

]);

$controller = new CustomerController();

$controller->setCustomerRepository($repository);

$customer = $controller->viewAction();

assertEquals('ACME Corp', $customer->getName());

There is still one drawback here, though, and that is that using setter injection does not make the dependencies required. This puts us in a situation that can lead to hard-to-detect defects when we forget to inject some dependency:

$controller = new CustomerController();

$customer = $controller->viewAction();

This code will throw errors as, without calling the setCustomerRepository() method, the class $repository variable will be null when it is used. Given how small this application is, we’ll likely find the problem easily, but in a larger system with more involved code, this could lead to a rough time debugging where something went wrong.

Using Constructor Injection

Using Constructor Injection, the problem presented with setter injection is solved in that, in order for the object to be instantiated, the dependencies must be injected via the constructor. If they aren’t, a very helpful, specific fatal error is thrown by PHP.

Providing that dependency would look something like this:

$controller = new CustomerController(new CustomerRepository());

$customer = $controller->viewAction();

The CustomerController is updated to require an instance of CustomerRepository be passed along to the constructor. We use type-hinting here so that an actual instance of CustomerRepository is given, not just any variable.

class CustomerController {

protected $repository;

public function __construct(CustomerRepository $repo) {

$this->repository = $repo;

}

public function viewAction() {

$customer = $this->repository->getById(1001);

return $customer;

}

}

The CustomerController is now guaranteed to have an instance of CustomerRepository ready to be used. This controller can test this just like it was with setter injection using a mocked repository, except it would be provided to the constructor rather than the set method:

$repository = new MockCustomerRepository([

1001 => (new Customer())->setName('ACME Corp')

]);

$controller = new CustomerController($repository);

$customer = $controller->viewAction();

assertEquals('ACME Corp', $customer->getName());

Dependency injection helps to both loosely couple our code base, as well as provides the ability to test individual components in isolation, without having to construct, prepare, and pass around their individual dependencies. Since constructor injection forces the object to be injected with its dependencies, it will be preferred over setter injection throughout the rest of this book.

When to use Dependency Injection

Now that we’ve discussed what dependency injection is and the problems it can help solve in your code, it’s important to take a moment think about where it is appropriate to use this technique, and where it is not. This is a bit of a blurry line, and whoever you talk to, you’ll probably get a different opinion.

Here’s where I think you should use dependency injection:

1. When the dependency is used by more than one component. If it’s being used by many things, it probably makes sense to abstract out the instantiation and configuration and inject the dependency, rather than doing it when needed. Without this, we make it hard to refactor our code that uses this dependency. However, if the dependency is only used once, you then only have one place to go when refactoring the code.

2. The dependency has different configurations in different contexts. If a dependency is configured differently in the different places it is used, then you definitely want to inject it. Again, this configuration shouldn’t take place in the dependent class. Not only does it make refactoring difficult, but can make testing difficult as well. You’ll probably also want to invest in a real factory that can create these dependencies under different scenarios to abstract further the creation of those dependencies.

3. When you need a different configuration to test a component. If testing a dependent object requires that the dependency needs to be configured differently to be tested, you’ll want to inject it. There isn’t any other good way around this. Think back to our example of mocking theCustomerRepository to control what data it returned.

4. When the dependency being injected is part of a third party library. If you’re using someone else’s code, you shouldn’t be instantiating it directly within the code that depends on it. These dependencies should absolutely be injected into your code. The usage of someone else’s code is something we might refactor often. Special attention needs to be paid to this scenario, and we’ll discuss that in detail in Abstracting with Adapters using the Adapter Pattern we’ve already discussed.

But there are definitely some scenarios where you probably don’t want to use dependency injection.

If a dependency doesn’t need to be configured in anyway (meaning, no constructor arguments or set methods that need to be called to set it up), and doesn’t have dependencies itself, it might be safe to go ahead and just instantiate that dependency within the class that needs it. This is especially true when the dependency is the component within the same layer of the application (we’ll get to talking about various layers of software in a little bit).

For example, if our framework requires that our controller actions return some kind of view or response object, it makes perfect sense to just instantiate and return that right in the action.

public function viewAction() {

$customer = $this->repository->getById(1001);

return new ViewModel([

'customer' => $customer

]);

}

There is little gained value from injecting this ViewModel class into the controller. It has no configuration, it has no dependencies itself, and in the case of testing, we probably just want to verify that an instance of ViewModel was returned with an instance of Customer stored within it.

Using Factories to Create Dependencies

If we have a dependency that needs configuration, it doesn’t always make sense to inject that dependency itself. Sometimes it might be a better idea to inject an object that knows how to build this dependency for us. This is useful when the way in which that dependency is configured is controlled by scenarios within the class itself.

Looking at the example above: what if we wanted to return a different type of response based on a context requested? Maybe by default we would return HTML, but based on context, might return JSON or XML as well?

In this case, we may want to inject a factory that knows how to build the response based on the requested context:

class CustomerController {

protected $repository;

protected $responseFactory;

public function __construct(

CustomerRepository $repo,

ResponseFactory $factory

) {

$this->repository = $repo;

$this->responseFactory = $factory;

}

public function viewAction() {

$customer = $this->repository->getById(1001);

$response = $this->responseFactory->create($this->params('context'));

$response->setData('customer', $customer);

return $response;

}

}

Previously, our dependency was the specific response we were returning. Now, however, it’s this new ResponseFactory class that builds a response for us.

The important thing here is that we are abstracting out the logic that determines how to build the dependency, and instead depending on that abstraction. We’re also injecting that in so that if the logic or methodology ever changes, we just have to change the implementation instead of updating an unknown number of locations that were previously building their own responses.

Handling Many Dependencies

It’s very easy to let dependency injection get out of control:

public function __construct(

CustomerRepository $customerRepository,

ProductRepository $productRepository,

UserRepository $userRepository,

TaxService $taxService,

InvoiceFactory $invoiceFactory,

ResponseFactory $factory,

// ...

) {

// ...

}

This is usually indicative of having a class that violates the Single Responsibility Principle and does too much and contains too much logic. There’s no hard rule about how many dependencies a class can have. Generally, the fewer the better, however, it’s entirely possible to go too far in the other direction as well, and end up with a hierarchy of tiny classes that are hard to follow, refactor and test.

After understanding the concepts of this book, you can start to use the “Feels Bad” policy of knowing when to refactor a bad situation into good, healthy code.

Are we still coupling?

Our whole reason for going down this path of dependency injection was to reduce coupling in our code. Recall that our initial example, pre-inversion of control looked like this:

class CustomerController {

public function viewAction() {

$repository = new CustomerRepository();

$customer = $repository->getById(1001);

return $customer;

}

}

In this code we are highly coupled to the CustomerRepository as we are declaring a concrete dependency right in the middle of our code. By switching to using dependency injection, we ended up with this:

class CustomerController {

protected $repository;

public function __construct(CustomerRepository $repo) {

$this->repository = $repo;

}

public function viewAction() {

$customer = $this->repository->getById(1001);

return $customer;

}

}

Now we’re being provided some kind of class that is an instance of CustomerRepository. This is much looser coupling, but it’s still coupling. We still need something that is or extends from CustomerRepository. There’s no real way around that. And since this repository will likely sit within our persistence implementation, we’re also coupling to a whole infrastructure layer that talks to a database.

There is one level farther we can go with decoupling our dependencies by using interfaces to define contracts.

Defining a Contract with Interfaces

In the previous chapter we discussed the principle of inversion of control, and describe how dependency injection can make refactoring and testing code easier. We started out by discussing object coupling, and presented dependency injection as a method of limiting coupling. However, when we reached the end, we realized that we hadn’t entirely removed the coupling, we only made it weaker by moving it to the constructor from the methods of the class.

class CustomerController {

protected $repository;

public function __construct(CustomerRepository $repo) {

$this->repository = $repo;

}

public function viewAction() {

$customer = $this->repository->getById(1001);

return $customer;

}

}

This class is still well coupled to the CustomerRepository class. Since the CustomerRepository class is responsible for, at least through its dependencies, connecting to and retrieving data from a database, this means that the CustomerController is also coupled to that database.

This can be problematic if we ever decided to switch data sources, such as moving to a NoSQL variant, or switching to some API service to provide our data. If we do that, we’ll have to then go modify all the code across our entire code base that uses this CustomerRepository to make it use something else.

Further, if we want to test this CustomerController, we still have to give it an instance of CustomerRepository. Any mock object we create will need to extend from CustomerRepository to pass the type-hint check. That means our simple mock repository will still have to have the entire database back-end tied to it, even if we are overriding everything it does. That’s pretty messy.

Interfaces in PHP

Recall that in PHP, an interface is a definition of a class, without the implementation details. You can think of it as a skeleton of a class. An interface cannot have any method bodies, just method signatures.

interface Automobile {

public function drive();

public function idle();

public function park();

}

Any class implementing an interface must implement all the methods of that interface.

class Car implements Automobile {

public function drive() {

echo "Driving!";

}

public function idle() {

echo "Idling!";

}

public function park() {

echo "Parking!";

}

}

Any number of implementations may exist for the interface Automobile:

class DumpTruck implements Automobile {

public function drive() {

echo "Driving a Dump Truck!";

}

public function idle() {

echo "Idling in my Dump Truck!";

}

public function park() {

echo "Parking my Dump Truck!";

}

}

The two classes Car and DumpTruck are considered compatible as they both define the Automobile interface, and either could be used in any instance where an Automobile is necessary.

This is known as polymorphism, where objects of different types can be used interchangeably, so long as they all inherit from a common subtype.

Using Interfaces as Type Hints

The usage of interfaces comes in handy when trying to reduce coupling within a class. We can define an interface of some dependency, and then reference only that interface. So far, we’ve been passing around concrete instances of CustomerRepository. Now, we’ll create an interface that defines the functionality of this repository:

interface CustomerRepositoryInterface {

public function getById($id);

}

We have a simple interface with one method, getById(), which returns a Customer object for the customer data identified by $id. As this is an interface, we cannot provide any implementation details, so this class provides no information about where the data comes from, or how it is retrieved.

Now in our controller, we use PHP’s type-hints for methods and functions to declare that the argument passed to the __construct() method must be an instance of our new interface, CustomerRepositoryInterface.

class CustomerController {

protected $repository;

public function __construct(CustomerRepositoryInterface $repo) {

$this->repository = $repo;

}

public function viewAction() {

$customer = $this->repository->getById(1001);

return $customer;

}

}

Now the CustomerController class is only coupled to the CustomerRepositoryInterface, but that’s okay: this interface isn’t a concrete implementation, it’s just a definition of an implementation. We can couple to this and, in fact, we should, as it defines how our application interacts, without referencing the specific implementations.

Whatever mechanism is responsible for instantiating the CustomerController can still provide it with the concrete CustomerRepository, so long as that class implements the `CustomerRepositoryInterface’.

class CustomerRepository implements

CustomerRepositoryInterface {

public function getById($id) {

// get and return the customer...

}

}

The CustomerRepository provides the implementation of the getById() method and fulfills the requirements of the interface.

When we want to test this controller now, we can instead use a mock instance of CustomerRepositoryInterface:

class MockCustomerRepository implements

CustomerRepositoryInterface {

public function getById($id) {

if ($id == 1001) {

return (new Customer())

->setId(1)

->setName('Customer #1001');

}

}

}

While this may not be the greatest code (and using a mocking library like Mockery or the mocking utilities provided by PHPUnit would be better), we can nevertheless pass this in to CustomersController to fulfill the CustomerRepositoryInterface type hint. Now the controller is being tested in isolation, without the specific configuration and dependencies of the real CustomerRepository.

The CustomersController really doesn’t care what object you end up injecting it with. So long as that object meets the required interface (and it will, otherwise a fatal error will be thrown), the controller should function just the same. This also assumes, of course, that the dependencies being injected actually work and return the data they should.

information

The Liskov Substitution Principle

If this sounds familiar, it should. We already discussed these principles when we talked about the Liskov Substitution Principle. Our various concrete repositories are interchangeable as they both extend the same interface.

The Dependency Inversion Principle also applies here, as we’re modifying our high level code (the controller in our example) to not depend upon low level code (the repository), and instead depend upon an abstraction.

Using Interfaces as a Contract

Another way to think about using interfaces with dependency injection is that they are fulfilling a contract. Our interface is a contract between the supplier, our code instantiating a dependency and injecting it, and our client, the class with a dependency need. The contract is fulfilled when the correct object is injected into the object.

This concept has been described as programming by contract. It’s an interesting way to think about interfaces and dependency injection.

Making Third Party Code Conform to Contracts

Using interfaces to define contracts is easy when it’s our own code, but how do we make use of a third party library and make it conform to an interface for dependency injection? After all, we shouldn’t simply open up the third party source code and modify it to extend from one of our interfaces.

The answer is to use the Adapter Pattern.

Abstracting with Adapters

Interfaces have provided the means to completely decouple our code from concrete implementations of their dependencies. So far, we’ve only show how to do this with our own low level code. What if we want to use some third party library instead?

Let’s say we find a great third party library through Packagist called Bill’s Geocoder that validates addresses with Google Maps or USPS or some other service.

class AddressController extends AbstractController {

protected $geocoder;

public function __construct(BillsGeocoder $geocoder) {

$this->geocoder = $geocoder;

}

public function validateAddressAction() {

$address = $this->vars()->fromPost('address');

$isValid = $this->geocoder->geocode($address) !== false;

}

}

We’re using some dependency injection into the controller, which is great. This is a step in the right direction and solves some problems for us, but it’s still strongly coupling our controller to whoever Bill is. What if he goes away? What if you figure out DavesGeocoder is so much better because it supports Zip+4, which BillsGeocoder didn’t? And what if you just happen to use this geocoder all over the place and now you have to go update all those references? What if DavesGeocoder doesn’t have a geocode() method but instead has validateAddress(). You’ve run into a refactoring nightmare.

Setting up the Adapter

Recall back to our discussion on design patterns, specifically the Adapter Pattern. Adapters are perfectly suited to solve this problem as they allow us to “wrap” the functionality of the third party code, and by doing so, make it conform to an interface we define, so that we can inject that adapter to fulfill the interface.

This is exactly what we did when we discussed the Adapter Pattern. We started by defining our interface:

interface GeocoderInterface {

public function geocode($address);

}

Then, we’ll go ahead and make our controller depend only upon this interface:

class AddressController extends AbstractController {

protected $geocoder;

public function __construct(GeocoderInterface $geocoder) {

$this->geocoder = $geocoder;

}

public function validateAddressAction() {

$address = $this->vars()->fromPost('address');

$isValid = $this->geocoder->geocode($address) !== false;

}

}

Finally, we’ll create an adapter to wrap BillsGeocoder and make it conform to our GeocoderInterface that is required by our AddressController class:

class BillsGeocoderAdapter implements GeocoderInterface {

protected $geocoder;

public function __construct(BillsGeocoder $geocoder) {

$this->geocoder = $geocoder;

}

public function geocode($address) {

return $this->geocoder->geocode($address);

}

}

In our geocode() method, we’re simply passing off the processing to our instance of BillsGeocoder, which we take through the constructor.

We can use dependency injection to inject an instance of BillsGeocoderAdapter into our AddressController, which allows us to use a third party library but makes sure it conforms to the interface we need.

How does this help?

This method of using adapters with third party libraries allows us to remain decoupled and free from dependence on those third party libraries. It allows us to freely swap out those dependencies without having to rewrite any code that uses them, and it allows us to easily test our application and its use of those dependences without actually having to test those dependencies ourselves. We only have to test that we’re properly utilizing them.

We’ll later discuss the importance of External Agency Independence when we discuss The Clean Architecture.