複数の変数をまとめて配列にしたい、逆に配列の各要素を変数として取り出したい——そんなときに便利なのが PHP の compact() と extract() です。compact() は変数名を指定するだけで「変数名をキー、値を値」とした配列を作り、extract() は配列のキーをそのまま変数名にして展開します。テンプレートにデータを渡す場面などでよく使われます。この記事では、2つの関数の使い方と典型的な用途、extract() を使うときの注意点まで、コード例で初心者の方にも分かるように解説します。
目次
compact と extract の関係
この2つは、ちょうど逆の働きをする関数です。compact() は「変数 → 配列」、extract() は「配列 → 変数」という変換を行います。まずは対応関係を整理しておきましょう。
| 関数 | 変換の向き | 引数 |
|---|---|---|
compact() | 変数 → 連想配列 | 変数名(文字列) |
extract() | 連想配列 → 変数 | 配列 |
compact() で変数を配列にまとめる
compact() は、引数に変数名を文字列で渡すと、その変数名をキー、変数の値を値とした連想配列を作って返します。$ は付けず、変数名だけを文字列で書くのがポイントです。
<?php
$name = "山田";
$age = 30;
$email = "yamada@example.com";
// 変数名を文字列で渡す($ は付けない)
$data = compact("name", "age", "email");
// $data は次の連想配列になる
// [ "name" => "山田", "age" => 30, "email" => "yamada@example.com" ]
同じ内容を $data = ["name" => $name, "age" => $age, ...] と書くこともできますが、変数名とキー名が同じなら compact() の方がずっと簡潔です。とくに、関数やテンプレートに複数の値をまとめて渡したいときに重宝します。
extract() で配列を変数に展開する
extract() は compact() の逆で、連想配列のキーを変数名にして、それぞれの値を変数として作り出します。$data["name"] のように毎回キーで取り出すのが面倒なとき、一度展開しておくと $name として直接使えるようになります。
<?php
$data = [
"name" => "山田",
"age" => 30,
];
extract($data); // キーを変数名にして展開
echo $name; // "山田"
echo $age; // 30
テンプレートにデータを渡す
この2つが活躍する代表例が、テンプレートの読み込みです。データを compact() で配列にまとめて関数に渡し、テンプレート側で extract() して使う、という流れがよく使われます。呼び出し側はまとめて渡せて、テンプレート側は短い変数名で書けるのが利点です。
<?php
function render($template, array $vars) {
extract($vars); // 配列を変数に展開
include $template; // テンプレート内で $title などが使える
}
$title = "お知らせ";
$body = "本日は晴天なり";
// compact でまとめて渡す
render("notice.php", compact("title", "body"));
<h1><?php echo htmlspecialchars($title); ?></h1>
<p><?php echo htmlspecialchars($body); ?></p>
extract() を使うときの注意点
ユーザー入力をそのまま展開しない
extract() でもっとも気をつけたいのが、$_GET や $_POST など外部から来た配列をそのまま展開しないことです。配列のキーがそのまま変数名になるため、攻撃者が任意の変数名を送り込めてしまい、既存の変数を上書きされる危険があります。外部入力は extract() に渡さず、必要な値だけをキー指定で取り出すようにしましょう。
既存の変数が上書きされる
extract() は既定で、同じ名前の変数があると上書きします。意図せず大切な変数が書き換わるのを防ぐには、第2引数にフラグを渡します。EXTR_SKIP を指定すると、すでに存在する変数は上書きせずスキップします。
<?php
$name = "既存の値";
$data = ["name" => "新しい値"];
// 既存の変数は上書きしない
extract($data, EXTR_SKIP);
echo $name; // "既存の値"(スキップされた)
どの変数が作られるか分かりにくくなるため、extract() の使いすぎはコードの読みにくさにつながります。利用するのは、テンプレートの読み込みのように役割がはっきりした場所に限定し、配列のキーが信頼できる場合だけにするのが安全です。
compact で値が入らないとき
compact() で期待したキーが配列に入らないときは、存在しない変数名を指定していることがほとんどです。compact() は、まだ定義されていない変数名を渡してもエラーを出さずに、その項目を黙って無視します。スペルミスや、変数を定義する前に compact() を呼んでいないか確認しましょう。
また、変数名は必ず文字列で渡します。compact($name) のように $ を付けて変数そのものを渡すと、変数名ではなく値が引数になってしまい、意図どおりに動きません。compact("name") と書くのが正解です。
まとめ
compact() と extract() は、変数と配列を相互に変換する便利な関数です。要点を整理します。
compact("a", "b")は変数を連想配列にまとめる(変数名がキー)。$は付けない。extract($arr)は配列のキーを変数名にして展開する。- テンプレートへ「まとめて渡す → 展開して使う」流れで相性がよい。
extract()に$_GETなどの外部入力をそのまま渡さない。- 上書きを防ぐには
extract($arr, EXTR_SKIP)を使う。
変数名とキー名をそろえて compact() でまとめる書き方を覚えると、関数やテンプレートへの値の受け渡しがすっきりします。extract() は便利な反面リスクもあるので、信頼できるデータに限って使うようにしましょう。