PHP 8.0: static return type for class methods

Version8.0
TypeNew Feature

PHP 8.0 allows static as a return type for class methods.

class Foo {
    public static function getInstance(): static {
        return new static();
    }
}

PHP class methods can return self and parent in previous versions, but static was not allowed in PHP versions prior to 8.0. The newly allowed static return type allows to narrow down the return type to the called class.

The static return type helps classes with fluent methods (i.e the ones with return $this), immutable classes (i.e return clone $this) or static methods that return an instance of the class itself.

Without the static type allowed in return types, one would have to use self as the return type, which may not be the ideal one. PHP DocBlock already allowed @return static in its DocBlocks to indicate that the methods return the object itself, or an instance of the same class.

With PHP 8.0's static return type support, it is now possible to replace DocBlock @return static statements with a return type declaration.

class Foo {
-   /**
-    * @return static
-    */
-   public static getInstance() {
+   public static getInstance(): static {
        return new static();
    }
}

Variance

static return type follows Liskov Substitution Principle. A child class method can return a narrower class object than the parent methods return type.

Because static always refer to the class name of the called object (i.e. same as get_class($object)), static is a subset of self, which in turn is subset of parent.

It is possible for a child class to return static, even if the parent methods return type is self, or parent.

For example, the entirety of the following inheritance is valid:

Excessive inheritance chains are almost always a bad idea, and leads to unmanageable code. The snippet below is just for demonstration.

class Foo {
    public function getInstance(): mixed {}
}
class Bar extends Foo {
    public function getInstance(): object|null {}
}
class Baz extends Bar {
    public function getInstance(): object {}
}
class Qux extends Baz {
    public function getInstance(): parent {}
}
class Quux extends Qux {
    public function getInstance(): self {}
}
class Corge extends Quux {
    public function getInstance(): static {}
}

The snippet above uses other PHP 8.0 features

Attempting to "widen" the return type scope with self, parent, or any other return type will cause error:

class Corge {
    public function getInstance(): static {}
}
class Grault extends Corge {
    public function getInstance(): parent {}
}
Fatal error: Declaration of Grault::getInstance(): Corge must be compatible with Corge::getInstance(): static in ... on line ...

In fact, it is also not allowed to replace the static return type with the class name of the child class or parent class either.

Return type only

static return type is only allowed as a return type. It is not allowed as a property type or a parameter type.

This is because the static return type is always narrowing the scope, which is not allowed in typed properties and parameter types.

Not allowed outside class context

Only class methods can declare static return type. Standard functions or closures are not allowed to declare static return type.

function get_instance(): static {}
Fatal error: Cannot use "static" when no class scope is active in ... on line ...

Backwards Compatibility Impact

Code with static return type will not be backwards-compatible with older PHP versions prior to 8.0. Doing so will result in a parse error:

Parse error: syntax error, unexpected 'static' (T_STATIC) in ... on line ...

It is not possible to back-port this feature to older PHP versions either.


RFC Discussion Implementation