Sintaxis callable de primera clase

La sintaxis de callable de primera clase es introducida a partir de PHP 8.1.0, como una manera de crear funciones anónimas a partir de callable. Reemplaza la sintaxis de callables existente utilizando cadenas y arrays. La ventaja de esta sintaxis es que es accesible al análisis estático y utiliza el ámbito del punto donde el callable es adquirido.

La sintaxis CallableExpr(...) es utilizada para crear un objeto Closure a partir del callable. CallableExpr acepta cualquier expresión que pueda ser directamente llamada en la gramática de PHP:

Ejemplo #1 Sintaxis callable de primera clase básica

<?php
class Foo {
public function
method() {}
public static function
staticmethod() {}
public function
__invoke() {}
}
$obj = new Foo();
$classStr = 'Foo';
$methodStr = 'method';
$staticmethodStr = 'staticmethod';
$f1 = strlen(...);
$f2 = $obj(...); // invokable object
$f3 = $obj->method(...);
$f4 = $obj->$methodStr(...);
$f5 = Foo::staticmethod(...);
$f6 = $classStr::$staticmethodStr(...);
// traditional callable using string, array
$f7 = 'strlen'(...);
$f8 = [$obj, 'method'](...);
$f9 = [Foo::class, 'staticmethod'](...);
?>

Nota:

Los ... forman parte de la sintaxis y no son una omisión.

CallableExpr(...) tiene las mismas semánticas que Closure::fromCallable(). Es decir, a diferencia de los callables utilizando cadenas y arrays, CallableExpr(...) respeta el ámbito del punto donde es creado:

Ejemplo #2 Comparación de ámbito de CallableExpr(...) y de callables tradicionales

<?php
class Foo {
public function
getPrivateMethod() {
return [
$this, 'privateMethod'];
}
private function
privateMethod() {
echo
__METHOD__, "\n";
}
}
$foo = new Foo;
$privateMethod = $foo->getPrivateMethod();
$privateMethod();
// Fatal error: Call to private method Foo::privateMethod() from global scope
// This is because call is performed outside from Foo and visibility will be checked from this point.
class Foo1 {
public function
getPrivateMethod() {
// Uses the scope where the callable is acquired.
return $this->privateMethod(...); // identical to Closure::fromCallable([$this, 'privateMethod']);
}
private function
privateMethod() {
echo
__METHOD__, "\n";
}
}
$foo1 = new Foo1;
$privateMethod = $foo1->getPrivateMethod();
$privateMethod(); // Foo1::privateMethod
?>

Nota:

La creación de objetos con esta sintaxis (e.g new Foo(...)) no es soportada, porque la sintaxis new Foo() no es considerada como una llamada.

Nota:

La sintaxis de callable de primera clase no puede ser combinada con el operador nullsafe. Los dos casos siguientes resultan en un error de compilación:

<?php
$obj
?->method(...);
$obj?->prop->method(...);
?>