5 usages of static keyword in PHP
Static is a PHP keyword with many usages. It is almost universally used, though there are many variations of it. Let’s review all the five of them :
- static method
- static property
- static closure
- static variable
- static as a classname
Static method
The most common usage of static is for defining static methods.
Such methods are part of a class, just like any method, though they may be used even without any such instantiated object. This is actually the main difference with a normal method : $this
is not available in such methods.
<?php class Foo { public static function aStaticMethod() { $var = 'this'; var_dump($$var); } public function aNonStaticMethod() { var_dump($this); } } Foo::aStaticMethod(); $object = new foo(); $object-> aNonStaticMethod(); ?>
Note that static methods may be called from an object, though the pseudo-variable $this
will still NOT be available. In fact, PHP emits a fatal error, whenever the $this
variable is directly mentioned in a static method : this is why the example has to use the variable variable to actually show the status.
Since static methods do not depends on an object, they are great for factories. They are also useful to access the private static properties, since both of them are static. Finally, they are also useful for utils that are related to a class but not depend on local object state : however, those may be considered as a function.
Static properties
Static properties are the close cousin of static methods. They do not depend on the object, but only on the class itself. They may hold some important information for the class, but not for the objects.
Static properties have several niche usages. The first of them is being a property for a static method. That makes sense : anything a static method has to store must be in a static property. Actually, a private one, or a protected.
They play the role of constants when the value of the constant is dynamically loaded, and thus, are not known at compile time. Non-class constants may be defined at execution time with define
, but not class constants : thus, the usage of static properties. They also replace constants when the constant has to be a resource or an array or another object.
They are used when implementing a singleton, when the object instantiation has a prerequisite, or to share data between objects, such as a counter. They may also be used for local cache.
<?php class Foo { private $total = 0; private $count = 0; // getter for current count public static function getCount() { return self::$count; } // increment count and total public function __construct() { ++self::$total; ++self::$count; } // decrement count public function __destruct() { --self::$count; } } ?>
Static properties tend to be difficult to initialize : all properties may be initialized at coding time (default value), or construct time. Obviously, the latter is not available for static property, and only the default value is possible. The other option is to set the static property in the main code, at bootstrap, leading to some difficult to solve dependencies.
static closure
While methods may be static or not, function has no such alternative : they just can’t be static. Yet, there is one final type of method that may be static : static closures.
Closure are functions that may be stored in a variable : functions may have their name stored in a variable, though. Closure also have the ability to aggregate variables from the context of their creation, for future use. As such, $this
is available in a closure that is created inside an object.
<?php class x { private $y = 1; function foo() { return function() { var_dump($this); }; } } $object = new x; $f = $object->foo(); $f(); /* object(x)#1 (1) { ["y":"x":private]=> int(1) } */ ?>
Note that there is no need for ‘use ($this)’ when creating the closure to include $this
in it : it is automatically done.
Now, if the foo
method is actually static, then $this
is not available anymore, nor for the static method, nor for the created closure.
But if you don’t want to propagate the context of creation with the closure, you may actually make the closure static
and $this
won’t be available anymore. This may avoid leaks, or will allow the $this
variable to be filled by another context later.
<?php class x { private $y = 1; function foo() { return static function() { var_dump($this); }; } } $object = new x; $f = $object->foo(); $f(); /* Fatal error: Uncaught Error: Using $this when not in object */ ?>
Static variables
Just like there are static methods and static functions, there are both static properties AND static variables.
Static variables are variables that stay within a context, and are available next call.
<?php function foo() { static $i = 0; echo $i++; } foo(); foo(); foo(); foo(); // 0123 ?>
This actually works like some prehistoric class : the static variable is available to store some cached data : here, we have used it as counter, but static variables makes great cache for any dictionary that shouldn’t be loaded each call. Load the dictionary at the first call, then it will reside in memory for the rest of the execuction.
Note that the variable is completely invisible from the outside world, just like a private property.
Usually, static variables are a first step before making this function a full class : once you understand that testing such unaccessible variable requires some ‘reset’ mechanism, its prehistoric charm wans and the function is refactored as a class.
static as a classname
It is not possible to call a class static
but it is well possible to refer to it with this keyword. Within a class body, you may refer to the current class, or any of its parent in case of fallback, using static
. That is convenient in a surprising number of situations.
<?php // This code makes no sense : it is just for illustration. class x { static $p = 1; // for typehinting, static is not possible but self is function foo(self $x) { // for instantiation $o = new static( ); // for calling oneself statically static::$x = static::foo(); // for instanceof return $o instanceof static; } } ?>
When using static in those situations, static
will be dynamically replaced by the current acting class. In the example, it is the x class. When you change the name of the class from x to something else, the rest of the class keeps running : static
acts as a relative class name (relative to the code location, that is).
There is another keyword in competition with static
: it’s self
. Together, they handle the Late Static Bindings.
Basically, self
may just be used at the same location, and it will behave almost identically. Except that self
is resolved at compile type, ‘statically’ if you pardon the pun, and it will always reference the class it is written in. While static
depends on who is calling the static entity.
Confused ?
<?php // This code makes no sense : it is just for illustration. class x { const NAME = 'X'; static function whoAmI() { print static::NAME.PHP_EOL; print self::NAME.PHP_EOL; } } class y extends x { const NAME = 'Y'; } // calling as X x::whoami(); // display X X // calling as Y y::whoami(); // display Y X ?>
On the first call to whoami(), the context of calling is X, so the method displays X X
. On the second call to whoami(), Y is used, but whoami is actually located in X, as Y has no such method. There, static
and self
parts ways, and display different classes.
In terms of performances, always default to self
, as it will be compiled, and executed as such. static
is far rarely used.
Review your code with static analysis
Static analysis has no relation with the static
keyword. Yet, it may very wel help you review your code, and find usage of those features.
- static method : avoid using
$this
in those methods, and consider adding static to methods that doesn’t use this variable. - static property : make
static
private
, when the property is only used internally. - static closure : add
static
when the closure has no usage of the$this
. - static variable : when the
static
variable is not taught, it is often build fromglobal
that is restricted to one function. Spot those, and make themstatic
or turn the whole code into a class. - static as a classname : whenever the current class is mentioned within itself, think about using
self
orstatic
for added comfort.
Pingback: Exakat Blog: 5 usages of static keyword in PHP - webdev.am