Callback-функции как объекты первого класса представлены в PHP 8.1.0 как способ создания анонимных функций из callback-функций. Синтаксис заменяет существующий синтаксис вызова с использованием строк и массивов. Преимущество синтаксиса заключается в том, что он доступен для статического анализа и использует область видимости в точке, где получена callback-функция.
Синтаксис CallableExpr(...)
используется для создания объекта Closure из callback-функции. CallableExpr
принимает любое выражение, которое может быть вызвано напрямую в грамматике PHP:
Пример #1 Простой пример callback-функции как объекты первого класса
<?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(...); // вызываемый объект
$f3 = $obj->method(...);
$f4 = $obj->$methodStr(...);
$f5 = Foo::staticmethod(...);
$f6 = $classStr::$staticmethodStr(...);
// традиционная callback-функция с использованием строки, массива
$f7 = 'strlen'(...);
$f8 = [$obj, 'method'](...);
$f9 = [Foo::class, 'staticmethod'](...);
?>
Замечание:
...
является частью синтаксиса, а не пропуском.
У CallableExpr(...)
та же семантика, что и у Closure::fromCallable().
То есть, в отличие от callback-функции с использованием строк и массивов, CallableExpr(...)
учитывает область видимости в точке, где она создаётся:
Пример #2 Сравнение области действия CallableExpr(...)
и традиционной callback-функции
<?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
// Это потому, что вызов выполняется вне Foo, и с этого момента будет проверяться видимость.
class Foo1 {
public function getPrivateMethod() {
// Использует область, в которой получена callback-функция.
return $this->privateMethod(...); // идентично Closure::fromCallable([$this, 'privateMethod']);
}
private function privateMethod() {
echo __METHOD__, "\n";
}
}
$foo1 = new Foo1;
$privateMethod = $foo1->getPrivateMethod();
$privateMethod(); // Foo1::privateMethod
?>
Замечание:
Создание объекта с помощью этого синтаксиса (например,
new Foo(...)
) не поддерживается, поскольку синтаксисnew Foo()
не считается callback-функцией.
Замечание:
Callback-функции как объекты первого класса нельзя комбинировать с оператором Nullsafe. Оба следующих результата приводят к ошибке времени компиляции:
<?php
$obj?->method(...);
$obj?->prop->method(...);
?>