> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# 컬렉션의 고차 메시지

> 컬렉션의 고차 메시지(Higher-order Messages) 구조와 실전적인 사용법

## 고차 메시지란

고차 메시지(Higher-order Messages)는 컬렉션의 메서드를 프로퍼티 접근 형태로 호출하는 구문입니다. 콜백을 작성하지 않고도, 각 요소에 대해 메서드를 호출하거나 프로퍼티를 가져올 수 있습니다.

```php theme={null}
// 通常の書き方
$names = $users->map(fn ($user) => $user->name);

// 高階メッセージを使った書き方
$names = $users->map->name;
```

`$users->map->name`은 "각 유저의 `name` 프로퍼티를 꺼내 `map`한다"는 의미가 됩니다.

## 구조 — HigherOrderCollectionProxy

`$collection->map`과 같이 프로퍼티로 접근하면, `EnumeratesValues` 트레이트의 `__get()`이 호출됩니다.

```php theme={null}
// 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()`이 호출됩니다.

```php theme={null}
// 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`은 다음과 동일합니다.

```php theme={null}
$users->map(fn ($user) => $user->name);
```

### \_\_call에 의한 메서드 호출 프록시

이어서 메서드를 호출(`->activate()`)하면 프록시의 `__call()`이 호출됩니다.

```php theme={null}
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()`는 다음과 동일합니다.

```php theme={null}
$users->each(fn ($user) => $user->activate());
```

## 대응하는 메서드 목록

고차 메시지로 사용할 수 있는 메서드는 `$proxies` 배열로 정의되어 있습니다.

```php theme={null}
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()`를 사용합니다.

```php theme={null}
Collection::proxy('myCustomMethod');
```

## 실전적인 유스케이스

### Eloquent 모델의 컬렉션

고차 메시지는 Eloquent의 컬렉션에서 특히 편리합니다.

```php theme={null}
$users = User::with('posts')->get();

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

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

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

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

### 필터링

```php theme={null}
$activeUsers = $users->filter->isActive();

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

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

### 집계

```php theme={null}
// 各ユーザーのpost_countプロパティで合計
$totalPosts = $users->sum->post_count;

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

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

### 그룹화·정렬

```php theme={null}
// role プロパティでグループ化
$grouped = $users->groupBy->role;

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

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

### flatMap으로 중첩 펼치기

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

### 조건 확인

```php theme={null}
// 全員が管理者か確認
$allAdmins = $users->every->isAdmin();

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

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

### 문자열 컬렉션

값이 문자열인 컬렉션에서도 사용할 수 있습니다. 프록시의 `__call()`은 문자열인 경우 정적 메서드로서 호출합니다.

```php theme={null}
$names = collect(['alice', 'bob', 'charlie']);

// 文字列コレクションに対してはクロージャの方が明示的
$upper = $names->map(fn ($name) => strtoupper($name));
// ['ALICE', 'BOB', 'CHARLIE']
```

<Info>
  문자열 컬렉션에 대한 고차 메시지는, 메서드가 문자열 타입에 정적으로 정의되어 있어야 합니다. 일반적으로 Eloquent 모델이나 자체 클래스의 컬렉션에서 사용하는 것이 자연스럽습니다.
</Info>

## 일반 클로저와의 비교

고차 메시지는 간결하지만, 모든 경우에 사용할 수 있는 것은 아닙니다.

```php theme={null}
// 高階メッセージ: シンプルなプロパティ取得・メソッド呼び出しに適する
$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;
});
```

<Tip>
  "각 요소의 같은 프로퍼티를 꺼낸다", "각 요소의 같은 메서드를 호출한다"의 경우에는 고차 메시지가 읽기 쉬워집니다. 조건이 복잡하거나 인수가 동적인 경우에는 클로저를 사용합니다.
</Tip>

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

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

```php theme={null}
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');
    }
}
```

```php theme={null}
// 登録後は高階メッセージとして使える
$activeUsers = $users->active;
```

## 다음 단계

<Card title="Conditionable 트레이트" icon="git-branch" href="/ko/advanced/conditionable">
  `when()` / `unless()`의 내부 구현과, QueryBuilder나 자체 클래스에의 적용 방법을 배웁니다.
</Card>


## Related topics

- [Collection Deep Dive](/ko/advanced/collection-deep-dive.md)
- [Conditionable 트레이트](/ko/advanced/conditionable.md)
- [컬렉션](/ko/collections.md)
- [Eloquent 컬렉션](/ko/eloquent-collections.md)
- [헬퍼 함수](/ko/helpers.md)
