## 一级可调用语法

从 PHP 8.1.0 开始引入一级可调用语法，作为从 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(...);

    // traditional callable using string, array
    $f7 = 'strlen'(...);
    $f8 = [$obj, 'method'](...);
    $f9 = [Foo::class, 'staticmethod'](...);
    ?>

> 注意:

> `...` 是语法的一部分，不是遗漏。

`CallableExpr(...)` 与 Closure::fromCallable() 语义相同。也就是说，与使用字符串和数组的 callable 不同，`CallableExpr(...)` 尊重其创建时的作用域：

示例 #2 `CallableExpr(...)` 与传统 callable 的作用域比较

    <?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() {
            // Uses the scope where the callable is acquired.
            return $this->privateMethod(...); // identical to 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(...);
>     ?>

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open