Developing a plugin using DI and TDD 14

How comes I’m not defining constructors in any interface?

Interface inception

The recurrent theme when using a dependency injection container is “binding” an interface to a concrete implementation; this means that the container will provide the specified concrete class instance to any object requiring a specific interface implementation.
An example in the development of the “I’d like this” plugin is the one dealing with meta boxes and the usage of the DI52 dependency injection container.
In the idlikethis_ServiceProviders_MetaBoxes service provider I’m binding two meta boxes implementations

class idlikethis_ServiceProviders_MetaBoxes extends tad_DI52_ServiceProvider
{

    /**
     * Binds and sets up implementations.
     */
    public function register()
    {
        add_action('add_meta_boxes', array($this, 'add_meta_boxes'));
    }

    public function add_meta_boxes()
    {
        $this->container->bind('idlikethis_MetaBoxes_VotesDisplayMetaBoxInterface', 'idlikethis_MetaBoxes_VotesDisplayMetaBox');
        $this->container->bind('idlikethis_MetaBoxes_PostControlMetaBoxInterface', 'idlikethis_MetaBoxes_PostControlMetaBox');

        $this->container->tag(array(
            'idlikethis_MetaBoxes_VotesDisplayMetaBoxInterface',
            'idlikethis_MetaBoxes_PostControlMetaBoxInterface',
        ), 'meta-boxes');

        /** @var idlikethis_MetaBoxes_MetaBoxInterface $meta_box */
        foreach ($this->container->tagged('meta-boxes') as $meta_box) {
            add_meta_box($meta_box->id(), $meta_box->title(), array($meta_box, 'render'), $meta_box->screen(), $meta_box->context(), $meta_box->priority());
        }
    }
}

and relying on a number of methods each meta box implementing class should define to add the meta box to WordPress (title(), screen() and so on).
The meta boxes implement to two distinct interfaces

interface idlikethis_MetaBoxes_PostControlMetaBoxInterface extends idlikethis_MetaBoxes_MetaBoxInterface
{

}

and

interface idlikethis_MetaBoxes_VotesDisplayMetaBoxInterface extends idlikethis_MetaBoxes_MetaBoxInterface
{

}

that will in turn extend the idlikethis_MetaBoxes_MetaBoxInterface root interface

interface idlikethis_MetaBoxes_MetaBoxInterface
{

    /**
     * Returns the meta box id.
     *
     * @return string
     */
    public function id();

    /**
     * Returns the meta box title.
     *
     * @return string
     */
    public function title();

    /**
     * Returns the screen(s) the meta box should display on.
     *
     * @return string|array|WP_Screen
     */
    public function screen();

    /**
     * Returns the context the meta box should display into.
     *
     * @return string
     */
    public function context();

    /**
     * Returns the priority for the meta box.
     *
     * @return string
     */
    public function priority();

    /**
     * Echoes the meta box markup to the page.
     *
     * @param string|WP_Post|array $object
     * @param array|mixed $box The meta box registration description.
     * @return void
     */
    public function render($object, $box);
}

that’s exposing a generic meta box API, the one that will be required of any meta box the project might use.

A tale of two cities

Interfaces are meant to detail the public API of an object; I think of those as “instructions” and of abstract classes as “blueprints”.
While the metaphor might be rough cut in some applications and circumstances it helps me to stick to a simple class design principle: do not make the __construct method signature part of the interface.
If an object has its dependencies injected then constructing those dependencies will not be a responsibility of that object: it will not need building instructions.
An easy example can be made of the two meta boxes: one is about showing the votes for a post while the other one is about giving the user some control on such votes.
Different responsibilities means different implementations and dependencies.
Sticking to the idea of providing any class all of its dependencies in the __construct method means that the two meta boxes constructor methods will have to differ in the number and nature of the arguments.
So: no __construct method in the root idlikethis_MetaBoxes_MetaBoxInterface interface, but what about a more specific one like idlikethis_MetaBoxes_PostControlMetaBoxInterface?
I would not specify the constructor method there either; thinking of the meta box responsibility now what I can come up with is that it will render some control instruments for the site administrator to use: the class would probably require the idlikethis_Repositories_CommentsRepositoryInterface as a dependency and the rendering engine.
But as the plugin iterates and progresses I might want to show certain controls to specific user roles and the new class extending that one would require the additional (and currently non existing) idlikethis_Users_UserInterface dependency to make some checks on the user role or capabilities.
Once the __construct method implementation is changed in the interface any class implementing it will have to change for the wrong reason: it’s not its responsibility that changed but the dependencies of another class.
Any class implementing the idlikethis_MetaBoxes_PostControlMetaBoxInterface would then be provided an instance of the idlikethis_Users_UserInterface concrete implementation that’s not using in a perfect waste of resources, code and developer time (those changes will have to be propagated and maintained).
So different classes, different responsibilities, different dependencies, different constructors: that’s why I’m not making constructor methods prototypes part of interfaces where possible.

Next

Stop the talk, show the votes.

I appreciate your input