rfc:alternative_callback_syntax

This is an old revision of the document!


Request for Comments: Alternative syntax for creating fully resolved callbacks

Introduction

This RFC proposes the syntax func_name::function for generating a callback value at runtime with correctly resolved class and function names.

Why?

The string and array formats for callbacks present difficulties for users and IDEs:

  • Most IDEs do not recognize callbacks, and so cannot offer autocompletion, rename refactoring, and other benefits of code comprehension.
  • Authors can misspell identifiers inside strings.
  • Within namespaced code, authors can forget to prepend the namespace, since function calls within the namespace do not require it.
  • Where use statements change the identifier for a class, authors can forget to specify the fully resolved name.

Proposal

PHP would provide a syntax, similar to a function call, which evaluates to a string or array callback value. This would be composed of the usual function call syntax, but replacing the parameter list and surrounding parenthesis with ::function. For example, to create the callback “Foo::bar”, one would use the expression Foo::bar::function.

Under the proposal, the following expressions (within a namespace NS and a class Foo) would evaluate as true:

func::function === 'NS\\func';
\func::function === 'func';
CN::meth::function === 'NS\\CN::meth';
\CN::meth::function === 'CN::meth';
self::meth::function === 'NS\\Foo::meth';
$obj->meth::function === [$obj, 'meth'];
parent::{'meth'}::function === ['NS\\Foo', 'parent::meth'];

Example Code

namespace NS1;
use NS2\Bee as B;
 
class A {
    static function init() {
        $inst = new self;
        var_export($inst->bar::function);
        $inst->bar();
    }
    function bar() {
        var_export(B::baz::function); 
    }
}
 
function c() {}
 
var_export(var_export ::function);
var_export(A::init ::function);
A::init();
var_export(c ::function);

At runtime, these values would be passed to var_export:

'var_export';
'NS1\\A::init';
[$inst, 'bar'];
'NS2\\Bee::baz';
'NS1\\c';

Considerations

As function is a reserved word, it should not be misinterpreted as a constant or method in previous versions (this idea borrowed from Ralph Schindler’s class_name_scalars RFC). If the implementation reused the T_FUNCTION token, the syntax would be case-insensitive.

Any other use of ::function should throw a parse error. Although it may be reasonable to suggest supporting syntaxes like ($callable)::function (evaluating to the value of $callable), I believe this would not provide much benefit and would complicate the spec.

As it is permitted between a function name and its argument list, for consistency and flexibility, whitespace should be permitted before the ::function tokens. It's not clear whether whitespace would improve or worsen readability of the expression in practice; this will likely depend on how syntax highlighters display the ::function tokens.

Summary

::function would give authors a straightforward and reliable way to specify correctly-formed callbacks without being tripped up by namespaces and use statements. Callback expressions would also be more clearly recognized as such by the reader, and by IDEs and static analysis tools.

Changelog

  • 2012-09-18 Created by Steve Clay
rfc/alternative_callback_syntax.1348018207.txt.gz · Last modified: 2017/09/22 13:28 (external edit)