The power of static in PHP

#php

Although most have probably seen the static keyword used in PHP before, have you ever wondered how many ways it can be used? Or possibly how many ways these different uses can provide value to your code? Let's dive into uses and examples and find out.

Method signature

Arguably the most common usage of the static keyword is the static method. While static methods can be referred to using the object operator (->) it is recommended to use the scope resolution operator (::) as the alternative is deprecated and may be removed in the future. The scope resolution operator allows you to call static methods directly on the class rather than an instance of the class. This also results in the $this keyword being unavailable in the body of static methods.

Static methods can be used to implement the Factory Method Pattern which acts as a factory for producing new instances of the containing class each time the method is called.

In this example we have created a factory method fromArray which instantiates a User object, assigns the instance values from the array and returns the instance.

class User
{
public static function fromArray($attributes)
{
$user = new User();
$user->name = $attributes['first'] . ' ' . $attributes['last'];
$user->password = password_hash($attributes['password'], PASSWORD_BCRYPT);
 
return $user;
}
}
 
$user = User::fromArray([
'first' => 'ryan',
'last' => 'cco',
'password' => 'password'
]);

Alternatively, this logic can be extracted to a standalone class which is also known as the Static Factory Pattern.

class UserFactory
{
public static function build($attributes)
{
//
}
}
 
$user = UserFactory::build($attributes);

Properties

Unlike regular properties, changing the value of a static property during the execution of your program will affect all instances of the containing class. Even those which have yet to be instantiated. In this way, static properties can be thought of as "mutable class constants". Static properties are only able to be referenced using the scope resolution operator.

Due to the nature of static properties, they can be used to implement the Singleton Pattern. The Singleton Pattern maintains a single instance of a given class throughout the execution of your program.

In this example, the initial call to Queue::getInstance() will create and assign an instance of Queue to Queue::$instance and return it. Every subsequent call will return the same instance of Queue previously assigned to Queue::$instance.

class Queue
{
private static $instance;
 
public static function getInstance()
{
if (static::$instance === null) {
static::$instance = new Queue();
}
 
return static::$instance;
}
}

Variables

When in context of a function, static variables maintain their value even once the program has moved out of scope of the containing function. When in the context of a class method, static variables have additional behavior similar to static properties in that changes to their values reflect across all instances of the containing class. Although similar in behavior to static properties, static variables are only accessible within a function or method body.

Static variables are often used as part of an optimization technique known as Memoization. Memoization aims to speed up an otherwise expensive operation by caching the results and saving them for a later call with the same parameters.

In this example, we are creating a hash which is unique to the parameters provided and use it to uniquely identify the call as $key. If the value of $key is not found as an index on $cache, we perform the preg_replace and store its output on the $key index of $cache. Every subsequent call to replace with the same parameters will bypass the call to preg_replace and return the value from a previous call.

function replace($pattern, $replacement, $subject)
{
static $cache = [];
 
$key = md5(serialize(func_get_args()));
 
if (! isset($cache[$key])) {
$cache[$key] = preg_replace(
$pattern, $replacement, $subject
);
}
 
return $cache[$key];
}

Anonymous functions

Like methods, when an anonymous function is defined in the context of a class they are not bound to the containing class and do not have the $this keyword available.

Static anonymous functions do not necessarily have any unique uses over regular anonymous functions. It is worth noting that in context of a class, static anonymous functions yield micro performance improvements and may be suggested in any instances which you do not need the containing class to be bound to the anonymous function.

class PostsCollectionFilter
{
public function unpublished($posts)
{
return $posts->filter(static function ($post) {
return ! $post->published;
});
}
}

Late Static Binding (LSB)

Late static binding demonstrates another usage of the static keyword: in the context of inheritance. In this context static refers to the class being called rather than that which the method was defined (which would be referred to with self or __CLASS__).

class A
{
public function saySelfValue()
{
echo self::class;
}
 
public function sayClassValue()
{
echo __CLASS__;
}
 
public function sayStaticValue()
{
echo static::class;
}
}
 
class B extends A
{
 
}
 
$a = new A();
$a->saySelfValue(); // 'A'
$a->sayStaticValue(); // 'A'
$a->sayClassValue(); // 'A'
 
$b = new B();
$b->saySelfValue(); // 'A'
$b->sayStaticValue(); // 'B'
$b->sayClassValue(); // 'A'

Closing

We've covered a few examples, some more contrived than others, of the different uses of the static keyword in PHP. Although contrived, the use cases are all very real and the value that they can deliver to your code can be hugely impactful. At the very least, familiarizing yourself with these uses and techniques to have available in your toolbox will make you that much stronger of a developer.

If you have some more real-world examples, possibly from open source projects, that could provide insights for other readers please share links in the comments!

Syntax highlighting provided by Torchlight.