Symfony to WordPress: Dependency injection

This is about all the great things that the Symfony framework brings in and could help in the WordPress world. Plugin- and Theme-Developer will love the dependency injection part. It brings a well structured way of rusing things and makes maintaining very easy.

For a couple of projects now a service container helped me to quickly build fast and lightweight plugins. Often you have to access variables or data that is far away from the current scope, like you need the plugin config within some template or method. Read on if you think of a function get_config() or writing global $_my_config;, because this is just bad and I like to call it wrong in terms of OOP (object oriented programming).

What do we want to keep accessible at any time?

  • Simple strings/bool (like credentials or settings for the plugin).
  • Posts, pages or other (our own object pool).
  • Own instances of our plugin classes (to simplify OOP).
  • Usually you instantiate everything you need at once which costs much memory. Or you instantiate it way to late which makes the plugin not very flexible or maintainable.

A service container solves all this. Less memory usage, faster and simpler plugins. Easy to maintain and extend.

A simple service container

What we see here is some altered code of Daniel Hüsken (inventor of BackWPup), who were inspired by Pimple. It is a very simple service container more like an object pool with lazy instantiating:

class Service_Container {
  private $values = array();
  private $raw = array();

  function __construct( $values = array() ) {
    $this->values = $values;
  }

  function set( $id, $value ) {
    $this->values[ $id ] = $value;
  }

  function has( $id ) {
    return array_key_exists( $id, $this->values );
  }

  function get( $id ) {
    if ( ! $this->has( $id ) ) {
      throw new \NotFoundException( // as in PSR-11
        sprintf( 'Service %s does not exist.', $id )
      );
    }

    if ( isset( $this->raw[ $id ] ) ) {
      return $this->raw[ $id ];
    }

    $value = $this->values[ $id ];

    if ( is_callable( $value ) ) {
      $value = $value( $this );
    }

    return $this->raw[ $id ] = $value;
  }
}

The simplest of all service container I’ve seen so far. This is especially good in the WordPress context when you have no need for complex patterns, factories or scope for dependency injection.

Very handy in a plugin

Imagine this in a plugin:

$_someslug_container = new Service_Container( [
  'api_key' => 'abba1972',
  'foo'     => new \Someslug\Not_Lazy_Loaded_Class(),
  'api'     => function ( $container ) {
    return new \Someslug\Api( $container->get( 'api_key' ) );
  }
] );

First we store some credentials in the service container, then we store some kind of configuration which instantly costs run-time and memory. To avoid flooding the memory cellar we can lazy load things by wrapping them into a function (like “api” entry). This way the API will only be instantiated (and cost memory) when it is really used.

Using the services anywhere

We could add some function to access the container easily from anywhere:

function _someslug_container() {
  global $_someslug_container;

  return $_someslug_container;
}

Which is not mandatory but helps at any point of the plugin or theme like in functions, methods, templates and so on:

$api = _someslug_container()->get( 'api' );

Now, wherever we are, we can use things out of our container. Here the API class get instantiated for the first time. Before it didn’t do anything, took no run-time and very little memory which keeps the plugin/theme fast and lightweight.