Want to learn object-oriented programmming? Get my free course

Using the static factory method pattern with WordPress

If you use object-oriented programming, there’s a good chance that you’re familiar with the constructor. It’s this special method that an object-oriented programming language uses to initialize a new object. In PHP (and a lot of other object-oriented programming languages), the __construct method is a special method reserved for the role of constructor.

The role of the constructor isn’t always well understood. This is especially true when you’re new to object-oriented programming. You know the method exists, but you’re not too sure how to use it.

This can lead to some less than ideal practices around constructors. This is especially true in the WordPress world where two such practices are popular. First, there’s the habit of putting hooks in the constructor. And, because of that habit, WordPress developers tend to overuse the singleton pattern.

These two practices show a misunderstanding of the role that a constructor plays inside a class. This isn’t how object-oriented programming wants you to use constructors. There are other ways to solve those problems without sacrificing the role of a constructor.

Now, this isn’t to say that constructors don’t have any problems either. They do! In fact, that’s why we’re looking at the static factory method pattern. It solves one common problem that constructors have in PHP.

The problem with constructors

Alright, so what’s this problem that constructors have in PHP? Well, they have a few, but they all originate from a single larger problem. It’s that you can only have one constructor per class in PHP.

What goes on outside the PHP world

In other programming languages, you can overload a class method to solve this issue. If you’re not familiar with overloading, it’s the ability to create more than one method with the same name. You can do that by defining a method multiple times, but with different parameters like this:

class OverloadingExample
{
    public void display(char c)
    {
         System.out.println(c);
    }
    public void display(char c, int num)  
    {
         System.out.println(c + " " + num);
    }
}

This is a small example in Java. You can see that there are two display methods. But each display method uses different parameters. One is just a char and the other is a char and an int.

You can also overload constructors in the same way. We call this constructor overloading. It looks pretty much the same overloading normal method:

public class TimeOfDay {
    public int hour;
    public int minute;

    public TimeOfDay(int h, int m) {
        hour   = h;
        minute = m;
    }

    public TimeOfDay(int h) {
        this(h, 0);
    }
}

Constructors in Java don’t use the __construct method name. Instead, you use the name of the class which is TimeOfDay here. (PHP used to allow you to do that as well.) Like our overloaded methods, each constructor has its own unique set of parameters.

Meanwhile in the PHP world

It wouldn’t be fair to say that you can’t overload functions or methods in PHP. The issue is that it’s not built into the language like we saw with Java. You have to be more creative about it.

class MyPlugin_SomeClass
{
    // ...
}

$some_class = new MyPlugin_SomeClass();
$some_class->do_something($argument1);
$some_class->do_something($argument2, $argument3);

As you can see in the example above, we have a small class called MyPlugin_SomeClass. (Great name, I know!) We left it empty for now. But below the class, we added three more lines of code.

The first one initializes the MyPlugin_SomeClass class. The other two lines of code call the do_something method. The first one calls it with a single argument while the second calls it with two.

Now, we need to create the do_something method. And we need to overload it to support the two different calls that we have. (We could also use a default value, but let’s imagine that we can’t here!) We have two options available to us to do that.

Magic method

The first option is to use the __call magic method. This magic method handles all calls to object methods that don’t exist. This might sound a bit confusing so let’s look at our small example modified to use the __call magic method.

class MyPlugin_SomeClass
{
    function __call($name, $arguments)
    {
        if ('do_something' == $name && 1 == count($arguments)) {
            // ...
        } elseif ('do_something' == $name && 2 == count($arguments)) {
            // ...
        }
    }
}

$some_class = new MyPlugin_SomeClass();
$some_class->do_something($argument1);
$some_class->do_something($argument1, $argument2);

As you might have noticed, the do_something method doesn’t exist inside our MyPlugin_SomeClass class. Instead, both method calls will go to the __call magic method.

The __call magic method has two arguments: name and arguments. name is the name of the called method that doesn’t exist. Meanwhile, arguments is an array containing all the arguments passed to that non-existent method.

In the __call magic method, we can check how many arguments the method received and adapt ourselves to it. We do this by using a conditional statement to check the name of the method. First, we always check if the name is do_something. Then, once we know the call is to the do_something method, we check the number of arguments.

We do that by using the count on the arguments parameter. If count returns 1, we do one thing. Meanwhile, if count returns 2, we do something else.

Variadic method

The other option is to turn our do_something method into a variadic method. A variadic method (or function) is a function or method that accepts an unknown number of arguments. PHP has two different methods for creating variadic functions and/or methods.

The first method is to use special PHP functions created to support variadic functions or methods. These are the func_get_arg, func_get_args and func_num_args functions. That said, it’s only worth remembering the func_get_args function. It’s the function that you’ll use most of the time.

class MyPlugin_SomeClass
{
    public function do_something()
    {
        $arguments = func_get_args();

        if (1 == count($arguments)) {
            // ...
        } elseif (2 == count($arguments)) {
            // ...
        }
    }
}

$some_class = new MyPlugin_SomeClass();
$some_class->do_something($argument1);
$some_class->do_something($argument2, $argument3);

Here’s another look at our MyPlugin_SomeClass class. We removed the __call method from earlier. And, instead of it, we have the do_something method that we coded as a variadic method.

This method looks a lot like our __call method from earlier with a few noteworthy changes. The first one is that the do_something method doesn’t have any parameters. Instead, it relies on the func_get_args function to get the arguments passed to it

We store the array of arguments returned by the func_get_args function in the arguments variable. We then use it in a similar conditional as earlier example with the __call method. We just don’t need name check anymore since we’re not using the __call method.

class MyPlugin_SomeClass
{
    public function do_something(...$arguments)
    {
        if (1 == count($arguments)) {
            // ...
        } elseif (2 == count($arguments)) {
            // ...
        }
    }
}

$some_class = new MyPlugin_SomeClass();
$some_class->do_something($argument1);
$some_class->do_something($argument2, $argument3);

If you’re using PHP 5.6 or later, there’s also the new ... token that you can see in the example above. You use it in function or method definition to say that it accepts an unknown number of arguments. It replaces the use of the func_get_args function that we used before.

Neither options work well with constructors

This brings us to the problems with both these options. The first problem is that the first option doesn’t even work with constructors! How come? Well, let’s imagine that you had a MyPlugin_SomeClass class that looked like this:

class MyPlugin_SomeClass
{
    function __call($name, $arguments)
    {
        if ('__construct' == $name && 1 == count($arguments)) {
            // ...
        }
    }
}

$some_class = new MyPlugin_SomeClass($argument1);

The MyPlugin_SomeClass above uses the __call magic method that we saw earlier. You’d think that since the MyPlugin_SomeClass class doesn’t have a __construct method that any call to it should go to the __call method. But that’s not what happens. The __call method won’t get called when you create a new object.

The issue with variadic functions or methods

So that rules out our first option, but what about the second? Well, the issue with a variadic constructor isn’t that it doesn’t work! (That would’ve been one crazy plot twist!) No, the issue with a variadic constructor is different from the one with the __call method

The issue with overloading a constructor using a variadic method is readability. (This is a problem with variadic functions/methods in general.) If a method accepts an unknown number of arguments, how can you know what the method accepts? You can do it with documentation, but that can also get confusing quite fast.

class MyPlugin_SomeClass
{
    public function __construct()
    {
        $arguments = func_get_args();

        if (1 == count($arguments)) {
            // ...
        } elseif (2 == count($arguments)) {
            // ...
        }
    }
}

Here’s our MyPlugin_SomeClass with a variadic constructor. It doesn’t look any different from the variadic do_something method from earlier. That said, it’s still possible to see the issue with readability.

Here are some examples questions that are hard to answer with our __construct method:

  • How many arguments can you pass?
  • What are the types of arguments accepted?
  • Does the order of the arguments matter?

In normal circumstances, a developer can answer all these questions in an instant. They can just go look at the definition of the function or method to see what it expects. It’s a painless exercise.

But when you make a function or method variadic, you obscure this information. You make others work harder to figure things out. They have to go in your function or method and read the code to see how it works and what it expects.

Of course, a good use of PHPDoc can answer a lot of these questions. But it can also make the PHPDoc heavy and complicated. It’s far from an ideal solution to our readability problem.

Why do we even care about constructor overloading?

Ok, so we’ve talked a lot about constructor overloading and how PHP doesn’t support it that well. But why should you care? Why is constructor overloading useful?

Constructor overloading is useful because it lets us have more than one way of creating an object. If you only have one constructor, you have to make it fit every possible scenario. This isn’t always ideal depending on what our class does.

Static factory method pattern

This is where the static factory method pattern can come in and help us out. Now, there’s a good chance that you’ve never heard of the static factory method pattern before. It’s not part of the popular design patterns that you see everywhere. It also gets confused with the factory method pattern a lot.

But don’t let this lack of popularity fool you! It’s a useful pattern to know about. So what does the static factory method pattern do and how does it work?

Well, the idea behind the static factory method pattern is quite simple. It’s a static method that returns an instance of the class. The static factory method behaves the exact same way as a constructor except that you don’t use the new keyword.

With the static factory method pattern, we can create as many “faux” constructors as we want. This lets us circumvent the one constructor limit that PHP gives us. And, without this limit, we’re free to rethink how to approach instantiating a new object.

A static factory method example

The best way to wrap our heads around all this is with an example! So let’s look at one! It’ll help you see how you can rethink how you use constructors when you use the static factory method pattern.

Managing products

Let’s imagine that we have a plugin that manages products. To represent these products, we created the MyPlugin_Product class. Here’s a partial look at it:

class MyPlugin_Product
{
    /**
     * The Product's ID. Not the WordPress post ID.
     *
     * @var string
     */
    private $id;

    /**
     * The name of the product.
     *
     * @var string
     */
    private $name;

    /**
     * The type of the product.
     *
     * @var string
     */
    private $type;

    /**
     * Constructor.
     *
     * @param string $id
     * @param string $name
     * @param string $type
     */
    public function __construct($id, $name, $type)
    {
        $this->id = $id;
        $this->name = $name;
        $this->type = $type;
    }

    // ...
}

The code above shows part of the MyPlugin_Product class. We have the three internal variables: id, name and type. Their names are pretty self-explanatory so we won’t go over them.

There’s also a constructor which has three mandatory parameters. These mandatory three parameters mirror the three internal variables of our class. And all that the constructor does is assign these arguments to those internal variables.

Creating an object from different data sources

Now, our plugin stores these products inside the WordPress database using a custom post type. That said, it’s not the only location where you can find the details about these products. They also reside on another service that we can access with an API.

This means that we have two data sources for these products: the WordPress database and the API. These two data sources also have different ways to represent these products. The WordPress database returns a WP_Post object by default.

Meanwhile, the API information returns a JSON object which we can convert using the json_decode function. By default, the json_decode function will convert our JSON object into an stdClass object. But you can also tell it to convert the JSON object into an array instead.

Different ways to store data

It doesn’t really matter which of the two you want to use. The important thing is that the two data sources don’t store and format the data the same way. Let’s imagine that you request information on a product from the API. The API returns this JSON object to you:

{
    "id": "42",
    "name": "My awesome book!",
    "type": "book",
    // ...
}

As you can see, our JSON object is pretty simple and straightforward. Each JSON object variable has a name that represents the data it stores. id for the product ID, name for the product name and type for the product type.

But things won’t be the same once we store this product in the WordPress database. We have to store this information as post metadata. We do this by using custom fields which is a key-value pair.

The problem with custom fields is that any plugins can add them to a post. This can lead to a situation where plugins could overwrite our metadata if we’re not careful. This is especially problematic if our keys are too generic which is the case with id and name.

To prevent this issue, it’s always better to prefix all the keys of our custom fields. This means that we can’t use the variable names from the JSON object as our keys. So, for example, instead of using id as our custom field key, we should use myplugin_product_id. These are keys that are unlikely to conflict with ones used by other plugins.

Creating our static factory methods

Now, that we’ve seen why we need static factory methods with our MyPlugin_Product class, we can go ahead and build them. In total, we’re going to need to create two static methods. One for creating a product from API data and another to create a product using data from the WordPress database.

Creating a product from API data

Let’s start with creating a product from API data! We saw earlier that the API would return a JSON object. We just need to pass that object to our static factory method.

class MyPlugin_Product
{
    // ...

    /**
     * Creates a new product from API data.
     *
     * @param mixed $object
     *
     * @return MyPlugin_Product|null
     */
    public static function from_api($object)
    {
        // ...
    }

    // ...
}

We’re going to name our static factory method from_api. This leads to a method call that looks like this: MyPlugin_Product::from_api(). This makes it easy for someone reading your code to understand what your method is doing. It’s constructing our object from API data.

The other element to take in consideration is that we don’t know the format of our JSON object. You can represent a JSON object in three different ways: a string, an array or a stdClass object. We’re going to try to deal with all three scenarios.

class MyPlugin_Product
{
    // ...

    /**
     * Creates a new product from API data.
     *
     * @param mixed $object
     *
     * @return MyPlugin_Product|null
     */
    public static function from_api($object)
    {
        if (is_string($object)) {
            $object = json_decode($object);
        }

        if (is_array($object) && isset($object['id'], $object['name'], $object['type'])) {
            return new self($object['id'], $object['name'], $object['type']);
        } elseif ($object instanceof stdClass && isset($object->id, $object->name, $object->type)) {
            return new self($object->id, $object->name, $object->type);
        }
    }

    // ...
}

Our from_api static factory method makes heavy use of conditionals to deal with these different scenarios. We start with a guard clause to check if the given object argument is a string using the is_string function. If we have a string, we pass it to the json_decode function to convert it into an object.

At this point, we know that we can’t have a string anymore. We need to deal with the other two scenarios where object is either a stdClass object or an array. This is what the last set of guard clauses does.

Both conditions in the guard clauses follow a similar pattern. They both start by checking the type of the object variable. We use the is_array function to check if object is an array. And we use the instanceof operator to check if object is a stdClass object.

Once we know the type of the object variable, we can check if it contains the necessary data. We do that using the isset function. We pass it all the values that we want to pass to our constructor.

For our call to the constructor, we use the self keyword. It acts as a shortcut to our class name. It’s equivalent to writing new MyPlugin_Product.

It’s also worth noting that the from_api static factory method can also return null. This will happen if object isn’t a valid JSON object, array or stdClass object. This is a preventive measure so that we don’t get errors because some information is missing.

Note on the isset function

Now, there’s a good chance that you never saw the isset function used the way we’re using it here. Most of us pass it one argument and nothing more. But isset can accept as many arguments as you want!

When you use isset with multiple arguments, it’ll only return true if all the arguments are set. This means that isset will only return true if we have an id, name and type in our object or array. This lets us pass those values to our constructor without having to worry whether those values exist or not.

Creating a product from a post object

Next, we want to look at our other static factory method. We need it to create a MyPlugin_Product object from a WP_Post object. This code will be a lot like the one from the from_api static factory method.

class MyPlugin_Product
{
    // ...

    /**
     * Creates a new product from a post object.
     *
     * @param WP_Post $post
     *
     * @return MyPlugin_Product|null
     */
    public static function from_post(WP_Post $post)
    {
        if (!isset($post->myplugin_product_id, $post->myplugin_product_name, $post->myplugin_product_type)) {
            return;
        }

        return new self($post->myplugin_product_id, $post->myplugin_product_name, $post->myplugin_product_type);
    }

    // ...
}

So here’s our static factory method for WP_Post objects. We called it from_post. The reasoning for the name is the same as the from_api static factory method. It makes it clear that we use this static factory method to create a MyPlugin_Product object from a post.

The from_post static factory method starts with a guard clause. The guard clause uses the isset function to check if our WP_Post object has the required post metadata. We need values for myplugin_product_id, myplugin_product_name and myplugin_product_type.

If we’re missing any of those values, the from_post static factory method returns nothing. (This is the same as returning null.) Otherwise, it returns a new MyPlugin_Product object using the post metadata.

Should you make your constructor private?

This wraps up the theory and the example of static factory methods. You might be wondering what the role of the constructor is at this point. Should it even be accessible outside the class?

This is a good question! You could change the visibility of the constructor from public to private. This would force everyone to use your static factory methods instead of the constructor.

This might seem like we’re just implementing the singleton pattern by doing that, but we’re not. There’s a crucial difference between making a constructor private here and doing it with the singleton pattern. In this case, we’re not preventing anyone from creating new MyPlugin_Product objects. We’re just preventing them from doing it the standard way using the new keyword.

A powerful way to use the static keyword

The static keyword is an easy concept to understand in object-oriented programming. But, as we’ve seen before, it’s also easy to abuse it. Its ease-of-use masks the difficulty in using it for the right type of problems.

But the static factory method pattern is a great example of how to use the static keyword! And not only that, it’s also a great tool to have under your belt. It offers an elegant way to let you create new objects based on different contexts.

Photo Credit: Ant Rozetsky

Creative Commons License