Syntaxe callable de première classe

La syntaxe de callable de première classe est introduite à partir de PHP 8.1.0, comme une manière de créer des fonctions anonymes depuis des callable. Elle remplace la syntaxe des callables existante utilisant les chaînes et tableaux. L'avantage de cette syntaxe est qu'elle est accessible à l'analyse statique et utilise la portée du point où le callable est acquis.

La syntaxe CallableExpr(...) est utilisée pour créer un objet Closure depuis le callable. CallableExpr accepte toute expression qui peut être directement appelée dans la grammaire de PHP :

Exemple #1 Syntaxe callable de première classe basique

<?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(...); // objet invocable
$f3 = $obj->method(...);
$f4 = $obj->$methodStr(...);
$f5 = Foo::staticmethod(...);
$f6 = $classStr::$staticmethodStr(...);
// callable traditionnel utilisant une chaîne, un tableau
$f7 = 'strlen'(...);
$f8 = [$obj, 'method'](...);
$f9 = [Foo::class, 'staticmethod'](...);
?>

Note:

Les ... font partie de la syntaxe et ne sont pas une omission.

CallableExpr(...) a les mêmes sémantiques que Closure::fromCallable(). C'est-à-dire, contrairement aux callables utilisant les chaînes et tableaux, CallableExpr(...) respecte la portée du point où il est créé :

Exemple #2 Comparaison de portée de CallableExpr(...) et des callables traditionnels

<?php
class Foo {
public function
getPrivateMethod() {
return [
$this, 'privateMethod'];
}
private function
privateMethod() {
echo
__METHOD__, "\n";
}
}
$foo = new Foo;
$privateMethod = $foo->getPrivateMethod();
$privateMethod();
// Erreur fatale : Call to private method Foo::privateMethod() from global scope
// Ceci est dû au fait que l'appel est effectué en dehors de Foo et la visibilité sera vérifiée depuis ce point.
class Foo1 {
public function
getPrivateMethod() {
// Utilise la portée où le callable est acquis.
return $this->privateMethod(...); // identique à Closure::fromCallable([$this, 'privateMethod']);
}
private function
privateMethod() {
echo
__METHOD__, "\n";
}
}
$foo1 = new Foo1;
$privateMethod = $foo1->getPrivateMethod();
$privateMethod(); // Foo1::privateMethod
?>

Note:

La création d'objets avec cette syntaxe (e.g new Foo(...)) n'est pas supportée, car la syntaxe new Foo() n'est pas considérée comme un appel.

Note:

La syntaxe de callable de première classe ne peut pas être combinée avec l'opérateur nullsafe. Les deux cas suivants entraînent une erreur de compilation :

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