かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

PHP コールバック関数を使うあれこれ

function_exists だと無記名関数はチェックできない

<?php
/**
 * @param: $callback コールバック関数
 */
function func($callback) {
  var_dump( function_exists($callback) );
  if( function_exists( $callback ) ) {
    call_user_func( $callback );
  } else {
    echo '関数がないよ。';
  }
}

function destroyer() {
  echo '響だよ';
}
// 関数名を文字列で渡すのはOK
func('destroyer'); // => 'bool(true) 響だよ'

// 変数に関数名を文字列で代入してもOK
$myFunc = 'destroyer';
func($myFunc); // => 'bool(true) 響だよ'

// 無記名関数は実行されない
func( function() {
  echo '響だよ';
} );  // => NULL 関数がないよ。

function_exists
function_exists — 指定した関数が定義されている場合に TRUE を返す

無記名関数は関数として定義されてないので、function_exists()NULLになるので、function_exists()でcallback関数のチェックをしている場合は実行されない。

is_callable でチェックする

is_callable
is_callable — 引数が、関数としてコール可能な構造であるかどうかを調べる

<?php
/**
 * @param: $callback コールバック関数
 */
function func($callback) {
  var_dump( is_callable($callback) );
  if( is_callable( $callback ) ) {
    call_user_func( $callback );
  } else {
    echo '関数がないよ。';
  }
}

function destroyer() {
  echo '響だよ';
}
// 関数名を文字列で渡すのはOK
func('destroyer'); // => 'bool(true) 響だよ'

// 変数に関数名を文字列で代入してもOK
$myFunc = 'destroyer';
func($myFunc); // => 'bool(true) 響だよ'

// 無記名関数でもOK
func( function() {
  echo '響だよ';
} );  // => bool(true) 響だよ

PHP5.4以降なら コールバック関数を実行する関数の引数にタイプヒンティングを付けておくと、関数以外を渡すとエラーを返せるようになる。

<?php
/**
 * @param: $callback コールバック関数
 */
function func(callable $callback) {
  // ※ 関数でない場合はエラーになるので if( is_callable ) でチェックする意味は無い
  call_user_func( $callback );
}

// 存在しない関数名を渡す
func( 'myFunc' ); //=> PHP Catchable fatal error:  Argument 1 passed to func() must be callable, ...

コールバック関数に引数を使いたい

call_user_func()では第2引数以降にパラメーター追加していって渡すことができる。

call_user_func

mixed call_user_func ( callable $callback [, mixed $parameter [, mixed $... ]] )
※ call_user_func() のパラメータは 参照渡しではないことに注意

<?php
/**
 * @param: $callback コールバック関数
 * @param: $a1, $2, $a3 ... コールバック関数に渡す引数
 * ※ 引数の数が合わないと Warning になるので注意が必要
 */
function func(callable $callback, $a1, $a2, $a3) {
  call_user_func( $callback, $a1, $a2, $a3 );
}

function destroyer($type, $number, $name) {
  echo "{$type}{$number}番艦 {$name}だよ";
}

func('destroyer', '暁', '一', '暁');  // => 暁型 一番艦 暁だよ

func( function($type, $number, $name) {
  echo "{$type}{$number}番艦 {$name}だよ";
}, '暁', '二', '響'); // => 暁型 二番艦 響だよ

パラメータが可変になるなら、第2引数の配列が展開されて、コールバックに渡されるのでcall_user_func_arrayの方が便利そう。

call_user_func_array

mixed call_user_func_array ( callable $callback , array $param_arr )

<?php
/**
 * @param: $callback コールバック関数
 * @param: $params(Array) コールバック関数に渡す引数の配列
 */
function func(callable $callback, $params = []) {
  call_user_func_array( $callback, $params );
}

function destroyer($type, $number, $name) {
  echo "{$type}{$number}番艦 {$name}だよ";
}

func('destroyer', ['暁', '一', '暁']); // => 暁型 一番艦 暁だよ

func( function($type, $number, $name) {
  echo "{$type}{$number}番艦 {$name}だよ";
}, ['暁', '二', '響']); // => 暁型 二番艦 響だよ

 


[参考]