PHP 8.0: Calling non-static class methods statically result in a fatal error
PHP 8.0 no longer allows to call non-static class methods with the static call operator (::
).
Calling non-static methods statically raised a PHP deprecation notice in all PHP 7 versions, and raised a Strict Standards notice in PHP 5 versions.
class Foo {
public function bar() {}
}
Foo::bar();
// Deprecated: Non-static method Foo::bar() should not be called statically in ... on line ...
In PHP 8.0 and later, this results in a fatal error:
class Foo {
public function bar() {}
}
Foo::bar();
// Fatal error: Uncaught Error: Call to undefined method Foo::bar() in ...:...
Note that this only affects calling non-static methods statically. Although discouraged, calling a static method non-statically (
$this->staticMethod()
) is allowed.
This change is implemented throughout the engine.
Variable Functions
class Foo {
public function bar() {}
}
['Foo', 'bar']();
// Fatal error: Uncaught Error: Non-static method Foo::bar() cannot be called statically in ...:...
Callables
PHP no longer considers an array with class name and a method (['Foo', 'bar']
) as a valid callable, and results in a fatal error. This includes PHP core functions that expect a callable. If such callable is passed to a function that expects a valid callable, a \TypeError
will be thrown instead of a fatal error at call-time.
class Foo {
public function bar() {}
}
call_user_func(['Foo', 'bar']);
call_user_func_array(['Foo', 'bar'], []);
// Fatal error: Uncaught TypeError: call_user_func(): Argument #1 ($function) must be a valid callback, non-static method Foo::bar() cannot be called statically in ...:...
This affects all functions ranging from call_user_func
and call_user_func_array
to register_shutdown_function
, set_error_handler
, set_error_handler
.
register_shutdown_function
function in PHP 8.0 versions until beta3 raised a PHP warning at the timeregister_shutdown_function
function is called instead of the current behavior of throwing a\TypeError
exception. This was corrected in PHP beta4.
is_callable
is_callable
function returns false
on callable that calls non-static methods statically. It returned true
prior to PHP 8.0.
class Foo {
public function bar() {}
}
is_callable(['Foo', 'bar']); // false
static
, self
, and parent
static
, self
, and and parent
pointers can continue to use the static call syntax inside a class.
class Test extends UpperTest{
public function foo(): {}
public function bar() {
static::foo();
self::foo();
parent::foo();
}
}
The call above is still allowed because static
, self
, and parent
are used inside the class scope.
static::
and self::
calls are identical to $this->
calls on non-static methods, and improves readability. In the example above, static::foo()
and self::foo()
calls can be safely replaced with $this->foo()
to improve readability because foo
is not a static method.
Backwards Compatibility Impact
For existing code that get fatal errors in PHP 8.0, the fix can as simple as using the correct syntax if there is a class instance in the same scope.
class Foo {
public function bar() {}
}
$foo = new Foo();
- Foo::bar();
+ $foo->bar();
If there is no instantiated class object, and if the class can be instantiated without any parameters or side effects, it will be simple replacement as well.
class Foo {
public function bar() {}
}
- Foo::bar();
+ (new Foo())->bar();
If the class constructor requires parameters, or tends to make any state changes, the fix can be more complicated. The instance needs to be injected to the scope the static call is made.
Note that functions that expect a callable
parameter no longer accept callables with a non-static method as static method. A \TypeError
exception will be thrown when the callable is passed, as opposed to when the callable is invoked.
class Foo {
public function bar() {}
}
function takeCallable(callable $func) {}
- takeCallable(['Foo', 'bar']);
+ takeCallable([new Foo(), 'bar']);
is_callable
function no longer returns true
for such callables either.