あっぽログ
← 記事一覧に戻る

PHPのCallableと高階関数を使いこなす:関数を引数・戻り値として活用する

はじめに

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_maparray_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が必要なとき

高階関数を活用すると、条件や処理をコードの外側から差し込めるようになり、テストしやすく変更に強い設計につながります。ぜひ普段のコードに取り入れてみてください。

← 記事一覧に戻る