Deprecate partially supported callables View as Markdown

Implemented (PHP 8.2)
Authors
Nikita Popov nikic@php.net
Date
2021-09-02
Target
PHP 8.2
Implementation
https://github.com/php/php-src/pull/7446
Source
wiki.php.net/rfc/deprecate_partially_supported_callables

Vote

Deprecate partially supported callables? closed
Yes
32
No
0
32 voters
alec Yes 2021-10-09 06:25
asgrim Yes 2021-10-20 13:44
ashnazg Yes 2021-10-13 14:15
brzuchal Yes 2021-10-09 16:39
bwoebi Yes 2021-10-08 21:44
cmb Yes 2021-10-08 14:09
dharman Yes 2021-10-08 20:51
galvao Yes 2021-10-15 13:46
geekcom Yes 2021-10-11 16:48
girgias Yes 2021-10-08 14:11
jhdxr Yes 2021-10-10 16:48
kalle Yes 2021-10-10 00:11
kocsismate Yes 2021-10-08 14:27
levim Yes 2021-10-08 14:06
marandall Yes 2021-10-09 10:28
mbeccati Yes 2021-10-12 20:05
mcmic Yes 2021-10-11 07:10
nicolasgrekas Yes 2021-10-08 14:25
nikic Yes 2021-10-08 14:04
ocramius Yes 2021-10-09 11:45
petk Yes 2021-10-09 11:05
pollita Yes 2021-10-08 15:43
ramsey Yes 2021-10-09 23:57
reywob Yes 2021-10-08 14:26
sebastian Yes 2021-10-11 03:57
sergey Yes 2021-10-11 12:05
sirsnyder Yes 2021-10-20 21:40
tandre Yes 2021-10-08 17:04
theodorejb Yes 2021-10-08 14:21
trowski Yes 2021-10-09 02:27
twosee Yes 2021-10-12 00:39
wyrihaximus Yes 2021-10-17 12:37

Discussions on the mailing list

[RFC] Deprecate partially supported callables
by Nikita Popov · 5 messages
[VOTE] Deprecate partially supported callables
by Nikita Popov · 2 messages

RFC text

Copied from wiki.php.net, last synchronized Oct 13, 2026 11:50 UTC

Introduction

This RFC proposes to deprecate callables that are supported by call_user_func($callable), but not by $callable().

Proposal

The following callables are currently accepted by the callable type, the is_callable() function and call_user_func(), but are not supported by $callable():

"self::method"
"parent::method"
"static::method"
["self", "method"]
["parent", "method"]
["static", "method"]
["Foo", "Bar::method"]
[new Foo, "Bar::method"]

This RFC proposes to deprecate in PHP 8.2 and remove in PHP 9.0 support for these callables. A deprecation warning will be thrown by all attempts to invoke such a callable, such as via call_user_func(), but also array_map().

The is_callable() function and callable type remain side-effect free and do not throw a deprecation warning. They will continue to accept these callables until support is removed entirely.

Normal "function", "Foo::method", ["Foo", "method"] and [new Foo, "method"] style callables are unaffected by this change.

Discussion

This RFC tries to address two issues. The first is the inconsistency in what PHP considers a “callable”. Nowadays, the recommended way to invoke a calllable is the $callable() syntax. However, some arguments that pass a callable type are not actually “callable” with this syntax.

There are principally two ways to resolve this inconsistency: Drop support for these callables entirely, or add support for them to $callable(). Both outcomes are generally viable.

This is where the second issue comes in: Apart from the last two cases, all of these callables are context-dependent. The method that "self::method" refers to depends on which class the call or callability check is performed from. In practice, this usually also holds for the last two cases, when used in the form of [new Foo, "parent::method"].

Reducing the context-dependence of callables is the secondary goal of this RFC. After this RFC, the only scope-dependence still left is method visibility: "Foo::bar" may be visible in one scope, but not another. If callables were to be limited to public methods in the future (while private methods would have to use first-class callables or Closure::fromCallable() to be made scope-independent), then the callable type would become well-defined and could be used as a property type. However, changes to visibility handling are not proposed as part of this RFC.

Backward Incompatible Changes

Most of the callables deprecated here have a straightforward replacement: "self" should be replaced with self::class, and so on:

"self::method"       -> self::class . "::method"
"parent::method"     -> parent::class . "::method"
"static::method"     -> static::class . "::method"
["self", "method"]   -> [self::class, "method"]
["parent", "method"] -> [parent::class, "method"]
["static", "method"] -> [static::class, "method"]

The new form of these callables is no longer context-dependent. It will refer to the self/parent/static scope of where the callable has been created, rather than where is will be called.

If compatibility with PHP < 8.1 is not desired, use of the first-class callable syntax self::method(...) is also possible.

The [$objOrClass, "Bar::method"] callable form deserves some additional explanation, as most people will not have encountered it. Given this kind of inheritance hierarchy...

class Bar {
    public function method() {}
}
class Foo extends Bar {
    public function method() {}
}

...the basic idea behind this callable syntax is that [new Foo, "method"] will refer to the method Foo::method(), which overrides Bar::method(). The [new Foo, "Bar::method"] or [new Foo, "parent::method"] syntax provides a way to call the overridden method instead.

Inside the scope of Foo, the same can be achieved with a call to ["Bar", "method"] or more intuitively written as [parent::class, "method"]. This is not a static method call, but a scoped instance call, the same as the familiar parent::method().

PHP does not provide any straightforward facilities to call an overriden method outside its inheritance hierarchy, as this is generally not a meaningful operation. If need be, this can still be achieved by using either reflection or closure rebinding:

// Using reflection:
(new ReflectionMethod("Bar", "method"))->invoke(new Foo);
// Using closure rebinding:
Closure::fromCallable([new Bar, "method"])->bindTo(new Foo)();

Vote

Voting opened on 2021-10-08 and closed on 2021-10-22.

Vote: Deprecate partially supported callables? — Yes: 32 · No: 0 (closed)