Laravelのpluckメソッドは、コレクションやデータベースのクエリ結果から「特定のカラムやキーの値だけ」をすばやく抽出して新しいコレクションを作成する便利な機能です。フォームのセレクトボックス(プルダウンメニュー)用の[id => name]連想配列を作ったり、whereInクエリに渡すID一覧を抽出したりする際に日常的に使われます。
しかし、pluckには「メモリ上のCollectionで動くもの」と「DBクエリを発行するEloquent/クエリビルダで動くもの」の2種類が存在し、それぞれ実行場所やパフォーマンスへの影響が大きく異なります。また、「複数カラムを取得したいときはどうするのか?」「select()との違いは何か?」といった疑問を持つ方も少なくありません。
本記事では、Laravelのpluckメソッドの基本的な使い方から、Collection版とEloquent版の違い、実務で頻出する活用パターン、selectとの使い分け、複数カラム取得時の代替手法、さらにはLaravel 12で追加された最新機能(クロージャ対応)やよくある落とし穴まで、実際に動作するコード例とともに徹底解説します。
Laravelのpluckメソッドとは?(基本の仕組み)
pluck(プラック)は英語で「引き抜く」「摘み取る」を意味し、データ群の中から指定したキーの値だけを抜き出してフラットなコレクションを作成するメソッドです。戻り値は常にIlluminate\Support\Collectionインスタンスとなります。
基本構文
// 第1引数: 取得したい値のカラム名 / キー名
// 第2引数 (任意): 結果コレクションのキーとして使いたいカラム名 / キー名
$plucked = $target->pluck('value_column', 'key_column');
1. 単一カラムの値を抽出する(第1引数のみ)
第1引数にカラム名を指定すると、その値だけをフラットに並べたコレクションを取得できます。
use App\Models\User;
// 全ユーザーの名前一覧を取得
$names = User::pluck('name');
// 取得結果: ['山田太郎', '佐藤花子', '鈴木一郎']
// (Illuminate\Support\Collection インスタンス)
2. キーと値のペアを作成する(第2引数を指定)
第2引数を渡すと、そのカラムをキー、第1引数のカラムを値にした連想配列形式のコレクションが作成されます。引数の順番が「第1引数=値(Value)」「第2引数=キー(Key)」である点に注意してください。
use App\Models\User;
// id をキー、name を値にした連想コレクションを取得
$userList = User::pluck('name', 'id');
// 取得結果:
// [
// 1 => '山田太郎',
// 2 => '佐藤花子',
// 3 => '鈴木一郎',
// ]
Collectionのpluck vs Eloquent(クエリビルダ)のpluckの違い
pluckを使いこなす上で最も重要なのが、「コレクションに対するpluck」と「Eloquent/クエリビルダに対するpluck」の違いを理解することです。
| 比較項目 | Eloquent / クエリビルダの pluck | Collection の pluck |
|---|---|---|
| 実行対象 | データベース(SQLクエリ) | PHPのメモリ上(Collection) |
| 発行されるSQL | SELECT name, id FROM users |
(事前に全件/指定件数を取得した後の操作) |
| メモリ消費 | 非常に小さい(必要カラムのみ転送・生成) | 大きい(取得済みの全データがメモリに載る) |
| モデルインスタンス | 生成されない(生データのみ) | 生成済みのモデルや配列から抽出 |
| 主な利用シーン | DBから直接一覧やキーペアを取得する時 | APIレスポンスや既存コレクションを加工する時 |
Eloquent / クエリビルダの pluck(DBから直接取得)
Eloquentモデルやクエリビルダに対してpluck()を呼び出すと、内部でSQLのSELECT句が最適化され、指定した1〜2カラムのみを取得するSQLが即座に実行されます。
use App\Models\User;
// 発行されるSQL: select `email`, `id` from `users`
$emails = User::where('active', true)->pluck('email', 'id');
get()で全カラムを取得してから抽出するよりも、DBサーバーからの通信量・PHPのメモリ消費量・モデルオブジェクトの生成コストを大幅に削減できるため、大量のレコードから特定カラムだけを取り出したい場合は必ずクエリビルダ側のpluck()を使用しましょう。
なお、Eloquentの基本やクエリビルダとの関係についてはLaravel Eloquentとは?使い方の基本からリレーション・クエリビルダとの違いまで徹底解説でも詳しく解説しています。
Collectionの pluck(メモリ上のデータを加工)
すでにメモリ上にある配列やコレクション、外部APIのレスポンス配列などに対してcollect()->pluck()を実行する場合です。
use Illuminate\Support\Collection;
$items = collect([
['product_id' => 'prod-100', 'name' => 'デスク', 'price' => 15000],
['product_id' => 'prod-200', 'name' => 'オフィスチェア', 'price' => 28000],
]);
// product_id をキー、name を値として抽出
$products = $items->pluck('name', 'product_id');
// 結果: ['prod-100' => 'デスク', 'prod-200' => 'オフィスチェア']
Collection全体の基礎知識やその他の便利メソッドはLaravel Collectionとは?基本の使い方と主要メソッドを初心者向けに解説を参照してください。
実務でよく使うpluckの活用パターン
1. フォームのセレクトボックス(プルダウンメニュー)を作る
実務で最も頻出するのが、Bladeテンプレートの<select>要素に渡す選択肢データの作成です。
// app/Http/Controllers/PostController.php
namespace App\Http\Controllers;
use App\Models\Category;
use Illuminate\View\View;
class PostController extends Controller
{
public function create(): View
{
// [1 => 'ニュース', 2 => '技術ブログ', 3 => 'お知らせ'] の連想コレクション
$categories = Category::orderBy('display_order')->pluck('name', 'id');
return view('posts.create', compact('categories'));
}
}
Bladeテンプレート側では、@foreachで簡単に展開できます。
<!-- resources/views/posts/create.blade.php -->
<label for="category_id">カテゴリー</label>
<select name="category_id" id="category_id" class="form-control">
<option value="">選択してください</option>
@foreach ($categories as $id => $name)
<option value="{{ $id }}" {{ old('category_id') == $id ? 'selected' : '' }}>
{{ $name }}
</option>
@endforeach
</select>
2. whereInクエリの条件に使うIDリストを抽出する
複数のレコードをまとめて取得・更新する際、中間データからIDの一覧を抽出してwhereInに渡すパターンです。
use App\Models\Order;
use App\Models\OrderItem;
// 未発送の注文ID一覧を取得([101, 102, 105, ...])
$pendingOrderIds = Order::where('status', 'pending')->pluck('id');
// 未発送注文に含まれる全注文明細を取得
$orderItems = OrderItem::whereIn('order_id', $pendingOrderIds)->get();
whereInの効率的な使い方やインデックスの注意点についてはLaravel whereInの使い方完全ガイドで詳しく解説しています。
3. ネストされた配列・リレーションのドット記法アクセス
Collectionのpluckは、階層が深い多次元配列やオブジェクトに対してドット記法(.)でアクセスできます。
$users = collect([
['id' => 1, 'profile' => ['name' => '田中', 'city' => '東京']],
['id' => 2, 'profile' => ['name' => '鈴木', 'city' => '大阪']],
]);
// ドット記法でネストした値を取得
$cities = $users->pluck('profile.city', 'id');
// 結果: [1 => '東京', 2 => '大阪']
また、リレーション先が1対多(HasManyなど)で配列になっている場合でも、ワイルドカード(*)記法を使って深くネストされた値を抽出できます。
$authors = collect([
[
'name' => '夏目漱石',
'books' => [
['title' => 'こゝろ'],
['title' => '坊っちゃん'],
],
],
[
'name' => '太宰治',
'books' => [
['title' => '人間失格'],
['title' => '走れメロス'],
],
],
]);
// 各著者の全書籍タイトルを抽出
$titles = $authors->pluck('books.*.title');
// 結果:
// [
// ['こゝろ', '坊っちゃん'],
// ['人間失格', '走れメロス'],
// ]
4. 純粋なPHP配列に変換する(all / toArray)
pluck()の戻り値はCollectionインスタンスです。サードパーティ製ライブラリへの受け渡しや型定義の関係で純粋なPHPの配列(array)にしたい場合は、all()またはtoArray()をチェーンします。
// Collection から array に変換
$userIds = User::where('active', true)->pluck('id')->all();
// $userIds は純粋な配列: [1, 2, 3, 5, 8]
5. 【Laravel 12対応】クロージャ(Closure)による値・キーの動的変換
Laravel 12(12.20以降)では、Collectionのpluck()の第1引数・第2引数に無名関数(クロージャ)を渡せるようになりました。これにより、取得した値をその場で整形・結合することが極めてシンプルに書けます。
// Laravel 12.x 以降(Collection の pluck)
$users = User::all();
// フルネームを生成して [id => "姓 名 (部署)"] の形式を作成
$list = $users->pluck(
fn ($user) => "{$user->last_name} {$user->first_name} ({$user->department})",
'id'
);
// キー側もクロージャで指定可能
$formattedKeys = $users->pluck(
'email',
fn ($user) => "user_{$user->id}"
);
// 結果: ['user_1' => 'tanaka@example.com', 'user_2' => 'suzuki@example.com']
※なお、クロージャが渡せるのはメモリ上のCollectionに対するpluck()のみです。Eloquent/クエリビルダのUser::pluck(...)はSQLへ変換されるため、クロージャを直接渡すことはできません(DBクエリの場合は事前にget()でコレクションを取得するか、SQLのCONCATやmap()を使用します)。
pluckとselectの違い(使い分けの基準)
「特定のカラムだけを取り出す」という目的において、pluck()とselect()の使い分けに迷うことがあります。両者の違いを整理しましょう。
| 特徴 | pluck('name', 'id') |
select('id', 'name')->get() |
|---|---|---|
| 戻り値の構造 | 値だけのコレクション(フラットまたはキーペア)[1 => '田中', 2 => '鈴木'] |
モデルオブジェクトのコレクション[User(id:1, name:'田中'), User(id:2, ...)] |
| モデルの機能 | 使えない(生の値のみ) | 使える(アクセサ、リレーション、メソッド等) |
| 取得可能なカラム数 | 基本的に1カラム(+キー1カラム) | 複数カラムを自由に指定可能 |
| 後続クエリの追加 | 不可(終端メソッド) | 可能(whereやorderByを続けられる) |
使い分けの判断基準
pluck()を使うべき場合:プルダウンの選択肢用データ(id => name)や、IDリスト、集計用の単一数値リストなど、「値そのもの」だけが必要な場合。select()を使うべき場合:取得したデータに対してモデルのアクセサ($user->full_nameなど)やリレーションメソッドを使いたい場合、または3つ以上のカラムを保持したままレコードを扱いたい場合。
「複数カラム」を取得したい場合の代替手法
pluckは1カラム(またはキー+値の2カラム)の抽出に特化しているため、User::pluck('id', 'name', 'email')のように3つ以上のカラムを指定することはできません。複数カラムを抽出したい場合は、以下のいずれかの方法を採用します。
代替案1: select() + get() を使う(最も一般的)
Eloquentモデルのインスタンスとして複数カラムを取得します。
// 指定した複数カラムだけをDBから取得
$users = User::select('id', 'name', 'email')->get();
// 各要素は User モデルインスタンス(メモリ節約しつつアクセサ等も利用可能)
代替案2: map / mapWithKeys でカスタム連想配列を作成する
3つ以上のカラムを独自の構造に整形したい場合は、get()の後にmapメソッドやmapWithKeysを使用します。
$userData = User::select('id', 'first_name', 'last_name', 'email')
->get()
->map(function ($user) {
return [
'id' => $user->id,
'full_name' => "{$user->last_name} {$user->first_name}",
'email' => $user->email,
];
});
代替案3: only() で特定キーのみに絞り込む
すでに取得済みのコレクションから複数キーだけを残したい場合は、onlyメソッドを組み合わせます。
$users = User::all()->map->only(['id', 'name', 'email']);
pluckを使う際の注意点とよくある落とし穴
1. キーが重複すると「後勝ち」で上書きされる
第2引数に指定したキーカラムに重複する値が含まれている場合、最後に出現した要素の値で上書きされます。
$collection = collect([
['role' => 'developer', 'name' => '佐藤'],
['role' => 'developer', 'name' => '鈴木'], // キー 'developer' が重複
['role' => 'designer', 'name' => '高橋'],
]);
$plucked = $collection->pluck('name', 'role');
// 結果:
// [
// 'developer' => '鈴木', // '佐藤' は上書きされて消える!
// 'designer' => '高橋',
// ]
重複したキーの要素を失いたくない(グループごとに配列でまとめたい)場合は、pluck()ではなくgroupByメソッドを使用してください。
2. 存在しないキーを指定すると null が混入する
指定したキー名が配列やモデルに存在しない場合、エラーにはならずnullが格納されます。
$items = collect([
['id' => 1, 'name' => '商品A'],
['id' => 2], // 'name' キーが存在しない
]);
$names = $items->pluck('name');
// 結果: ['商品A', null]
// null を除去したい場合は filter() をチェーンする
$validNames = $items->pluck('name')->filter()->values();
// 結果: ['商品A']
3. ループ内でリレーションのpluckを呼ぶN+1問題
各ユーザーの投稿タイトル一覧を取得しようとして、ループ内でリレーションのpluck()を呼ぶと、反復ごとにSQLが発行されてN+1問題が発生します。
// NG: ユーザーの件数分だけ毎回クエリが発行される(N+1問題)
$users = User::all();
foreach ($users as $user) {
// 毎回 select `title` from `posts` where `posts`.`user_id` = ? が実行される
$postTitles = $user->posts()->pluck('title');
}
// OK: Eager Loading(with)で一括取得してからメモリ上でpluckする
$users = User::with('posts')->get();
foreach ($users as $user) {
// メモリ上のCollectionに対してpluckするため追加クエリはゼロ
$postTitles = $user->posts->pluck('title');
}
$user->posts()(メソッド呼び出し=クエリ発行)と$user->posts(プロパティ呼び出し=EagerロードされたCollection参照)の違いを意識しましょう。
4. 大量データ取得時のメモリ対策(lazy / chunk)
データベースのテーブルに数十万件〜数百万件のレコードがある場合、User::pluck('email')を実行すると、たとえ1カラムだけでも巨大な配列が一括でPHPメモリに展開され、Allowed memory size exhaustedエラーになるリスクがあります。
大量のデータを順次処理したい場合は、chunkやlazy() / cursor()と組み合わせるのが安全です。
// 大量データを小分けに処理する
User::orderBy('id')->chunk(1000, function ($users) {
$emails = $users->pluck('email');
// 1,000件ずつメール送信などの処理を実行
});
よくある質問(FAQ)
Q1. pluckした結果のキーを 0, 1, 2… の連番にリセットするには?
第2引数を指定してキー付けされたコレクションや、連想配列からpluckした結果をゼロ始まりの連番インデックスに戻したい場合は、values()メソッドをチェーンします。
$list = collect(['a' => 'りんご', 'b' => 'みかん']);
$names = $list->values(); // [0 => 'りんご', 1 => 'みかん']
Q2. Eloquentのpluckで重複する値を除外(一意に)できますか?
クエリビルダのdistinct()と組み合わせることで、SQLレベルで重複を排除した一意の値リストを取得できます。
// 発行されるSQL: select distinct `country` from `users`
$countries = User::distinct()->pluck('country');
Q3. リレーション先のカラムを直接クエリビルダのpluckで取得できますか?
Eloquentのpluck()でUser::pluck('posts.title')のように指定することはできません(ドット記法はSQL側ではテーブル結合を行わないため)。リレーション先のカラムをSQLレベルで取得したい場合は、join()で明示的にテーブルを結合するか、Eager Loading(with)で取得後にCollectionのpluck()を使用してください。
まとめ
Laravelのpluckメソッドは、指定したカラムやキーの値だけをピンポイントで取り出すための非常に強力で直感的なメソッドです。
- Eloquent/クエリビルダの
pluck():DBクエリで指定カラムのみを取得するため、メモリ消費と負荷を大幅に削減できる(User::pluck('name', 'id'))。 - Collectionの
pluck():メモリ上の配列やオブジェクトからドット記法やLaravel 12のクロージャを使って柔軟に値を抽出できる。 - セレクトボックスの作成:
pluck('value_column', 'key_column')の順序で[id => name]の連想配列を簡単に作成可能。 - 複数カラム取得やモデル操作:複数カラムが必要な場合は
select()->get()やmap()を使い分ける。
それぞれの特性を正しく理解し、フォーム作成やクエリ最適化にぜひpluckを活用してください。
