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

PHPのFirst-class Callableを使いこなす:関数・メソッドをシンプルに参照する

First-class Callable Syntaxとは

PHP 8.1で導入された First-class Callable Syntax(第一級呼び出し可能構文) は、関数やメソッドを簡単にクロージャとして取得できる機能です。

従来は Closure::fromCallable() を使っていた処理を、... (スプレッド演算子)を使った短い記法で書けるようになりました。

// 従来の書き方
$fn = Closure::fromCallable('strlen');

// First-class Callable Syntax
$fn = strlen(...);

たった一行の違いですが、コードの読みやすさが大きく向上します。


基本的な使い方

組み込み関数をクロージャとして取得する

<?php

$fn = strlen(...);

echo $fn('Hello'); // 5
echo $fn('PHP');   // 3

strlen(...)strlen 関数を Closure オブジェクトとして返します。変数に代入して後から呼び出せます。

ユーザー定義関数に使う

<?php

function double(int $n): int
{
    return $n * 2;
}

$fn = double(...);

echo $fn(5);  // 10
echo $fn(21); // 42

自分で定義した関数でも同様に使えます。


array_map・array_filterとの組み合わせ

First-class Callable Syntaxが最も力を発揮するのは、コールバックを受け取る関数と組み合わせたときです。

array_mapで使う

<?php

$words = ['hello', 'world', 'php'];

// 従来の書き方
$lengths = array_map('strlen', $words);

// First-class Callable Syntax
$lengths = array_map(strlen(...), $words);

print_r($lengths);
// [5, 5, 3]

文字列 'strlen' を渡す書き方と比べて、IDEの補完やリファクタリングが効きやすくなるのが大きなメリットです。

array_filterで使う

<?php

function isPositive(int $n): bool
{
    return $n > 0;
}

$numbers = [-3, -1, 0, 2, 5, 8];

$positives = array_filter($numbers, isPositive(...));

print_r(array_values($positives));
// [2, 5, 8]

usortで使う

<?php

function compareByLength(string $a, string $b): int
{
    return strlen($a) <=> strlen($b);
}

$fruits = ['banana', 'fig', 'apple', 'kiwi'];

usort($fruits, compareByLength(...));

print_r($fruits);
// ['fig', 'kiwi', 'apple', 'banana']

メソッドへの参照

インスタンスメソッドや静的メソッドに対しても使えます。

インスタンスメソッド

<?php

class Formatter
{
    public function toUpperCase(string $text): string
    {
        return strtoupper($text);
    }
}

$formatter = new Formatter();
$fn = $formatter->toUpperCase(...);

echo $fn('hello'); // HELLO

$words = ['php', 'rust', 'laravel'];
$upper = array_map($formatter->toUpperCase(...), $words);

print_r($upper);
// ['PHP', 'RUST', 'LARAVEL']

静的メソッド

<?php

class MathHelper
{
    public static function square(int $n): int
    {
        return $n ** 2;
    }
}

$fn = MathHelper::square(...);

echo $fn(4); // 16

$numbers = [1, 2, 3, 4, 5];
$squares = array_map(MathHelper::square(...), $numbers);

print_r($squares);
// [1, 4, 9, 16, 25]

従来の書き方との比較まとめ

状況従来の書き方First-class Callable
組み込み関数'strlen'strlen(...)
ユーザー関数'myFunc'myFunc(...)
インスタンスメソッド[$obj, 'method']$obj->method(...)
静的メソッド['Class', 'method']Class::method(...)
Closure変換Closure::fromCallable('fn')fn(...)

文字列や配列でメソッドを参照する書き方は、タイポしてもエラーが検出されにくいという問題がありました。First-class Callable Syntaxはコード解析ツールや静的解析ツール(PHPStan・Psalmなど)が正しく型を認識できるため、より安全にコードを書けます。


実践的なユースケース

パイプライン処理に使う

<?php

function pipe(mixed $value, callable ...$fns): mixed
{
    foreach ($fns as $fn) {
        $value = $fn($value);
    }
    return $value;
}

function trim_spaces(string $s): string
{
    return trim($s);
}

function to_lower(string $s): string
{
    return strtolower($s);
}

function add_prefix(string $s): string
{
    return 'user_' . $s;
}

$result = pipe(
    '  Alice  ',
    trim_spaces(...),
    to_lower(...),
    add_prefix(...),
);

echo $result; // user_alice

パイプライン処理のように関数を順番に適用する場面では、First-class Callable Syntaxを使うと非常にすっきりと書けます。


まとめ

PHP 8.1のFirst-class Callable Syntaxは、関数やメソッドをクロージャとして取得するための便利な構文です。

  • strlen(...) のように ... を付けるだけでクロージャに変換できる
  • array_maparray_filter などのコールバックと相性が良い
  • インスタンスメソッド・静的メソッドにも対応
  • 文字列による参照より型安全で、IDEや静的解析ツールに優しい

既存のコードを書き換える際にも少しずつ導入しやすい機能です。PHPで関数型スタイルの処理を書くときにぜひ活用してみてください。

← 記事一覧に戻る