What is a null object, and when are they useful?

Tags:

If you’ve written code, you’ve probably used the value null to indicate some variable is not set. This is perfectly good, but did you know there’s more to nulls than just the value null?

There is also a null object, which doesn’t really have anything to do with the value null, but its purprose is similar.

How many times have you written code, which checks if a value is null, and then displays something special because of that? Have you written the very same check in more than one place in your code? A null object is an elegant solution to this.

Let’s check out what exactly is a null object, and when it becomes a valuable pattern.

What is a null object?

Contrary to what it may sound like, a null object is not simply a variable such as Object myVar = null – it’s an actual object instance, but it represents an “empty” value.

What an empty or null value means depends much on the context. For example, if you think of a website which allows users to register accounts, an empty value could be an anonymous user without an account. In a case like this, you could have a null user object, which represents a user who has not logged in.

Implementing a null object

Implementing null objects is quite simple. The typical approach is to have it extend the class, which you want to use it as an empty value for. This allows for polymorphism, so you can use the null object without any special cases.

Consider the user registration system mentioned earlier; In it, we could have a User class such as this:

class User {
  private $_name;
 
  public function __construct($name) {
    $this->_name = $name;
  }
 
  public function getName() {
    return $this->_name;
  }
}

Now, say we want to represent anonymous users with a user object. We’ll create an AnonymousUser object, which is a null object:

class AnonymousUser extends User {
  public function __construct() { }
 
  public function getName() {
    return 'Anonymous user';
  }
}

The name null object may be a bit misleading – the AnonymousUser object is very much an object and not “null”. However, when we define the user by default as AnonymousUser, instead of the value null, it represents the same thing.

But why are null objects beneficial to my application?

To figure out why a null object is useful, we need to consider some special cases that are typical in applications.

Again, continuing with the user example, let’s say we want to display the user’s name somewhere on the site.

In a typical case, you would have something such as this:

<span>Hello, <strong><?php echo $user->getName(); ?></strong></span>

Now, what if the $user object would be null when the user is not logged in? We get the following rather messy code:

<span>Hello, 
  <strong>
    <?php if($user == null): ?>
      Anonymous user
    <?php else: ?>
      <?php echo $user->getName(); ?>
    <?php endif; ?>
  </strong>
</span>

As you can see, the markup got a lot more complex. You could probably simplify it by using the ternary operator, but it would still be a bit tricky to read.

Now, let’s say $user is an AnonymousUser object when not logged in. We get the following code:

<span>Hello, <strong><?php echo $user->getName(); ?></strong></span>

Oh wait, isn’t this the code we had in the first place? Yes! With a null object, we get all the benefits of polymorphism, and we won’t need to use if-elses to work with special cases such as this.

Another benefit of this approach is that it simplifies if-elses when we actually need them. Sometimes we just can’t avoid it. For example, if we want to display a login form, we do need to know if the user is logged in or not:

<?php if($user instanceof AnonymousUser): ?>
Please log in
<?php endif; ?>

Last, but not least, having a null object improves understandability. If you think about it, does $user = null; actually convey a meaning? How do we know what null represents?

When we say $user = new AnonymousUser();, it’s immediately quite obvious that the variable now represents an anonymous user.

Conclusion

The null object pattern is very useful in many contexts. In addition to the other benefits, it also helps reduce clutter in switch-case statements.

A good pattern to combine with the null object can be the factory or builder pattern. They allow you to abstract the process of building the object, and it can be a good thing if the consumer of the object doesn’t need to know the specifics – such as if the object is a null object or not.

However, as with all patterns, remember to think of your specific case before implementing – otherwise you may wind up having patternitis!