Written by Rafal Kanski
Published August 29, 2016

How to use composer to run Dependency Inversion in PHP

Assuming that you, the reader, are a programmer, I think I can safely presume that each of us at some point in our career comes to a point where we not only want the code to work but also for it to look clean. Readability, flexibility and scalability begin to have a meaning to us.

With time, more and more details draw our attention. We realize that the name of each variable, every method and the amount of its parameters are very important. We also start to appreciate the advantages of polymorphism, inheritance and abstraction.

That is because we live in 2016, when work is done in groups, using agile methodologies, and each line of code that we write should be understood by other developers, and every class that we have written should be easy to maintain and open for extension. In the end, we strive for perfection, we want to be better programmers. And here design patterns, TDD/BDD and principles such as DRY KISS and SOLID come to our aid. I would like to dedicate this post to the latter. To be precise, to its last letter – D.

SOLID

SOLID is an acronym for the five principles of object-oriented programming, which must be followed. At least that is what Robert C. Martin, the author of this rule who needs no introduction, believes. He wrote a lot of publications and books, one of which is one of my favorites – “Clean Code. A Handbook of Agile Software Craftsmanship”.

Single responsibility

This principle tells us that the class we create should be responsible for one thing only. Just like in real life, if I am a programmer, I am not a plumber, a painter nor a singer at the same time. I do one thing but I am trying to do it well. Therefore, let’s look at the following example of a class that has too many responsibilities:

class DataSaverAndLogger
{
    /**
     * @param string $string
     */
    public function log($string)
    {
        // implementation
    }

    /**
     * @param mixed $data
     */
    public function save($data)
    {
        // implementation
    }
}

If my job is to log events in the system, should I really be taking care of saving data? After refactoring the above code would look like this:

class DataSaver
{
    /**
     * @param mixed $data
     */
    public function save($data)
    {
        // implementation
    }
}

class Logger
{
    /**
     * @param string $string
     */
    public function log($string)
    {
        // implementation
    }
}

Isn’t it a better, simpler and more readable solution?

Open close interface

This rule states that you must write code open for extension and closed for modification. This can be achieved by using inheritance or interfaces. We do not have to search long to find an analogy in everyday life. Just ask yourself. If I want to add RAM to my computer, do I have to modify its motherboard with my own hands? No. The computer is usually ready for expansion with RAM modules which can be easily mounted in dedicated slots.

class Html
{
    // some logic and public interface

    /**
     * @param string $string
     */
    public function generate($string)
    {
        // implementation
    }
}

In this case, changing this piece of code requires direct tampering with the class’ code. Would it not be better to delegate this process to an external class and inject it in the constructor? Let’s see.

interface GeneratorInterface
{
    /**
     * @param string $string
     */
    public function generate($string);
}

class SomeGenerator implements GeneratorInterface
{
    /**
     * {@inheritdoc}
     */
    public function generate($string)
    {
        // implementation
    }
}

class Html
{
    private $generator;

    public function __construct(GeneratorInterface $generator)
    {
        $this->generator = $generator;
    }

    // some logic and public interface

    /**
     * @param string $string
     */
    public function generate($string)
    {
        $this->generator->generate($string);
    }
}

Liskov substitution rule

This rule states that if we are using typing on a base class, we should be able to use sub-classes. Just like in real life. When we have HDMI cables, regardless of the country and the manufacturer, they should all work the same. Let’s look at the following example.

class MyLogger
{
    /**
     * @param string $string
     */
    public function log($string)
    {
        // implementation
    }
}

class SecondLogger
{
    /**
     * @param string $string
     */
    public function logMessage($string)
    {
        // implementation
    }
}

From the client perspective, it is really hard to use them. Let’s see:

if ($a instanceof SecondLogger) {
    $a->logMessage('message');
} elseif ($a instanceof MyLogger) {
    $a->log('message');
}

It is better to introduce abstraction layer:

abstract class Logger
{
    /**
    * @param string $string
    */
    abstract function log($string);
}

class MyLogger extends Logger
{
    /**
    * {@inheritdoc}
    */
    public function log($string)
    {
        // implementation
    }
}

class SecondLogger extends Logger
{
    /**
    * {@inheritdoc}
    */
    function log($string)
    {
        // implementation
    }
}

From now, the client is not aware of implementation which is used:

// i don’t care if it is MyLogger or SecondLogger, i use Logger abstraction
$a->log('message');

Interface segregation principle

This principle states that the client should not have access to a very large interface, especially when it does not use some of the supplied methods. In reality, when our ear hurts, an otolaryngologist will provide us with more specific information than a general practitioner. We are not interested in the fact that he/she can prescribe an antibiotic for bronchitis, or diagnose any skin or nail disease. Let’s take a look at an example.

interface FatInterface
{
    /**
    * @param string $string
    */
    public function generate($string);

    /**
    * @param string $string
    */
    public function log($string);

    /**
    * @param string $string
    */
    public function save($string);
}

If I am interested in logging in, then why does this interface have such diverse responsibilities as logging in and saving data? Separating them would be a better solution.

interface GenerateInterface
{
    /**
    * @param string $string
    */
    public function generate($string);
}

interface LogInterface
{
    /**
    * @param string $string
    */
    public function log($string);
}

interface SaveInterface
{
    /**
    * @param string $string
    */
    public function save($string);
}

Dependency Inversion

This principle states that we should make the code dependent on abstractions, and not on specific classes. Just as in real world, house blueprints do not bear the name of a particular electrician, it is only assumed that electricians will connect electricity. At a given time, we have to define the need to employ someone with a specific set of skills, not a person with a given name and surname. Let’s look at an example.

class LogImplementation
{
    /**
    * {@inheritdoc}
    */
    public function log($string)
    {
        // implementation
    }
}

class Html
{
    private $logger;

    public function __construct(LogImplementation $logger)
    {
        $this->logger = $logger;
    }

    public function generate()
    {
        $this->logger->log('message');
    }
}

It would be better if the HTML class was focused on interfaces. In future it would be easier to swap components.

interface LogInterface
{
    /**
    * @param string $string
    */
    public function log($string);
}

class LogImplementation implements LogInterface
{
    /**
    /* {@inheritdoc}
    */
    public function log($string)
    {
        // implementation
    }
}

class Html
{
    private $logger;

    public function __construct(LogInterface $logger)
    {
        $this->logger = $logger;
    }
    
    public function generate()
    {
        $this->logger->log('message');
    }
}

Great, but to use the Dependency Inversion we need some standard interfaces which could be used by everyone. Here PHP-FIG comes to our aid. PHP-FIG is Framework Interopt Group which aims at  delivering these interfaces on many levels. Among the results of their work, which you can easily find on github, they have sets of interfaces (cache, http-message and login), standards of coding or autoloading. They are constantly working on new ones and developing these that exist.. For further information see here.

When we have common interfaces and know how to use dependency inversion, we still need  to find a way to share our work with others, which is where composer – a well-known tool – comes in handy. Yes, it supports dependency inversion. Let’s try to combine everything into a coherent whole by preparing a sample package.

Simple API Client

Let’s assume for the purposes of this entry and understanding the discussed topic that you want to write a simple API client. It is natural that it will be a wrapper for some HTTP client library. To find it we use packagist. We decide which one to choose from the most popular ones, i.e. guzzle. Since our package will be distributed through composer, we create the composer.json file that looks like this:

{
    "name": "somename/api-client",
    "description": "API Client",
    "minimum-stability": "stable",
    "require": {
        "guzzlehttp/guzzle": "6.2.1"
    }
}

Can you already see a potential problem? Almost every project, a smaller or a larger one, can now use guzzle. It is quite a popular library. If someone will require another version of it that is incompatible with our requirements, the installation of our package will fail. In this case the stubborn person who wants to use our API client, despite the many inconveniences, will have to adapt to our requirements which can be costly, time-consuming and sometimes simply impossible. Of course, there is semantic versioning, but it does not give us full flexibility.

Let’s try to solve this problem another way. First, we’ll visit PSR-FIG’s website. A brief overview will lead us to PSR-7. It is a HTTP message standard. It defines every aspect of sending data using the HTTP protocol, so we will find the interfaces for request, response and stream here. Perfect, we have something that allows us to focus on the interfaces rather than the implementation but we are still missing something very important. The bonding material, i.e. the HTTP client interface. There is no point looking for it in HTTP message. But just look around a bit and you will find a website. The authors create a number of tools and interfaces using the PSR7 standard. And so we come by the HTTP Client package or, more precisely, a client interface using the PSR-7. Perfect. We can focus entirely  on the interfaces. But how do we state in the composer’s requirements that any implementation of this interface is to be delivered? Virtual packages that can be easily defined in composer using “provide” come to our aid in this regard.

{
    "name": "somename/api-client",
    "description": "API Client",
    "minimum-stability": "stable",
    "type": "project",
    "provide": {
        "somename/virtual-package-name": "1.0"
    }
}

In the example above, we declare that we deliver “somename/virtual-package-name”. After adding it to packagist, it will be possible to find it using, e.g. the phrase “virtual-package-name”. The search results page for that phrase will also include an appropriate notification that it is a virtual package.

Zrzut ekranu 2016-08-29 o 12.02.08

After clicking, you will get a view of all the packages which declare having “somename/virtual-package-name” in their “provide” attribute, i.e. only ours – “somename/api-client”.

So what is this virtual package? In summary, we supply its name through the “provide” attribute, it can be any name and people will be able to find it in packagist right away. This is only a declaration that we provide something. But what exactly: which interface or what abstraction, that is a matter of agreement. And so, for the PSR-7 package “psr/http-message” the virtual package is “psr/http-message-implementation”. After searching for it we’ll see a whole list of “psr /http-message” implementations.

Zrzut ekranu 2016-08-29 o 12.04.39

Of course, this solution is far from ideal. As the author of the package, I can lie that I provide something while I really don’t. Also, the ability to create virtual packages in an uncontrolled manner may result in a situation where the official virtual package for “psr/http-message” will be covered with thousands of packages with similar names. You don’t even need to be spiteful, an accidental typo will do the trick.

Apart from these drawbacks, there are also pluses. Let’s go back, therefore, to our API client. Since we have already found an HTTP Client defined in the “php-http/httplug” and its virtual package is “php-http/client-implementation”, nothing stands in the way of putting “php-http/client-implementation” in the requirements in composer and leaving the choice of implementation to the person who will be installing our package.

{
    "name": "somename/api-client",
    "description": "API Client",
    "minimum-stability": "stable",
    "type": "project",
    "require": {
        "php-http/client-implementation": "^1.0"
    }
}

And now, in a situation where someone has guzzle in dependencies, they will be able to choose another package that provides this interface without its use. Just remember that as the authors of the package we have to operate on interfaces which may not be a trivial task, but we should probably try it. Last but not least , a small note. While working on our own library, we will probably be using the “composer install” command. This means that we will need the “php-http/client-implementation” implementation. Otherwise, the operation will fail and composer will return an error. The solution is to put a sample implementation in “require-dev”. This, in turn, can prove useful in, for example, tests. Just do not use it by accident in the package’s code.

{
    "name": "somename/api-client",
    "description": "API Client",
    "minimum-stability": "stable",
    "type": "project",
    "require": {
        "php-http/client-implementation": "^1.0"
    },
    "require-dev": {
        "php-http/guzzle6-adapter": "^1.1"
    }
}

What is my opinion on dependency inversion using composer? I am fully aware of its disadvantages, which I mentioned in the text, however,  there are also advantages. In practice, such solution saved me a lot of time and energy in some cases. If you are interested in how such a package should look like, please refer to one of them of which I am a co-author.

Written by Rafal Kanski
Published August 29, 2016