1. ホーム
  2. PHP

【PHP】compact と extract の使い方|変数と配列を相互に変換する方法

Share

複数の変数をまとめて配列にしたい、逆に配列の各要素を変数として取り出したい——そんなときに便利なのが PHP の compact()extract() です。compact() は変数名を指定するだけで「変数名をキー、値を値」とした配列を作り、extract() は配列のキーをそのまま変数名にして展開します。テンプレートにデータを渡す場面などでよく使われます。この記事では、2つの関数の使い方と典型的な用途、extract() を使うときの注意点まで、コード例で初心者の方にも分かるように解説します。

compact と extract の関係

この2つは、ちょうど逆の働きをする関数です。compact() は「変数 → 配列」、extract() は「配列 → 変数」という変換を行います。まずは対応関係を整理しておきましょう。

関数変換の向き引数
compact()変数 → 連想配列変数名(文字列)
extract()連想配列 → 変数配列

compact() で変数を配列にまとめる

compact() は、引数に変数名を文字列で渡すと、その変数名をキー、変数の値を値とした連想配列を作って返します。$ は付けず、変数名だけを文字列で書くのがポイントです。

compact.php
<?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 として直接使えるようになります。

extract.php
<?php
$data = [
    "name" => "山田",
    "age"  => 30,
];

extract($data); // キーを変数名にして展開

echo $name; // "山田"
echo $age;  // 30

テンプレートにデータを渡す

この2つが活躍する代表例が、テンプレートの読み込みです。データを compact() で配列にまとめて関数に渡し、テンプレート側で extract() して使う、という流れがよく使われます。呼び出し側はまとめて渡せて、テンプレート側は短い変数名で書けるのが利点です。

render.php
<?php
function render($template, array $vars) {
    extract($vars);        // 配列を変数に展開
    include $template;     // テンプレート内で $title などが使える
}

$title = "お知らせ";
$body  = "本日は晴天なり";

// compact でまとめて渡す
render("notice.php", compact("title", "body"));
notice.php
<h1><?php echo htmlspecialchars($title); ?></h1>
<p><?php echo htmlspecialchars($body); ?></p>

extract() を使うときの注意点

ユーザー入力をそのまま展開しない

extract() でもっとも気をつけたいのが、$_GET$_POST など外部から来た配列をそのまま展開しないことです。配列のキーがそのまま変数名になるため、攻撃者が任意の変数名を送り込めてしまい、既存の変数を上書きされる危険があります。外部入力は extract() に渡さず、必要な値だけをキー指定で取り出すようにしましょう。

既存の変数が上書きされる

extract() は既定で、同じ名前の変数があると上書きします。意図せず大切な変数が書き換わるのを防ぐには、第2引数にフラグを渡します。EXTR_SKIP を指定すると、すでに存在する変数は上書きせずスキップします。

extract.php
<?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() は便利な反面リスクもあるので、信頼できるデータに限って使うようにしましょう。

参考ページ