01 · THE IDEAREAD → TRY → LEARN
Why static members exist
Most class members belong to an object. A normal method can read $this, so its result may depend on that object's properties. A static member belongs to the class itself. You can reach it with the scope resolution operator :: without creating an object first.
That makes static methods a good fit for small helpers that only need their arguments, such as converting units, formatting a label, or classifying a number. Class constants fit alongside them. They give a name to a fixed value that the class owns, so you avoid scattering magic numbers through your code.
A first static method and constant
A static method is declared with the static keyword. Because no object is involved, $this does not exist inside it. Inside the class, use self::NAME to read a constant. From outside, write ClassName::NAME.
class Temperature
{
public const FREEZING_C = 0;
public static function toFahrenheit(float $celsius): float
{
return $celsius * 9 / 5 + 32;
}
}
echo Temperature::toFahrenheit(100), "\n";
echo Temperature::toFahrenheit(Temperature::FREEZING_C), "\n";212 32
The method does not remember anything between calls. Given the same input, it returns the same output. That predictability is what you want from a helper.
Static methods as callables
Static methods work well with functions that accept callbacks. The first-class callable syntax Label::wrap(...) turns a static method into a closure without writing a string or an array callable by hand.
final class Label
{
public static function wrap(string $text): string
{
return '[' . $text . ']';
}
}
$wrapped = array_map(Label::wrap(...), ['a', 'b']);
echo json_encode($wrapped, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";["[a]","[b]"]
Because wrap() depends only on its argument, you can reuse it anywhere and test it with a handful of inputs.
The hazard: persistent mutable statics
A static property is shared by the whole program for the life of the request. If a static method changes it, every later call can behave differently. The result depends on hidden history.
class Counter
{
public static int $calls = 0;
public static function next(): int
{
self::$calls++;
return self::$calls;
}
}
echo Counter::next(), "\n";
echo Counter::next(), "\n";1 2
The same call Counter::next() gave two different answers. This is effectively a global variable with a class name. Tests that call it can pass or fail depending on what ran earlier. Code in unrelated places can also change the value without you noticing.
A safer design passes state in and returns new state out. A method such as next(int $current): int would be stateless, and the caller owns the value. Reserve static properties for rare cases, such as caches that cannot change observable results.
Rules of thumb
- Use a static method when the work needs only its parameters and constants.
- Use an instance method when behavior depends on object state.
- Use
self::CONSTANTfor values the class owns, and give each one a meaningful name. - Do not call
$thisin a static method. It is not available. - Calling a non-static method statically throws an
Errorin PHP 8. - Keep static methods deterministic. Avoid reading clocks, randomness or hidden static properties.
- Remember that
self::refers to the class where the code was written, whilestatic::is for late static binding. That is a separate topic you will meet with inheritance.
Worked plan for the exercise
You will build a small ScoreGrader class. It holds three threshold constants and one static method, grade(int $score): string. Then you will write a plain function, gradeScores(array $scores): array, that maps each score to a letter in the original order.
- Check the highest threshold first: a score at or above
A_MINisA. - Check
B_MIN, thenC_MIN, in descending order. - Return
Fwhen no threshold matches. - Pay attention to the boundaries. A score of exactly 90 must be an
A, so use>=rather than>. - Loop over the input and call
ScoreGrader::grade()for each value. An empty array should give an empty array.
No static property is needed, so the helper stays stateless and every call is independent.
Recap
Static methods and class constants let a class offer helpers without an object. They shine when they are stateless, deterministic and named well. Avoid persistent mutable static properties, because they create hidden shared state that makes code harder to reason about and test.
Functions · Arrays · Types
- Write stateless static helpers; avoid persistent mutable statics
- Implement and test a deterministic PHP 8.4 function