5 usages of static keyword in PHP

5 usages of static keyword in PHP

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 from global that is restricted to one function. Spot those, and make them static or turn the whole code into a class.
  • static as a classname : whenever the current class is mentioned within itself, think about using self or static for added comfort.