Functional Dependency Injection in PHP

Having become used to the convenience of passing first-class functions around in JavaScript to make other functions decoupled and easily testable, I was wondering if we could do the same thing in PHP.

Of course, PHP technically has first-class functions as well, but the syntax is a little awkward, since the functions must be referenced as a string (and sometimes as an array).

Often I have some logic that can easily be contained in a pure function, and while I could put it in a class method, it’s not uncommon that the function doesn’t feel like it belongs to any particular class.

In these cases I tend to create “helper” classes. Essentially, I create a god class which is really just there to namespace its functions. If there’s a group of functions I want to inject, I might use regular class methods for this purpose, injecting an instance of the class. Otherwise, I use static methods. It occurred to me that maybe I could do the same thing with plain functions and actual namespaces.

JavaScript

In JavaScript one could do the following (this example is a bit contrived, but bear with me).

export function getGreenTea() {
    return 'green tea';
}

export function getOolongTea() {
    return 'oolong tea';
}
import {getGreenTea, getOolongTea} from 'tea-types';

function makeTea(getTea) {
    console.log(getTea());
}

makeTea(getGreenTea);
makeTea(getOolongTea);

PHP instance methods

Here’s how it could be done in PHP with classes and instance methods.

class GreenTea {
    public function getTea() {
        return 'green tea';
    }
}

class OolongTea {
    public function getTea() {
        return 'oolong tea';
    }
}

public function makeTea($teaType) {
    echo $teaType->getTea() . "\n";
}

makeTea(new GreenTea());
makeTea(new OolongTea());

PHP static methods

Here’s how it could be done with classes and static functions.

class TeaTypes {
    public static function getGreenTea() {
        return 'green tea';
    }

    public static function getOolongTea() {
        return 'oolong tea';
    }
}

function makeTea($getTea) {
    echo $getTea() . "\n";
}

makeTea([TeaTypes::class, 'getGreenTea']);
makeTea([TeaTypes::class, 'getOolongTea']);

PHP namespace functions

Lastly, here’s how it could be done with just namespaces. I think this is the closest to the JavaScript version, and doesn’t require creating unnecessary classes.

namespace TeaTypes;

function getGreenTea() {
    return 'green tea';
}

function getOolongTea() {
    return 'oolong tea';
}
namespace TeaMaker;

require('./TeaTypes.php');

function makeTea($getTea) {
    echo $getTea() . "\n";
}

makeTea('\TeaTypes\getGreenTea');
makeTea('\TeaTypes\getOolongTea');

Of course, this technique might not be the best choice for some situations. If there is any shared state or expensive repeated operations between functions, then they should be in a class and the methods should not be static.

Also, passing lots of dependencies to functions can sometimes be verbose and hard to read. In these cases it can be easier to pass the dependencies as a single object instance instead.

Finally, if there are several unrelated helper functions which are used in multiple places within the methods of a class, it can be more readable to pass all the helpers to the class constructor at once as an object (as though they were related).

Still, I think that passing functions as dependency injection is an under-used technique in PHP. I know it’s not the least bit Object-Oriented, and PHP is much more of an OOP language than JavaScript. In my opinion, however, the power of OOP is shared state and polymorphism and pure functions need neither.

(The image for this post is by 童 彤 on Unsplash.)

Thoughts on Privilege

Today in my Sangha we explored the concept of Engaged Buddhism, particularly as it applies to race, gender, and class. We explored the most insidious aspect of privilege in our society: that those with privilege do not see it; we are blind to it. White people do not consider race to be a primary factor in their day-to-day affairs. Many people of color do. In fact, even the existence of the term “people of color” implies that the default race is White. Even if we “ignore race” (or any other characteristic), we are making a decision to perpetuate the discrimination that other people face constantly.

When I was young, I was bullied and insulted because I was considered a nerd. I couldn’t do a pull-up. I wasn’t interested in organized sports. I loved reading books and learning about computers. Because of these things I was considered an outcast among my peers and even many adults. My dream was always to fit in, and to that end I’ve worked my entire life to try and be one with the group, to gain the power that I felt I lacked. Of course, I didn’t see the privilege and power that I already held by the nature of my skin color, family wealth, and gender.

Since that time, nerds have become powerful. Computers and the Internet are no longer a niche in society. Their use is no longer optional. Most people in the West even carry a supercomputer in their pocket. We have achieved what might be considered an outcast’s dream: we have made ourselves indispensable to everyone. And we probably all think of ourselves as having won some great battle in the manner of the Great American Dream: with skill and talent and persistence, we were able to rise above our station and achieve that we which had been denied to us but which we richly deserved.

This, of course, is a fiction, because in most cases the only reason one is able to rise up and achieve something is when the culture allows that to happen. In my case, my whiteness and my other privileges made it possible for me to utilize the resources around me to get the things I wanted. I think the same is true for all of the technical elite of our current era. The danger is that we don’t realize what enabled us to achieve our status, instead believing it was our innate ability alone.

This incorrect view leads us to conclude that everyone has the same chance that we had. It leads us to blame those who are suffering for their own suffering. It leads to the idea that the poor are poor because they are lazy, that those convicted as criminals are evil, and that those who are in power deserve to be there.

Even within the open-source software world, the myth of the meritocracy is one example of this pervasive idea. It goes something like, “if we don’t see a person’s appearance, gender, real name, or class, and if contributions can be made by anyone freely without position or power, then surely the best ideas will rise to the top and everyone will be evaluated and judged only by their skill.”

What this concept fails to take into account is that an open-source project is a community of people, and all communities are bound by the same rules of privilege that exist in the “real world”. Contributing to a “free” project still means spending time, and it likely means spending money for a computer, special tools, and most importantly access to information. Does everyone have these resources available? Is everyone encouraged in their pursuits, supported by their families and communities?

If we treat “tech” as a meritocracy, then we might as well say that landscape painting is a meritocracy. After all, it’s just paint on canvas, and one need never see or know the identity of the person who painted a picture. But of course, amazing painters are not born, they are made through training and practice. This is not to say that different people don’t have different innate abilities, but that those abilities are only a small part of what brings about success. The rest is the often-invisible support of thousands of other people who open the doors to the skill which we think we earn.

So how do we work to change these things? How can we make a difference? If there was an easy answer to those questions, we’d all know about it already. But I believe the first step is to examine our experiences and always look for the support from others, the little forgiveness, the gifts of time and money and information; in short, to look for our privilege as it manifests. Only then, I think, can we work to dismantle the invisible architecture that separates Us from Them.

(Photo by Nicholas Green on Unsplash)