PHP

【PHP】プロパティに格納されたクロージャを呼び出す方法まとめ

More than 1 year has passed since last update.

■ はじめに

PHP: プロパティ - Manual
PHP: 無名関数 - Manual

プロパティ(クラスのメンバ変数)にクロージャ(無名関数)を格納したとき、
なにも工夫をしないと呼び出すことができません。

下記出力の通り、$this->closure()は変数ではなく関数として扱われてしまいます。

<?php

class CallClosure {

  /**
   * @var \Closure
   */
  private $closure;

  public function set_closure(\Closure $arg)
  {
    $this->closure = $arg;
  }

  public function call_simply($arg)
  {
    $this->closure($arg);
  }

}

$call_closure = new CallClosure();
$call_closure->set_closure(function($arg) {
  echo $arg;
});
$message = 'よんだ?';
$call_closure->call_simply($message);
出力
PHP Fatal error:  Uncaught Error: Call to undefined method CallClosure::closure() in /workspace/Main.php:14
Stack trace:
#0 /workspace/Main.php(24): CallClosure->call_simply('\xE3\x82\x88\xE3\x82\x93\xE3\x81\xA0\xEF\xBC\x9F')
#1 {main}
  thrown in /workspace/Main.php on line 14

そういうわけで、プロパティと同じ名称の関数を用意してやると当然そちらが呼び出されます。

<?php

class CallClosure {

  /**
   * @var \Closure
   */
  private $closure;

  public function set_closure(\Closure $arg)
  {
    $this->closure = $arg;
  }

  public function call_simply($arg)
  {
    $this->closure($arg);
  }

  public function closure($arg)
  {
    echo $arg . 'よんでないよ';
  }

}

$call_closure = new CallClosure();
$call_closure->set_closure(function($arg) {
  echo $arg;
});
$message = 'よんだ?';
$call_closure->call_simply($message);
出力
よんだ?よんでないよ

■ プロパティに格納されたクロージャを呼び出す

ぱっと調べた感じ、方法は5つあるっぽいです。

  1. 一度ローカル変数に代入してから呼び出す
  2. カッコでくくってから呼び出す
  3. マジックメソッド__invokeで呼び出す → PHP: マジックメソッド - Manual
  4. コールバックで呼び出す → PHP: コールバック / Callable - Manual
  5. Closure::callで呼び出す → PHP: Closure::call - Manuall
<?php

class CallClosure {

  /**
   * @var \Closure
   */
  private $closure;

  public function set_closure(\Closure $arg)
  {
    $this->closure = $arg;
  }

  public function call_via_local_variable($arg)
  {
    $closure = $this->closure;
    $closure($arg);
  }

  public function call_via_brackets($arg)
  {
    ($this->closure)($arg);
  }

  public function call_via_invoke($arg)
  {
    $this->closure->__invoke($arg);
  }

  public function call_via_call_user_func($arg)
  {
    call_user_func($this->closure, $arg);
  }

  public function call_via_call_of_closure($arg)
  {
    $this->closure->call($this, $arg);
  }

}

$call_closure = new CallClosure();
$call_closure->set_closure(function($arg) {
  echo $arg;
});
$message = 'よんだ?';
$call_closure->call_via_local_variable($message);
$call_closure->call_via_brackets($message);
$call_closure->call_via_invoke($message);
$call_closure->call_via_call_user_func($message);
$call_closure->call_via_call_of_closure($message);
出力
よんだ?よんだ?よんだ?よんだ?よんだ?

おわり!