目次
最初に
WordPressでget_permalink()
やget_the_title()
を書き換えたりするカスタマイズをしていると、「アクションフック」「フィルターフック」というワードを良く目にします。
普段なんとなくで使っているこの機能を詳しく深堀りしてみようと思いました。
ネットで検索すると、PHPのコールバック関数という技術が使われているそうで、まずその知見が私に不足していますので、調べてサンプルを作ってみました。
検証は、PHP Version 7.3.10で行いました。
コールバック関数とは、引数に関数名を文字列で設定し、呼び出す
まず簡単な定義についてまとめます。
PHPの関数には、引数というものが設定できます。
コールバック関数は、その引数に任意のコールバック関数名の文字列を設定することで、呼び出しができるものです。
通常の関数同様、任意の処理や、引数も設定できます。
また、変数にコールバック関数名を代入し、呼び出しできるため、可変関数とも呼ばれています。
下記に簡単な例を記載しましたので、構造を理解しましょう。
/*Logic
---------------------------*/
function greeting(callable $method)
{
//helloworld()を呼び出す
echo $method();
}
function helloworld()
{
echo "Hello World";
}
/*View
---------------------------*/
//引数にhelloworld()の関数名の文字列を配置
greeting("helloworld");
/*@output
---------------------------
Hello World
*/
greeting()
の引数にhelloworld()
の関数名の文字列を配置することで、helloworld()
を呼び出すことができます。
コールバック関数の活用サンプル
【サンプル1】基本的な使い方
下記に簡単な使い方の例を記載します。
/*Logic
---------------------------*/
function greeting(string $str,callable $method)
{
//goodmorning()、goodnight()を呼び出し
//$strのように引数も設定可能
echo $method($str);
}
function goodmorning(string $str)
{
echo "Good morning " . $str . "<br>";
}
function goodnight(string $str)
{
echo "Good night " . $str . "<br>";
}
/*View
---------------------------*/
//第2引数にコールバック関数名を文字列でそれぞれ設定
greeting("ネコ", "goodmorning");
greeting("ネコ", "goodnight");
/*@output
---------------------------
Good morning ネコ
Good night ネコ
*/
greeting()
の第2引数にgoodmorning()
、goodnight()
のコールバック関数名を文字列でそれぞれ設定しています。
greeting()
内の$method($str);
は、引数の$method
に代入された関数名の文字列から、goodmorning()
、goodnight()
を呼び出しています。
"ネコ"
の文字列のように通常の関数同様引数も設定できます。
もし、コールバック関数を知らなかったら、私はおそらく下記のように書いていたと思います。
/*Logic
---------------------------*/
function greeting($str, $method)
{
switch($method){
case "goodmorning"://!!ここで文字列を設定しないといけなくなる
goodmorning($str);
break;
case "goodnight"://!!ここで文字列を設定しないといけなくなる
goodnight($str);
break;
}
}
function goodmorning($str)
{
echo "Good morning " . $str . "<br>";
}
function goodnight($str)
{
echo "Good night " . $str . "<br>";
}
/*View
---------------------------*/
greeting("ネコ", "goodmorning");
greeting("ネコ", "goodnight");
/*@output
---------------------------
Good morning ネコ
Good night ネコ
*/
greeting()
で、$method
引数に応じて、switch文で処理を分けていますが、これではcaseに別途文字列を用意しないけません。
上記のように書いても、出力される文字列は変わらないので、大きな問題ではないのですが、コールバック関数を用いることで、より簡潔にコードを書くことができるようになります。
【サンプル2】クラスメソッドを使用
クラスメソッドとしてコールバック関数を使用したくなる場合もあるかと思います。
下記のサンプルでは、greeting()
の引数にnew演算子と文字列の関数名の配列を配置し、コールバック関数を使用しています。
/*logic
---------------------------*/
function greeting(string $str,callable $method)
{
echo $method($str);
}
class greeting_class
{
public function goodmorning(string $str)
{
echo "Good morning " . $str . "<br>";
}
public function goodnight(string $str)
{
echo "Good night " . $str . "<br>";
}
}
/*View
---------------------------*/
//new演算子の宣言
$greeting_class = new greeting_class();
//引数にnew演算子と文字列の関数名の配列を配置
greeting( "ネコ", [$greeting_class,'goodmorning']);
greeting( "ネコ", [$greeting_class,'goodnight']);
/*@output
---------------------------
Good morning ネコ
Good night ネコ
*/
【サンプル3】クラスにメソッドを動的に追加
コールバック関数を使用することで、もともとあるクラスメソッドにプラスで任意のメソッドを動的に追加することができます。
下記のサンプルはgreeting_class
内にhello()
を追加するという内容です。
追加するためには、Closure::bindTo()
と、__call()
を使用します。
Closure::bindTo()
は下記のサンプルでは、$callback->bindTo()
となりますが、クラスオブジェクトに登録する無名関数を関連付け(bind)させておきます。
__call()
は、アクセスが制限されていたり、存在しないメソッドをオブジェクト参照で実行したときに動くものです。
そのため、コールバック関数と共に使うことで、プラスで関連付け(bind)させ無名関数を動的に追加することができます。
このようにすることで、プラグイン的な設計も可能になるかと思います。
/*logic
---------------------------*/
class greeting_class
{
private $functions = [];
//アクセスが制限されていたり、存在しないメソッドをオブジェクト参照で実行したときに動く
function __call($name, $args)
{
$callback = $this->functions[$name];
return call_user_func_array($callback, $args);
}
public function goodmorning(string $str)
{
echo "Good morning " . $str . "<br>";
}
public function goodnight(string $str)
{
echo "Good night " . $str . "<br>";
}
public function bind_callback(string $method_name, callable $callback)
{
//クラスオブジェクトに登録する無名関数を関連付け
$this->functions[$method_name] = $callback->bindTo($this, self::class);
}
}
/*View
---------------------------*/
$greeting_class= new greeting_class();
$greeting_class->bind_callback(
"hello",
function(string $str){
echo "Hello " . $str. "<br>";;
}
);
$greeting_class->goodmorning("ネコ!");
$greeting_class->goodnight("ネコ!");
$greeting_class->hello("ネコ!");
/*@output
---------------------------
Good morning ネコ!
Good night ネコ!
Hello ネコ!
*/
WordPressやPHPではコールバック関数をどのように使うのか
サンプルで示したように、テーマ制作では、functions.phpで書いているコードをより簡潔に書いたり、固定ページスラッグを活用してコールバック関数を使えたりしそうですね。
また、もともとある機能に動的にメソッドを追加できるので、親テーマで作ったクラスオブジェクトに子テーマのほうで、メソッドを追加したりできるので、使えそうな場面はたくさんありそうです。
PHPではusort()
などのソートを行う関数はコールバック関数の機能を使ってユーザー独自のソートを行うことができるとのことです。
さいごに
これでコールバック関数の概要的な部分を理解できたと思いますので、WordPressの「アクションフック」「フィルターフック」などをまた調べてみようと思います。
自分の知らない部分でしたので、とても勉強になりました。