La sintaxis de callable de primera clase se introduce a partir de PHP 8.1.0, como una manera de crear funciones anónimas desde callables. Reemplaza la sintaxis de callables existente que utiliza 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(...)
se utiliza para crear un objeto
Closure desde el 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(...); // objeto invocable
$f3 = $obj->method(...);
$f4 = $obj->$methodStr(...);
$f5 = Foo::staticmethod(...);
$f6 = $classStr::$staticmethodStr(...);
// callable tradicional usando 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 que utilizan cadenas y arrays,
CallableExpr(...)
respeta el ámbito del punto donde es creado:
Ejemplo #2 Comparación de ámbito de CallableExpr(...)
y 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
// Esto es porque la llamada se realiza fuera de Foo y la visibilidad será verificada desde este punto.
class Foo1 {
public function getPrivateMethod() {
// Usa el ámbito donde el callable es adquirido.
return $this->privateMethod(...); // idéntico a 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 (por ejemplo
new Foo(...)
) no es soportada, ya que la sintaxisnew Foo()
no es considerada 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(...);
?>