메인 콘텐츠로 건너뛰기

고차 메시지란

고차 메시지(Higher-order Messages)는 컬렉션의 메서드를 프로퍼티 접근 형태로 호출하는 구문입니다. 콜백을 작성하지 않고도, 각 요소에 대해 메서드를 호출하거나 프로퍼티를 가져올 수 있습니다.
// 通常の書き方
$names = $users->map(fn ($user) => $user->name);

// 高階メッセージを使った書き方
$names = $users->map->name;
$users->map->name은 “각 유저의 name 프로퍼티를 꺼내 map한다”는 의미가 됩니다.

구조 — HigherOrderCollectionProxy

$collection->map과 같이 프로퍼티로 접근하면, EnumeratesValues 트레이트의 __get()이 호출됩니다.
// src/Illuminate/Collections/Traits/EnumeratesValues.php
public function __get($key)
{
    if (! in_array($key, static::$proxies)) {
        throw new Exception("Property [{$key}] does not exist on this collection instance.");
    }

    return new HigherOrderCollectionProxy($this, $key);
}
$proxies에 포함된 메서드명인 경우, HigherOrderCollectionProxy 인스턴스가 반환됩니다. 이 프록시는 컬렉션과 메서드명 두 가지를 보관합니다.

__get에 의한 프로퍼티 접근 프록시

이어서 프로퍼티에 접근(->name)하면 프록시의 __get()이 호출됩니다.
// src/Illuminate/Collections/HigherOrderCollectionProxy.php
public function __get($key)
{
    return $this->collection->{$this->method}(function ($value) use ($key) {
        return is_array($value) ? $value[$key] : $value->{$key};
    });
}
$users->map->name은 다음과 동일합니다.
$users->map(fn ($user) => $user->name);

__call에 의한 메서드 호출 프록시

이어서 메서드를 호출(->activate())하면 프록시의 __call()이 호출됩니다.
public function __call($method, $parameters)
{
    return $this->collection->{$this->method}(function ($value) use ($method, $parameters) {
        return is_string($value)
            ? $value::{$method}(...$parameters)
            : $value->{$method}(...$parameters);
    });
}
$users->each->activate()는 다음과 동일합니다.
$users->each(fn ($user) => $user->activate());

대응하는 메서드 목록

고차 메시지로 사용할 수 있는 메서드는 $proxies 배열로 정의되어 있습니다.
protected static $proxies = [
    'average', 'avg',
    'contains', 'doesntContain', 'some',
    'each', 'every',
    'filter', 'reject',
    'first', 'last',
    'flatMap', 'map',
    'groupBy', 'keyBy',
    'hasMany', 'hasSole',
    'max', 'min', 'sum', 'percentage',
    'partition',
    'skipUntil', 'skipWhile',
    'sortBy', 'sortByDesc',
    'takeUntil', 'takeWhile',
    'unique',
    'unless', 'until', 'when',
];
커스텀 메서드를 추가하려면 Collection::proxy()를 사용합니다.
Collection::proxy('myCustomMethod');

실전적인 유스케이스

Eloquent 모델의 컬렉션

고차 메시지는 Eloquent의 컬렉션에서 특히 편리합니다.
$users = User::with('posts')->get();

// メソッド呼び出し: 各ユーザーのステータスを更新
$users->each->markAsVerified();

// プロパティアクセス: 名前だけ取り出す
$names = $users->map->name;

// メソッドに引数を渡す
$users->each->sendPasswordReset('ja');

// メール送信
$users->each->notify(new WelcomeNotification);

필터링

$activeUsers = $users->filter->isActive();

// isActive() が true を返すユーザーだけ残す
// $users->filter(fn ($user) => $user->isActive()) と同等

$inactiveUsers = $users->reject->isActive();

집계

// 各ユーザーのpost_countプロパティで合計
$totalPosts = $users->sum->post_count;

// 各ユーザーのscoreで最大値
$highestScore = $users->max->score;

// 各ユーザーのageで平均
$averageAge = $users->avg->age;

그룹화·정렬

// role プロパティでグループ化
$grouped = $users->groupBy->role;

// name プロパティで昇順ソート
$sorted = $users->sortBy->name;

// created_at プロパティで降順ソート
$sorted = $users->sortByDesc->created_at;

flatMap으로 중첩 펼치기

// 各ユーザーの posts リレーションを展開して1つのコレクションにする
$posts = $users->flatMap->posts;

조건 확인

// 全員が管理者か確認
$allAdmins = $users->every->isAdmin();

// 1人でもアクティブがいるか確認
$hasActive = $users->contains->isActive();

// 全員が特定のプランか確認
$allPro = $users->every->hasPlan('pro');

문자열 컬렉션

값이 문자열인 컬렉션에서도 사용할 수 있습니다. 프록시의 __call()은 문자열인 경우 정적 메서드로서 호출합니다.
$names = collect(['alice', 'bob', 'charlie']);

// 文字列コレクションに対してはクロージャの方が明示的
$upper = $names->map(fn ($name) => strtoupper($name));
// ['ALICE', 'BOB', 'CHARLIE']
문자열 컬렉션에 대한 고차 메시지는, 메서드가 문자열 타입에 정적으로 정의되어 있어야 합니다. 일반적으로 Eloquent 모델이나 자체 클래스의 컬렉션에서 사용하는 것이 자연스럽습니다.

일반 클로저와의 비교

고차 메시지는 간결하지만, 모든 경우에 사용할 수 있는 것은 아닙니다.
// 高階メッセージ: シンプルなプロパティ取得・メソッド呼び出しに適する
$emails = $users->map->email;
$users->each->sendWelcomeMail();
$admins = $users->filter->isAdmin();

// クロージャ: 複雑なロジックや引数が必要なケースに適する
$formatted = $users->map(function ($user) {
    return "{$user->name} <{$user->email}>";
});

$filtered = $users->filter(function ($user) use ($minAge, $role) {
    return $user->age >= $minAge && $user->role === $role;
});
“각 요소의 같은 프로퍼티를 꺼낸다”, “각 요소의 같은 메서드를 호출한다”의 경우에는 고차 메시지가 읽기 쉬워집니다. 조건이 복잡하거나 인수가 동적인 경우에는 클로저를 사용합니다.

커스텀 클래스에서 고차 메시지 사용하기

EnumeratesValues 트레이트를 통해 HigherOrderCollectionProxy의 구조를 이용하려면, Collection::proxy()를 호출해 메서드를 프록시 대상에 추가합니다.
namespace App\Providers;

use Illuminate\Support\Collection;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        // カスタムマクロをプロキシ対象に追加
        Collection::macro('active', function () {
            return $this->filter(fn ($item) => $item->isActive());
        });

        Collection::proxy('active');
    }
}
// 登録後は高階メッセージとして使える
$activeUsers = $users->active;

다음 단계

Conditionable 트레이트

when() / unless()의 내부 구현과, QueryBuilder나 자체 클래스에의 적용 방법을 배웁니다.
마지막 수정일 2026년 7월 13일