Safe alternatives to PHP Globals (Good Coding Practices)

1. Globals. Works like a charm. Globals are hated thus my thoughts of not using it.

Well, globals are not just hated. They are hated for a reason. If you didn’t run so far into the problems globals cause, fine. There is no need for you to refactor your code.

2. Define a constant in my config.php file.

This is actually just like a global, but with another name. You would spare the $ as well and to use the global at the beginning of functions. WordPress did this for their configuration, I’d say this is more bad than using global variables. It makes it much more complicated to introduce seams. Also you can not assign an object to a constant.

3. Include the config file in the function.

I’d consider this as overhead. You segmentize the codebase for not much gain. The “global” here will become the name of the file you inlcude btw..


Taken these three thoughts of you and my comments to them into account I’d say: Unless you run into actual issues with some global variables, you can stick to them. Global then work as your service locator (configuration, database). Others do much more to create the same.

If you run into problems (e.g. you probably want to develop test-driven), I suggest you start with putting one part after the other under test and then you learn how to avoid the globals.

Dependency Injection

As inside comments it became clear you’re looking for dependency injection, and if you can not edit the function parameter definition, you can – if you use objects – inject dependencies via the constructor or by using so called setter methods. In the following example code I’ll do both which is for demonstration purposes only as you might have guessed, it’s not useful to use both at once:

Let’s say the configuration array is the dependency we would like to inject. Let’s call it config and name the variable $config. As it is an array, we can type-hint it as array. first of all define the configuration in a include file maybe, you could also use parse_ini_file if you prefer the ini-file format. I think it’s even faster.

config.php:

<?php
/**
 * configuration file
 */
return array(
    'db_user' => 'root',
    'db_pass' => '',
);

That file then can just be required inside your application where-ever you want to:

$config = require('/path/to/config.php');

So it can be easily turned into an array variable somewhere in your code. Nothing spectacular so far and totally unrelated to dependency injection. Let’s see an exemplary database class which needs to have the configuration here, it needs to have the username and the password otherwise it can’t connect let’s say:

class DBLayer
{
    private $config;

    public function __construct(array $config)
    {
        $this->setConfig($config);
    }

    public function setConfig(array $config)
    {
        $this->config = $config;
    }

    public function oneICanNotChange($paramFixed1, $paramFixed2)
    {
        $user = $this->config['db_user'];
        $password = $this->config['db_pass'];
        $dsn = 'mysql:dbname=testdb;host=127.0.0.1';
        try {
            $dbh = new PDO($dsn, $user, $password);
        } catch (PDOException $e) {
            throw new DBLayerException('Connection failed: ' . $e->getMessage());
        }

        ...
}

This example is a bit rough, but it has the two examples of dependency injection. First via the constructor:

public function __construct(array $config)

This one is very common, all dependencies the class needs to do it’s work are injection at creation time. This also ensures that when any other method of that object is called, the object will be in a pre-determinable state – which is somewhat important for a system.

The second example is to have a public setter method:

public function setConfig(array $config)

This allows to add the dependency later, but some methods might need to check for things being available prior doing their job. E.g. if you could create the DBLayer object without providing configuration, the oneICanNotChange method could be called without that object having configuration and should had to deal with that (which is not shown in this example).

Service Locator

As you need to probably integrate code on the fly and you want your new code to be put under test with dependency injection and all that what’s making our live easier, you might need to put this together with your ancient / legacy code. I think that part is tough. Dependency injection on it’s own is pretty easy, but putting this together with old code is not that straight forward.

What I can suggest here is that you make one global variable that is the so called service locator. It contains a central point to fetch objects (or even arrays like your $config) from. It can be used then and the contract is that single variable name. So to remove globals we make use of a global variable. Sounds a bit counter-productive and it even is if your new code uses it too much as well. However, you need some tool to bring old and new together. So here is the most bare PHP service locator implementation I could imagine so far.

It consists of one Services object that offers all of your services, like the config from above. Because when a PHP script starts, we yet do not know if a service at all is needed (e.g. we might not run any database query, so we don’t need to instantiate the database), it offers some lazy initialization feature as well. This is done by using factory-scripts that are just PHP files that setup the service and return it.

A first example: Let’s say the function oneICanNotChange would not have been part of an object but just a simple function in the global namespace. We would not have been able to inject config dependency. This is where the Services Service Locator object comes in:

$services = new Services(array(
    'config' => '/path/to/config.php',
));

...

function oneICanNotChange($paramFixed1, $paramFixed2)
{
    global $services;
    $user = $services['config']['db_user'];
    $password = $services['config']['db_pass'];

    ...

As the example already shows, the Services object does map the string 'config' to the path of the PHP file that defines the $config array: /path/to/config.php. It uses the ArrayAccess interface than to expose that service inside the oneICanNotChange function.

I suggest the ArrayAccess interface here, because it’s well defined and it shows that we have some dynamic character here. On the other hand it allows us the lazy initialization:

class Services implements ArrayAccess
{
    private $config;
    private $services;

    public function __construct(array $config)
    {
        $this->config = $config;
    }
    ...
    public function offsetGet($name)
    {
        return @$this->services[$name] ?
            : $this->services[$name] = require($this->config[$name]);
   }
   ...
}

This exemplary stub just requires the factory scripts if it has not done so far, otherwise will return the scripts return value, like an array, an object or even a string (but not NULL which makes sense).

I hope these examples are helpful and show that not much code is needed to gain more flexibility here and punching globals out of your code. But you should be clear, that the service locator introduces global state to your code. The benefit is just, that it’s easier to de-couple this from concrete variable names and to provide a bit more flexibility. Maybe you’re able to divide the objects you use in your code into certain groups, of which only some need to become available via the service-locator and you can keep the code small that depends on the locator.

Leave a Comment