第一級callableを生成する記法

第一級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(...);
?>

関連キーワード:  callable, 生成, 記法, 一級, スコープ, CallableExpr, 注意, Foo, new, 文法