PHPのラムダ式について

採用はこちら

PHPで「ラムダ式」と呼ばれるものは、主に無名関数アロー関数のことです。

名前を付けて定義する通常の関数とは異なり、ラムダ式は関数名を持たず、その場で定義して使える関数です。

配列の要素を変換したり、条件に合うデータだけを抽出したり、コールバック処理を渡したりするときによく使われます。

PHP公式の用語としては、「ラムダ式」よりも次の言葉がよく使われます。

用語意味
無名関数名前を持たない関数
クロージャ無名関数として扱われる関数オブジェクト。外側の変数を取り込める
アロー関数fn を使って短く書ける無名関数の構文

PHPでは、無名関数やアロー関数は Closure クラスのオブジェクトとして扱われます。

目次

PHPのラムダ式の基本

通常の関数との違い

まず、通常の関数は次のように名前を付けて定義します。

function double($num) {
    return $num * 2;
}

echo double(5); // 10

一方、ラムダ式では関数名を付けずに定義できます。

$double = function ($num) {
    return $num * 2;
};

echo $double(5); // 10

この例では、function ($num) { ... } の部分が無名関数です。

無名関数を $double という変数に代入し、$double(5) のように呼び出しています。

無名関数の基本構文

PHPの無名関数は、次のように書きます。

$変数名 = function (引数) {
    処理;
    return 戻り値;
};

たとえば、2つの数値を足す関数は次のように書けます。

$add = function ($a, $b) {
    return $a + $b;
};

echo $add(3, 5); // 8

ポイントは、無名関数を変数に代入しているため、最後にセミコロン ; が必要になることです。

$add = function ($a, $b) {
    return $a + $b;
};

通常の関数定義では最後にセミコロンを書きませんが、無名関数を変数に代入する場合は、代入文として扱われるためセミコロンが必要です。

無名関数とは

名前を持たない関数

無名関数とは、名前のない関数のことです。

通常の関数は次のように名前があります。

function greet($name) {
    return $name . 'さん、こんにちは';
}

しかし、無名関数には関数名がありません。

$greet = function ($name) {
    return $name . 'さん、こんにちは';
};

echo $greet('田中'); // 田中さん、こんにちは

function greet($name) ではなく、function ($name) と書いている点が特徴です。

無名関数を変数に代入する

無名関数は、変数に代入して使えます。

$hello = function () {
    return 'Hello';
};

echo $hello(); // Hello

このように、変数名の後ろに () を付けることで、関数として実行できます。

$hello();

変数の中に関数そのものが入っている、と考えると分かりやすいです。

無名関数を関数の引数として渡す

無名関数は、他の関数に引数として渡すこともできます。

function apply($value, $callback) {
    return $callback($value);
}

$result = apply(10, function ($num) {
    return $num * 3;
});

echo $result; // 30

この例では、apply() に「10を3倍にする処理」を渡しています。

このように、関数に別の関数を渡す仕組みをコールバックと呼びます。

PHPのラムダ式は、このコールバック処理でよく使われます。

クロージャとは

PHPにおけるクロージャの考え方

PHPでは、無名関数は Closure クラスのオブジェクトとして実装されています。

実務上は、特に外側のスコープにある変数を取り込んで使える無名関数をクロージャとして説明することが多いです。

たとえば、次のようなケースです。

$tax = 1.1;

$calc = function ($price) use ($tax) {
    return $price * $tax;
};

echo $calc(1000); // 1100

このコードでは、無名関数の外側にある $tax を、関数の中で使っています。

ただし、通常の無名関数では外側の変数を自動的には使えません。

外側の変数を使うには、use を使って明示的に取り込む必要があります。

useで外側の変数を取り込む

無名関数の外側にある変数を使いたい場合は、次のように use を書きます。

$message = 'こんにちは';

$greet = function ($name) use ($message) {
    return $message . '、' . $name . 'さん';
};

echo $greet('田中'); // こんにちは、田中さん

use ($message) と書くことで、外側の $message を無名関数の中で使えるようになります。

もし use を書かずに次のようにすると、無名関数の中では $message が未定義変数として扱われます。

$message = 'こんにちは';

$greet = function ($name) {
    return $message . '、' . $name . 'さん';
};

echo $greet('田中');

PHP 8.0以降では、未定義変数を使った場合に Undefined variable の警告が出ます。

useは定義時点の値を取り込む

use で取り込まれる値は、基本的に無名関数を定義した時点の値です。

$rate = 1.1;

$calc = function ($price) use ($rate) {
    return $price * $rate;
};

$rate = 1.2;

echo $calc(1000); // 1100

このコードでは、途中で $rate1.2 に変更しています。

しかし、無名関数の中で使われる $rate は、定義時点の 1.1 です。

そのため、結果は 1200 ではなく 1100 になります。

参照渡しで外側の変数を変更する

外側の変数そのものを変更したい場合は、& を付けて参照渡しにします。

$count = 0;

$increment = function () use (&$count) {
    $count++;
};

$increment();
$increment();

echo $count; // 2

use (&$count) と書くことで、無名関数の外側にある $count 自体を変更できます。

ただし、参照渡しは便利な一方で、どこで値が変わったのか分かりにくくなることがあります。

実務では、必要な場合だけ使うのがおすすめです。

アロー関数とは

アロー関数の基本構文

アロー関数は、PHP 7.4から使えるようになった、無名関数を短く書くための構文です。

基本形は次の通りです。

fn (引数) => 式

たとえば、数値を2倍にする処理は次のように書けます。

$double = fn ($num) => $num * 2;

echo $double(5); // 10

これは、次の無名関数と似た意味になります。

$double = function ($num) {
    return $num * 2;
};

echo $double(5); // 10

アロー関数では、return を書きません。=> の右側に書いた式が、そのまま戻り値になります。

アロー関数ではreturnを書かない

アロー関数では、次のように書きます。

$add = fn ($a, $b) => $a + $b;

次のように return を書くことはできません。

// 誤り
$add = fn ($a, $b) => return $a + $b;

アロー関数は、短い式をそのまま返すための構文です。

アロー関数は外側の変数を自動で使える

無名関数では、外側の変数を使うために use が必要でした。

$tax = 1.1;

$calc = function ($price) use ($tax) {
    return $price * $tax;
};

echo $calc(1000); // 1100

一方、アロー関数では外側の変数を自動的に使えます。

$tax = 1.1;

$calc = fn ($price) => $price * $tax;

echo $calc(1000); // 1100

use ($tax) と書かなくても、外側にある $tax を使えるのがアロー関数の特徴です。

アロー関数の変数キャプチャは値渡し

アロー関数は外側の変数を自動で使えますが、基本的には値渡しで取り込みます。

そのため、外側の変数を書き換える用途には向いていません。

$count = 0;

$increment = fn () => $count++;

$increment();

echo $count; // 0

この例では、$count++ と書いていますが、外側の $count は変更されません。

外側の変数を変更したい場合は、次のように無名関数で参照渡しを使います。

$count = 0;

$increment = function () use (&$count) {
    $count++;
};

$increment();

echo $count; // 1

無名関数とアロー関数の違い

書き方の違い

無名関数は次のように書きます。

$double = function ($num) {
    return $num * 2;
};

アロー関数は次のように書きます。

$double = fn ($num) => $num * 2;

アロー関数のほうが短く書けます。

外側の変数の扱いの違い

無名関数では、外側の変数を使うために use が必要です。

$rate = 1.1;

$calc = function ($price) use ($rate) {
    return $price * $rate;
};

アロー関数では、外側の変数を自動で使えます。

$rate = 1.1;

$calc = fn ($price) => $price * $rate;

ただし、アロー関数の変数キャプチャは値渡しです。

外側の変数を直接変更したい場合は、通常の無名関数を使うほうが分かりやすいです。

複数行の処理を書けるかどうか

無名関数では、複数行の処理を書けます。

$formatPrice = function ($price) {
    $taxRate = 1.1;
    $priceWithTax = $price * $taxRate;

    return number_format($priceWithTax) . '円';
};

echo $formatPrice(1000); // 1,100円

一方、アロー関数は基本的に1つの式を返すための構文です。

$formatPrice = fn ($price) => number_format($price * 1.1) . '円';

echo $formatPrice(1000); // 1,100円

短い処理ならアロー関数が便利ですが、途中で変数を作ったり、条件分岐を複数書いたりする場合は、無名関数のほうが読みやすくなります。

使い分けの目安

無名関数とアロー関数は、次のように使い分けるとよいです。

種類向いている処理
無名関数複数行の処理、複雑な条件、参照渡しを使う処理
アロー関数1行で書ける単純な変換・判定処理

たとえば、単純に配列の値を2倍にするだけなら、アロー関数が向いています。

$result = array_map(fn ($num) => $num * 2, $numbers);

一方、複数の処理を行う場合は、無名関数のほうが適しています。

$result = array_map(function ($user) {
    $name = trim($user['name']);
    return mb_strtoupper($name);
}, $users);

PHPのラムダ式を配列処理で使う

array_mapで使う

array_map() は、配列の各要素に処理を適用して、新しい配列を作る関数です。

$numbers = [1, 2, 3, 4, 5];

$result = array_map(function ($num) {
    return $num * 2;
}, $numbers);

print_r($result);

出力は次のようになります。

Array
(
    [0] => 2
    [1] => 4
    [2] => 6
    [3] => 8
    [4] => 10
)

アロー関数を使うと、さらに短く書けます。

$numbers = [1, 2, 3, 4, 5];

$result = array_map(fn ($num) => $num * 2, $numbers);

print_r($result);

array_map() は、先にコールバック関数を書き、その後に配列を指定します。

array_map(コールバック関数, 配列);

array_filterで使う

array_filter() は、条件に合う要素だけを残す関数です。

$numbers = [1, 2, 3, 4, 5, 6];

$evenNumbers = array_filter($numbers, function ($num) {
    return $num % 2 === 0;
});

print_r($evenNumbers);

出力は次のようになります。

Array
(
    [1] => 2
    [3] => 4
    [5] => 6
)

この例では、偶数だけを抽出しています。

アロー関数で書くと、次のようになります。

$numbers = [1, 2, 3, 4, 5, 6];

$evenNumbers = array_filter($numbers, fn ($num) => $num % 2 === 0);

print_r($evenNumbers);

array_filter() は、先に配列を書き、その後にコールバック関数を指定します。

array_filter(配列, コールバック関数);

array_map() とは引数の順番が違うため注意しましょう。

array_filterはキーを保持する

array_filter() は、条件に合わない要素を削除したあとも、元の配列のキーを保持します。

$numbers = [1, 2, 3, 4];

$result = array_filter($numbers, fn ($num) => $num % 2 === 0);

print_r($result);

出力は次のようになります。

Array
(
    [1] => 2
    [3] => 4
)

キーが [0][1] に振り直されるわけではありません。

キーを連番にしたい場合は、array_values() を使います。

$numbers = [1, 2, 3, 4];

$result = array_values(
    array_filter($numbers, fn ($num) => $num % 2 === 0)
);

print_r($result);

出力は次のようになります。

Array
(
    [0] => 2
    [1] => 4
)

APIのレスポンスやJSON化する配列では、キーが飛んでいると意図しない形になることがあります。

必要に応じて array_values() でキーを振り直すと安心です。

array_reduceで使う

array_reduce() は、配列の値を1つの結果にまとめる関数です。

$numbers = [1, 2, 3, 4, 5];

$total = array_reduce($numbers, function ($carry, $num) {
    return $carry + $num;
}, 0);

echo $total; // 15

$carry は途中経過、$num は現在処理している要素です。

アロー関数を使うと、次のように書けます。

$numbers = [1, 2, 3, 4, 5];

$total = array_reduce($numbers, fn ($carry, $num) => $carry + $num, 0);

echo $total; // 15

合計値の計算、文字列の連結、配列データの集約などに使えます。

PHPのラムダ式をコールバックで使う

コールバックとは

コールバックとは、別の関数に渡して、あとから呼び出してもらう関数のことです。

PHPでは、次のような関数でコールバックがよく使われます。

関数用途
array_map()配列の各要素を変換する
array_filter()条件に合う要素だけ残す
array_reduce()配列を1つの値にまとめる
preg_replace_callback()正規表現に一致した部分を関数で置換する
usort()独自ルールで配列を並び替える

ラムダ式は、こうしたコールバック処理と相性がよいです。

preg_replace_callbackで使う

preg_replace_callback() は、正規表現に一致した部分を、コールバック関数で置換する関数です。

$text = 'hello-world';

$result = preg_replace_callback('/-([a-z])/', function ($matches) {
    return strtoupper($matches[1]);
}, $text);

echo $result; // helloWorld

この例では、hello-world-w に一致した部分を W に変換しています。

アロー関数で書くと、次のようになります。

$text = 'hello-world';

$result = preg_replace_callback(
    '/-([a-z])/',
    fn ($matches) => strtoupper($matches[1]),
    $text
);

echo $result; // helloWorld

短い変換処理であれば、アロー関数のほうがすっきり書けます。

usortで使う

usort() は、配列を独自のルールで並び替えるときに使います。

$users = [
    ['name' => '田中', 'age' => 25],
    ['name' => '佐藤', 'age' => 17],
    ['name' => '鈴木', 'age' => 32],
];

usort($users, function ($a, $b) {
    return $a['age'] <=> $b['age'];
});

print_r($users);

この例では、年齢の昇順で並び替えています。

アロー関数を使うと、次のように短く書けます。

usort($users, fn ($a, $b) => $a['age'] <=> $b['age']);

<=> は宇宙船演算子と呼ばれ、左辺が小さい場合は -1、等しい場合は 0、大きい場合は 1 を返します。並び替えの比較処理でよく使われます。

型宣言とラムダ式

引数と戻り値に型を付ける

PHPのラムダ式では、通常の関数と同じように型宣言を使えます。

$add = function (int $a, int $b): int {
    return $a + $b;
};

echo $add(3, 5); // 8

アロー関数でも型宣言を使えます。

$add = fn (int $a, int $b): int => $a + $b;

echo $add(3, 5); // 8

型宣言を付けることで、引数や戻り値の意図が明確になります。

callable型を使う

ラムダ式を関数の引数として受け取る場合は、callable 型を使えます。

function apply(int $value, callable $callback): int {
    return $callback($value);
}

$result = apply(10, fn ($num) => $num * 3);

echo $result; // 30

callable は、「呼び出し可能なもの」を表す型です。

たとえば、次のようなものが callable として扱えます。

function double($num) {
    return $num * 2;
}

echo apply(10, 'double'); // 20

無名関数やアロー関数だけでなく、関数名の文字列や、オブジェクトのメソッドなども callable として渡せます。

Closure型を使う

Closure 型を指定すると、無名関数やアロー関数のような Closure オブジェクトを受け取ることを明示できます。

function apply(int $value, Closure $callback): int {
    return $callback($value);
}

$result = apply(10, fn ($num) => $num * 2);

echo $result; // 20

callable は「呼び出せるもの」全般を表します。

一方、Closure はその中でも、無名関数やアロー関数などの関数オブジェクトを表します。

実務では、広くコールバックを受け取りたい場合は callable、無名関数やアロー関数に限定したい場合は Closure を使うとよいです。

callableとClosureの違い

callableは呼び出し可能なもの全般

callable は、呼び出し可能なものを広く表します。

たとえば、次のようなものが callable です。

function hello() {
    return 'Hello';
}

$callback = 'hello';

echo $callback(); // Hello

オブジェクトのメソッドも callable として扱えます。

class Greeter
{
    public function hello()
    {
        return 'Hello';
    }
}

$greeter = new Greeter();

$callback = [$greeter, 'hello'];

echo $callback(); // Hello

このように、callable はかなり広い概念です。

Closureは無名関数やアロー関数の実体

Closure は、無名関数やアロー関数の実体です。

$func = function () {
    return 'Hello';
};

var_dump($func instanceof Closure); // true

アロー関数も Closure です。

$func = fn () => 'Hello';

var_dump($func instanceof Closure); // true

つまり、Closurecallable の一種と考えると分かりやすいです。

first-class callable構文

PHP 8.1以降で使える構文

PHP 8.1以降では、既存の関数やメソッドから Closure を作るために、first-class callable構文を使えます。

たとえば、次のような関数があるとします。

function double($num) {
    return $num * 2;
}

この関数を Closure として扱いたい場合、PHP 8.1以降では次のように書けます。

$double = double(...);

echo $double(5); // 10

double(...) と書くことで、double 関数を Closure として変数に代入できます。

メソッドでも使える

クラスのメソッドでも使えます。

class Calculator
{
    public function double($num)
    {
        return $num * 2;
    }
}

$calculator = new Calculator();

$double = $calculator->double(...);

echo $double(5); // 10

これは厳密にはラムダ式そのものではなく、既存の関数やメソッドを Closure として扱うための構文です。

ただし、ラムダ式やコールバック処理と一緒に使われることがあるため、関連知識として覚えておくと便利です。

クラス内でラムダ式を使う場合

アロー関数で$thisを使う

クラスのメソッド内でラムダ式を使う場合、$this を利用できます。

class UserService
{
    private string $prefix = 'User: ';

    public function formatNames(array $names): array
    {
        return array_map(fn ($name) => $this->prefix . $name, $names);
    }
}

$service = new UserService();

print_r($service->formatNames(['Tanaka', 'Sato']));

この例では、アロー関数の中で $this->prefix を使っています。

クラス内で配列を加工するとき、アロー関数はよく使われます。

static functionとstatic fnに注意する

無名関数やアロー関数には、static を付けることもできます。

$func = static function () {
    return 'Hello';
};
$func = static fn () => 'Hello';

ただし、static functionstatic fn では $this は使えません。

class UserService
{
    private string $prefix = 'User: ';

    public function formatNames(array $names): array
    {
        return array_map(static fn ($name) => $this->prefix . $name, $names);
    }
}

このような書き方はできません。

$this を使いたい場合は、static を付けないようにしましょう。

ラムダ式を使うメリット

コードを短く書ける

ラムダ式を使うと、短い処理を簡潔に書けます。

$numbers = [1, 2, 3];

$result = array_map(fn ($num) => $num * 2, $numbers);

このような単純な処理のために、わざわざ名前付き関数を定義する必要はありません。

通常の関数で書くと、次のようになります。

function double($num) {
    return $num * 2;
}

$result = array_map('double', $numbers);

もちろんこれでも問題ありませんが、一度しか使わない処理であれば、ラムダ式のほうが簡潔です。

処理をその場で定義できる

ラムダ式の大きなメリットは、必要な場所で処理をそのまま書けることです。

$activeUsers = array_filter($users, fn ($user) => $user['status'] === 'active');

このコードを見ると、「アクティブなユーザーだけを抽出している」とすぐに分かります。

処理内容が短ければ、別の場所に関数を定義するよりも読みやすくなります。

コールバック処理を書きやすい

PHPでは、コールバックを受け取る関数が多くあります。

ラムダ式を使うことで、その場で処理を渡せます。

$validators = [
    'name' => fn ($value) => $value !== '',
    'age' => fn ($value) => $value >= 20,
];

var_dump($validators['name']('田中')); // true
var_dump($validators['age'](18));      // false

このように、バリデーションルールを関数として配列に持たせることもできます。

外側の値を使いやすい

アロー関数では、外側の変数を自動で使えます。

$minAge = 20;

$adults = array_filter($users, fn ($user) => $user['age'] >= $minAge);

無名関数で書く場合は、use が必要です。

$minAge = 20;

$adults = array_filter($users, function ($user) use ($minAge) {
    return $user['age'] >= $minAge;
});

短い処理で外側の値を使いたい場合は、アロー関数が便利です。

ラムダ式を使うときの注意点

複雑な処理を書くと読みにくい

ラムダ式は便利ですが、何でもラムダ式で書けばよいわけではありません。

たとえば、次のように条件が長くなると読みにくくなります。

$result = array_filter($users, fn ($user) => $user['age'] >= 20 && $user['status'] === 'active' && $user['email_verified'] === true);

この程度ならまだ読めますが、条件がさらに増えると、コードの意図が分かりにくくなります。

その場合は、名前付き関数やメソッドに切り出したほうがよいです。

function isCampaignTarget(array $user): bool
{
    return $user['age'] >= 20
        && $user['status'] === 'active'
        && $user['email_verified'] === true;
}

$result = array_filter($users, 'isCampaignTarget');

関数名があることで、「キャンペーン対象者を判定している」という意味が伝わりやすくなります。

アロー関数は複数文に向かない

アロー関数は1つの式を返すための構文です。

次のような複数文の処理は書けません。

// 誤り
$formatName = fn ($name) => {
    $trimmed = trim($name);
    return mb_strtoupper($trimmed);
};

この場合は、無名関数を使います。

$formatName = function ($name) {
    $trimmed = trim($name);
    return mb_strtoupper($trimmed);
};

短い処理はアロー関数、複数行の処理は無名関数、と覚えておくとよいです。

外側の変数を変更する処理は慎重に使う

無名関数では、参照渡しを使うことで外側の変数を変更できます。

$count = 0;

$increment = function () use (&$count) {
    $count++;
};

ただし、外側の変数を関数内で変更すると、副作用が増えます。

副作用が多いコードは、あとから読んだときに「どこで値が変わったのか」が分かりにくくなります。

そのため、外側の変数を変更する設計は必要最小限にしたほうがよいです。

セミコロンを忘れない

無名関数やアロー関数を変数に代入する場合、最後にセミコロンが必要です。

$double = function ($num) {
    return $num * 2;
};

アロー関数でも同じです。

$double = fn ($num) => $num * 2;

通常の関数定義とは違い、変数への代入文なので、最後の ; を忘れないようにしましょう。

実務での使い分け

1行で終わる処理はアロー関数

単純な変換や判定であれば、アロー関数が向いています。

$names = array_map(fn ($user) => $user['name'], $users);
$adults = array_filter($users, fn ($user) => $user['age'] >= 20);
$pricesWithTax = array_map(fn ($price) => $price * 1.1, $prices);

このように、1行で意味が分かる処理なら、アロー関数を使うとコードがすっきりします。

複数行の処理は無名関数

途中で変数を作ったり、複数の処理を行ったりする場合は、無名関数が向いています。

$formattedUsers = array_map(function ($user) {
    $name = trim($user['name']);
    $age = (int) $user['age'];

    return "{$name}({$age}歳)";
}, $users);

アロー関数で無理に短く書くよりも、無名関数で複数行に分けたほうが読みやすくなります。

意味のある処理は名前付き関数やメソッド

ビジネスロジックとして意味がある処理は、ラムダ式ではなく、名前付き関数やメソッドに切り出すのがおすすめです。

class UserService
{
    public function isCampaignTarget(array $user): bool
    {
        return $user['age'] >= 20
            && $user['status'] === 'active'
            && $user['email_verified'] === true;
    }

    public function filterCampaignTargets(array $users): array
    {
        return array_filter($users, [$this, 'isCampaignTarget']);
    }
}

isCampaignTarget() という名前があることで、処理の意味が明確になります。

ラムダ式は便利ですが、処理の意味を名前で表したほうが分かりやすい場面では、メソッド化したほうが保守しやすくなります。

ラムダ式の実用例

ユーザー名だけを取り出す

$users = [
    ['id' => 1, 'name' => '田中'],
    ['id' => 2, 'name' => '佐藤'],
    ['id' => 3, 'name' => '鈴木'],
];

$names = array_map(fn ($user) => $user['name'], $users);

print_r($names);

出力は次のようになります。

Array
(
    [0] => 田中
    [1] => 佐藤
    [2] => 鈴木
)

20歳以上のユーザーだけを抽出する

$users = [
    ['name' => '田中', 'age' => 25],
    ['name' => '佐藤', 'age' => 17],
    ['name' => '鈴木', 'age' => 32],
];

$adults = array_values(
    array_filter($users, fn ($user) => $user['age'] >= 20)
);

print_r($adults);

array_filter() はキーを保持するため、必要に応じて array_values() で連番にしています。

金額を税込価格に変換する

$prices = [1000, 2000, 3000];
$taxRate = 1.1;

$pricesWithTax = array_map(fn ($price) => $price * $taxRate, $prices);

print_r($pricesWithTax);

出力は次のようになります。

Array
(
    [0] => 1100
    [1] => 2200
    [2] => 3300
)

アロー関数では外側の $taxRate を自動で使えるため、短く書けます。

バリデーションルールを定義する

$validators = [
    'name' => fn ($value) => $value !== '',
    'email' => fn ($value) => filter_var($value, FILTER_VALIDATE_EMAIL) !== false,
    'age' => fn ($value) => $value >= 20,
];

$data = [
    'name' => '田中',
    'email' => 'tanaka@example.com',
    'age' => 25,
];

foreach ($validators as $field => $validator) {
    if (!$validator($data[$field])) {
        echo "{$field} が不正です";
    }
}

このように、項目ごとのチェック処理を関数として持たせることもできます。

よくある間違い

useを書き忘れる

無名関数で外側の変数を使うときは、use が必要です。

$tax = 1.1;

$calc = function ($price) {
    return $price * $tax;
};

このコードでは、無名関数の中で $tax が未定義変数として扱われます。

正しくは次のように書きます。

$tax = 1.1;

$calc = function ($price) use ($tax) {
    return $price * $tax;
};

アロー関数なら、use を書かずに外側の変数を使えます。

$tax = 1.1;

$calc = fn ($price) => $price * $tax;

array_mapとarray_filterの引数順を混同する

array_map()array_filter() は、どちらもコールバックを使いますが、引数の順番が違います。

array_map() は、先にコールバックを書きます。

$result = array_map(fn ($num) => $num * 2, $numbers);

array_filter() は、先に配列を書きます。

$result = array_filter($numbers, fn ($num) => $num % 2 === 0);

この違いは間違えやすいので注意しましょう。

アロー関数で複数文を書こうとする

アロー関数では、複数文をそのまま書くことはできません。

// 誤り
$func = fn ($x) => {
    $y = $x * 2;
    return $y;
};

複数行の処理を書きたい場合は、無名関数を使います。

$func = function ($x) {
    $y = $x * 2;
    return $y;
};

array_filterのキー保持を忘れる

array_filter() は、元の配列のキーを保持します。

$numbers = [1, 2, 3, 4];

$result = array_filter($numbers, fn ($num) => $num % 2 === 0);

print_r($result);

結果は次のようになります。

Array
(
    [1] => 2
    [3] => 4
)

連番の配列にしたい場合は、array_values() を使います。

$result = array_values(
    array_filter($numbers, fn ($num) => $num % 2 === 0)
);

PHPのラムダ式を使うときの考え方

短い処理に向いている

ラムダ式は、短い処理をその場で書くのに向いています。

$ids = array_map(fn ($user) => $user['id'], $users);
$activeUsers = array_filter($users, fn ($user) => $user['active']);

このように、処理内容が一目で分かる場合は、ラムダ式を使うとコードが読みやすくなります。

複雑な処理は切り出す

一方で、複雑な条件や長い処理をラムダ式に詰め込むと、読みにくくなります。

$targets = array_filter($users, fn ($user) => $user['age'] >= 20 && $user['status'] === 'active' && $user['email_verified'] && $user['last_login'] >= '2026-01-01');

このような場合は、次のようにメソッド化したほうが分かりやすいです。

function isTargetUser(array $user): bool
{
    return $user['age'] >= 20
        && $user['status'] === 'active'
        && $user['email_verified']
        && $user['last_login'] >= '2026-01-01';
}

$targets = array_filter($users, 'isTargetUser');

ラムダ式は便利ですが、コードの読みやすさを優先することが大切です。

まとめ

PHPのラムダ式は無名関数やアロー関数を指す

PHPで「ラムダ式」と呼ばれるものは、主に無名関数やアロー関数です。

無名関数は、名前を持たない関数です。

$double = function ($num) {
    return $num * 2;
};

アロー関数は、無名関数を短く書ける構文です。

$double = fn ($num) => $num * 2;

どちらも、配列処理やコールバック処理でよく使われます。

無名関数ではuseを使って外側の変数を取り込む

通常の無名関数では、外側の変数をそのまま使えません。

$tax = 1.1;

$calc = function ($price) use ($tax) {
    return $price * $tax;
};

外側の変数を使うには、use を使って明示的に取り込みます。

外側の変数を変更したい場合は、参照渡しを使います。

$count = 0;

$increment = function () use (&$count) {
    $count++;
};

アロー関数は短い処理に向いている

アロー関数は、1行で書ける短い処理に向いています。

$names = array_map(fn ($user) => $user['name'], $users);

外側の変数を自動で使えるため、シンプルな配列処理では非常に便利です。

$minAge = 20;

$adults = array_filter($users, fn ($user) => $user['age'] >= $minAge);

ただし、アロー関数は基本的に1つの式を返すための構文です。

複数行の処理や複雑な条件には、無名関数や名前付き関数を使ったほうが読みやすくなります。

実務では使い分けが重要

PHPのラムダ式は、短く書ける便利な構文です。

ただし、何でもラムダ式にすればよいわけではありません。

場面おすすめ
1行で終わる単純な変換・判定アロー関数
複数行の処理無名関数
外側の変数を参照渡しで変更したい無名関数
ビジネス上の意味がある処理名前付き関数・メソッド

実務では、次のように考えるとよいです。

短い処理はアロー関数、複数行の処理は無名関数、意味のある処理は名前付き関数やメソッドに切り出す。

この使い分けができると、PHPの配列処理やコールバック処理を、読みやすく保守しやすい形で書けるようになります。

以上、PHPのラムダ式についてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次