La sintassi delle callable di prima classe è stata introdotta a partire da PHP 8.1.0, come un modo per creare funzioni anonime da callable. Sostituisce la sintassi delle callable esistente utilizzando stringhe ed array. Il vantaggio di questa sintassi è che è accessibile dall'analisi statica e utilizza lo scope nel punto in cui viene acquisita la callable.
La sintassi CallableExpr(...)
viene utilizzata per creare un oggetto Closure dalla callable. CallableExpr
accetta qualsiasi espressione che puó essere richiamata direttamente nella grammatica PHP:
Example #1 Sintassi della callable di prima classe semplice
<?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(...); // oggetto invocabile
$f3 = $obj->method(...);
$f4 = $obj->$methodStr(...);
$f5 = Foo::staticmethod(...);
$f6 = $classStr::$staticmethodStr(...);
// callable tradizionale usando string, array
$f7 = 'strlen'(...);
$f8 = [$obj, 'method'](...);
$f9 = [Foo::class, 'staticmethod'](...);
?>
Nota:
I
...
fanno parte della sintassi e non sono un'omissione.
CallableExpr(...)
ha la stessa semantica di Closure::fromCallable().
Ovvero, a differenza di callable che utilizzano stringhe e array, CallableExpr(...)
rispetta lo scope nel punto in cui viene creato:
Example #2 Confronto dello scope tra CallableExpr(...)
e callable tradizionale
<?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
// Questo perché la chiamata viene eseguita all'esterno di Foo e la visibilità verrà controllata da questo punto.
class Foo1 {
public function getPrivateMethod() {
// Utilizza lo scope in cui viene acquisita la callable.
return $this->privateMethod(...); // uguale a Closure::fromCallable([$this, 'privateMethod']);
}
private function privateMethod() {
echo __METHOD__, "\n";
}
}
$foo1 = new Foo1;
$privateMethod = $foo1->getPrivateMethod();
$privateMethod(); // Foo1::privateMethod
?>
Nota:
La creazione di oggetti con questa sintassi (ad esempio
new Foo(...)
) non è supportata, perché la sintassinew Foo()
non è considerata una chiamata.
Nota:
La sintassi della callable di prima classe non può essere combinata con l'operatore nullsafe. Entrambi i seguenti porteranno ad un errore in fase di compilazione:
<?php
$obj?->method(...);
$obj?->prop->method(...);
?>