第一級callableを生成する記法 (First class callable syntax) とは、PHP 8.1.0 で追加された、 callable から 無名関数 を生成する記法です。 この記法は、 文字列や配列を使って callable を生成するやり方を置き換えるものです。 この記法の利点は、callable の静的解析を行いやすくなることに加え、 そのスコープが、callable を生成した時点のスコープになることです。
CallableExpr(...)
という記法で、
callable から Closure を生成します。
CallableExpr
には、
PHP の文法上直接コールできるあらゆる式が使えます:
例1 簡単な例
<?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(...);
// 文字列や配列を使った、古い記法
$f7 = 'strlen'(...);
$f8 = [$obj, 'method'](...);
$f9 = [Foo::class, 'staticmethod'](...);
?>
注意:
...
は文法の一部であり、省略形ではありません。
この記法の動作は、
Closure::fromCallable()
の仕様に従います。
つまり、文字列や配列から callable を作るやり方とは異なり、
CallableExpr(...)
のスコープは、
それを生成した時点でのスコープになります:
例2 古い callable の生成方法と、CallableExpr(...)
の比較
<?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() {
// 下記は、callable を生成した時点のスコープになります。
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()
は、呼び出しとは見なされないからです。
注意:
この記法は、nullsafe 演算子 と組み合わせて使うことはできません。 以下のコードは、いずれもコンパイルエラーになります:
<?php
$obj?->method(...);
$obj?->prop->method(...);
?>