はじめに
PHPでは「関数を値として扱う」ことができます。関数を別の関数の引数として渡したり、関数の戻り値として返したりする仕組みを 高階関数(Higher-Order Function) と呼びます。
この概念を理解すると、コードの重複を大幅に減らし、柔軟で再利用しやすい設計が可能になります。本記事ではPHPの callable 型の種類から、高階関数の実用的な使い方まで順を追って解説します。
callableとは何か
PHPでは関数を表す値を総称して callable と呼びます。callableには主に以下の種類があります。
| 種類 | 例 |
|---|---|
| 関数名(文字列) | 'strtoupper' |
| クロージャ(無名関数) | function($x) { return $x * 2; } |
| アロー関数 | fn($x) => $x * 2 |
| オブジェクトのメソッド | [$obj, 'methodName'] |
| 静的メソッド | [MyClass::class, 'methodName'] |
__invoke を持つオブジェクト | new MyInvokable() |
関数名を文字列で渡す
最もシンプルなcallableは、関数名を文字列として渡す方法です。
<?php
function double(int $n): int
{
return $n * 2;
}
$numbers = [1, 2, 3, 4, 5];
// 関数名を文字列としてarray_mapに渡す
$result = array_map('double', $numbers);
print_r($result);
// Array ( [0] => 2 [1] => 4 [2] => 6 [3] => 8 [4] => 10 )
クロージャを使う
クロージャ(無名関数) は、名前を持たない関数をその場で定義できる機能です。コールバックとして使うときに非常に便利です。
<?php
$numbers = [1, 2, 3, 4, 5, 6];
// 偶数だけを抽出するクロージャ
$evens = array_filter($numbers, function (int $n): bool {
return $n % 2 === 0;
});
print_r($evens);
// Array ( [1] => 2 [3] => 4 [5] => 6 )
useキーワードで外部変数を取り込む
クロージャの中で外側のスコープの変数を使いたい場合は use を使います。
<?php
$threshold = 3;
$filtered = array_filter([1, 2, 3, 4, 5], function (int $n) use ($threshold): bool {
return $n > $threshold;
});
print_r($filtered);
// Array ( [3] => 4 [4] => 5 )
アロー関数(PHP 7.4以降)
fn キーワードを使うと、より短く書けます。アロー関数は外部スコープの変数を use なしで自動的に取り込めます。
<?php
$threshold = 3;
$filtered = array_filter([1, 2, 3, 4, 5], fn(int $n) => $n > $threshold);
print_r($filtered);
// Array ( [3] => 4 [4] => 5 )
高階関数を自作する
既存の array_map や array_filter だけでなく、自分でも高階関数を作れます。
関数を引数として受け取る
<?php
/**
* 配列の各要素に変換処理を適用して、条件を満たすものだけ返す
*
* @param array $items
* @param callable $transform 変換処理
* @param callable $predicate フィルタ条件
*/
function transformAndFilter(array $items, callable $transform, callable $predicate): array
{
$transformed = array_map($transform, $items);
return array_values(array_filter($transformed, $predicate));
}
$result = transformAndFilter(
[1, 2, 3, 4, 5],
fn(int $n) => $n * 3, // 3倍にする
fn(int $n) => $n > 6 // 6より大きいものを残す
);
print_r($result);
// Array ( [0] => 9 [1] => 12 [2] => 15 )
関数を戻り値として返す(関数ファクトリ)
関数を戻り値として返すことで、設定済みの関数を動的に生成できます。
<?php
// 「n倍にする関数」を生成するファクトリ
function makeMultiplier(int $factor): Closure
{
return fn(int $n) => $n * $factor;
}
$double = makeMultiplier(2);
$triple = makeMultiplier(3);
echo $double(5); // 10
echo $triple(5); // 15
$numbers = [1, 2, 3, 4, 5];
print_r(array_map($double, $numbers));
// Array ( [0] => 2 [1] => 4 [2] => 6 [3] => 8 [4] => 10 )
__invokeを使った呼び出し可能なクラス
クラスに __invoke マジックメソッドを実装すると、そのオブジェクト自体を関数のように呼び出せます。状態を持つcallableを作りたいときに便利です。
<?php
class PrefixFormatter
{
public function __construct(private string $prefix) {}
public function __invoke(string $value): string
{
return $this->prefix . $value;
}
}
$formatter = new PrefixFormatter('[INFO] ');
echo $formatter('サーバーが起動しました');
// [INFO] サーバーが起動しました
$messages = ['接続完了', '処理中', '完了'];
$formatted = array_map($formatter, $messages);
print_r($formatted);
// Array ( [0] => [INFO] 接続完了 [1] => [INFO] 処理中 [2] => [INFO] 完了 )
is_callableで確認する
受け取った値が呼び出し可能かどうかを確認するには is_callable() を使います。
<?php
function safeCall(mixed $fn, mixed $arg): mixed
{
if (!is_callable($fn)) {
throw new \InvalidArgumentException('callableではありません');
}
return $fn($arg);
}
echo safeCall(fn($x) => $x * 2, 10); // 20
echo safeCall('strtoupper', 'hello'); // HELLO
まとめ
| 機能 | 使いどころ |
|---|---|
| 関数名文字列 | 既存関数をシンプルに渡したいとき |
| クロージャ | 使い捨ての処理や外部変数を取り込みたいとき |
| アロー関数 | 短い処理を簡潔に書きたいとき |
| 関数ファクトリ | 設定済みの関数を動的に生成したいとき |
__invoke | 状態を持つcallableが必要なとき |
高階関数を活用すると、条件や処理をコードの外側から差し込めるようになり、テストしやすく変更に強い設計につながります。ぜひ普段のコードに取り入れてみてください。