Lazy Loading in PHP Object Composition

When it comes to nicely performing PHP scripts (yes in PHP these are all scripts as PHP code is run-time) there is a nice addition since PHP 7 named the Null coalescing operator which plays very well with the basic nature that PHP is loosely typed and unset variables are basically null when warnings are not in effect. You know what? Not set warnings (like with isset) are not in effect with the  ?? Null Coalescing Operator (PHP Manual).

So how about a simple and quick usage example for lazy-loading? By default all class members are null when defined:

class MyFoo
{
  /**
   * @var Config
   */
  private $config;
}

With any new MyFoo() that private property will be null. Now one thing could be to properly inject the Config in the constructor (__construct()) but while you’re writing code you might want to defer the details to later (dependency injection is not always useful but don’t get me wrong it’s generally the option to go on with constructor injection while you progress) one way to deal with the outcome is lazy loading (back to constructor injection, you might want to inject a ConfigFactory then).

So what is about lazy loading here? Let’s say MyFoo is used more centrally in an application (a primitive)  so might be some kind of service to your application, you only want to instantiate the Config in case it is actually used. You know that it is used when it is acquired from the service-like-acting MyFoo when the getter is called (mind the Law od Demeter and Getters and Setters can be a smell, too):

class MyFoo
{
    ...
    public function getConfig(): Config {
        return $this->config;
    }
}

Now when that getConfig() method is called, it will return null unless the Config has been set to private MyFoo::$config so far – which is not a case in our scenario. Also the Config of MyFoo is a singleton (not the (anti-) pattern) , so it is easy to implement it on the go:

class MyFoo
{
    ...

    public function getConfig(): Config {
        return $this->config ?? $this->config = new Config();
    }
}

Creating the Config object is here deferred to the point when getConfig() is called the first time. That is also the first time it is needed (by definition of this simplified example at least). The Null Coalescing Operator is helpful here to do this in a single line.

It is also easy to switch to constructor injection (eager loading) or even constructor injection based lazy loading when you inject a factory that will create (or a repository that providea) the Config at that time in place.

I hope this is a nice example to show how well the Null Coalescing Operator in PHP plays with non-initialized object properties (or even unset variables). Which reminds me I should not use it too often.

In the next PHP version (7.2) this can be shortened even more btw (see the PHP RFC: Null Coalescing Assignment Operator):

class MyFoo
{
    ...

    public function getConfig(): Config {
        return $this->config ??= new Config();
    }
}

The only thing missed for ?? addicts like me might be the sometimes unnecessary operand after the operator:

    $var = $unset ??; # expressing just null

This will spare isset() if conditionals but might also direct dealing with nulls to other places (which can add a lot of burden to consumers). But I’m just too little experienced in writing PHP wiki RFCs and I couldn’t even provide a patch, so with closing time for PHP 7.2 this is really future material (and perhaps just a sign I want “wrong” things).

/Edit: An RFC exists already: PHP RFC: Unary null coalescing operator


Read On:

This entry was posted in Hakre's Tips, PHP Development, PHP Development, Pressed, The Know Your Language Department, Tools and tagged , . Bookmark the permalink.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.