基礎

PHPの__invoke()|オブジェクトを関数のように呼び出す

__invoke()は、オブジェクトを関数のように呼び出したときに自動的に実行されるマジックメソッドです。コールバック関数としてオブジェクトを渡したい場合に便利です。

基本的な使い方

PHP
<?php
class Greeter {
    private string $greeting;
    
    public function __construct(string $greeting) {
        $this->greeting = $greeting;
    }
    
    // オブジェクトを関数として呼び出すと実行される
    public function __invoke(string $name): string {
        return "{$this->greeting}, {$name}!";
    }
}

$hello = new Greeter("Hello");
$konnichiwa = new Greeter("こんにちは");

// オブジェクトを関数のように呼び出す
echo $hello("World");
echo "<br>";
echo $konnichiwa("太郎");
?>
実行結果
Hello, World!
こんにちは、太郎!

$hello("World")のように、変数に格納したオブジェクトを関数呼び出しの構文で実行すると、__invoke()メソッドが呼ばれます。

コールバック関数として使う

__invoke()の最も実用的な使い方は、array_map()array_filter()などのコールバック関数としてオブジェクトを渡すことです。

PHP
<?php
class TaxCalculator {
    private float $rate;
    
    public function __construct(float $rate) {
        $this->rate = $rate;
    }
    
    public function __invoke(int $price): int {
        return (int)($price * (1 + $this->rate));
    }
}

$prices = [100, 200, 300, 500, 1000];
$tax10 = new TaxCalculator(0.10);

// コールバックとしてオブジェクトを渡す
$withTax = array_map($tax10, $prices);
print_r($withTax);
?>
実行結果
Array ( [0] => 110 [1] => 220 [2] => 330 [3] => 550 [4] => 1100 )

クロージャでも同じことはできますが、__invoke()を使うとオブジェクトに状態(ここでは税率)を持たせられるため、設定を変えやすく再利用しやすいコードになります。

callable判定

PHP
<?php
class MyCallable {
    public function __invoke() {}
}

$obj = new MyCallable();
var_dump(is_callable($obj));  // bool(true)

class NotCallable {}
$obj2 = new NotCallable();
var_dump(is_callable($obj2)); // bool(false)
?>
__invoke()とクロージャの関係

PHPのクロージャ(無名関数)は内部的にClosureクラスのインスタンスであり、__invoke()を持っています。つまり、__invoke()を実装したクラスは「呼び出し可能なオブジェクト」として、クロージャと同じように振る舞えます。

まとめ

  • __invoke()はオブジェクトを関数のように呼び出すと実行されるマジックメソッド
  • array_map()などのコールバックにオブジェクトを渡せるようになる
  • 状態を持つコールバックを作りたい場合にクロージャの代替として有用
  • is_callable()で呼び出し可能か判定できる