PHPでは変数名に別の変数を使って表す「可変変数」というものがあり、これを使うと連番や配列を変数名にセットする等、複数の変数を動的に扱うことが可能になります。
そんな「可変変数」の使い方についてまとめてみたいと思います。
通常の変数と変数名
通常の変数名は「$var」のように$記号と任意の文字で構成されています。名付けた変数名を直接指定することで変数を扱うことができます。
$var = 'foods'; // 変数を定める
echo $var; // 変数を使う上の例では1行目で定めた変数$varを2行目のechoで直接指定して使っています。その結果、$varに格納されている文字列「foods」が表示されます。
実行結果
foods
変数名を別の変数で表すとは?
通常の変数を使って新たな変数を定める
$記号と任意の文字で構成される変数名ですが、「任意の文字」の箇所に別の変数を使うことができます。つまり$記号と変数を組み合わせて変数名に利用することができます。
これを可変変数といい「$$〇〇」のように書きます。


上の図では$strに格納されている文字列次第で$$strが示す内容が変わってきます。
可変変数の呼び出し方
解説用に「$foods, $drink, $fruits」の3つの変数を前もって用意しています。
6行目の可変変数では、変数名に5行目の変数$strが使われています。
$foods = 'meat'; // 解説用変数
$drink = 'water'; // 解説用変数
$fruits = 'apple'; // 解説用変数
$str = 'foods'; // 変数名に使う文字
echo $$str; // $strを変数名に利用した可変変数実行結果
meat
このまま実行すると$strには文字列「foods」が代入されているので$$strは$foodsを表していることになり、「meat」と表示されます。
5行目を$str = 'drink';と書き換えた場合、$$strは$drinkを表すことになり、「water」と表示されます。同様に$str = 'fruits';とすると「apple」と表示されます。
これが元の変数によって変数名が動的に可変する可変変数ということになります。
配列の場合はインデックスに注意
可変変数が配列であった場合はインデックスを指定する必要がありますが、$$str[1]と書いた場合インデックスが$strと$$strのどちらの[1]なのか曖昧になってしまいます。
つまり次の例では[1]が cars と fruit のどちらを指しているのか判別しかねるということです。
$str = [ 'foods', 'cars', 'tools' ];
$$str = [ 'meet', 'fruit', 'vegetable' ];
echo $$str[1]; // インデックスが曖昧この曖昧さを解消するために可変変数の命名に使う部分は{ }で括ることができます。
次の例では7行目のforeachの条件式で可変変数${$str[1]}を使っており、[1]が$strのインデックスであることが明示的になっています。
$cat_a = [ 'meet', 'fruit', 'vegetable' ];
$cat_b = [ 'red', 'blue', 'white' ];
$cat_c = [ 'win', 'mac', 'linux' ];
$str = [ 'cat_a', 'cat_b', 'cat_c' ];
foreach ( ${$str[1]} as $value ) { // { }で括ってインデックスが明示的になっている
echo $value . ' / ';
}結果はどうなるでしょうか。
{ }で括られた$str[1]は ‘cat_b’ という文字列を参照しています。
つまり${$str[1]}は$cat_bを表していることとなり、2行目の配列が書き出されます。
実行結果
red / blue / white /
参考リンク
php.net – 可変変数
可変変数の実用的な例
次は可変変数を効率的に利用する例を挙げてみたいと思います。
配列の中身をそれぞれ別の変数に代入する
$arrの中身を$dealer0, $dealer1, $dealer2というそれぞれ異なる連番付きの変数に代入します。
$arr = [ 'TOYOTA', 'MAZDA', 'GM' ];
$i = 0;
foreach ( $arr as $value ) {
${'dealer' . $i} = $value . ' / ';
$i++;
}
echo $dealer0;
echo $dealer1;
echo $dealer2;2行目:連番に使用する変数を用意しておきます。
3行目:配列の数ほどループで処理を行います。
4行目:ここで可変変数を使っています。ループ毎に$iの部分が異なる可変変数が用意され、$arrの中身を代入しています。
7~9行目:ループと可変変数で生成されたそれぞれの変数を表示します。
ループ内でecho ${"dealer".$i};として書き出すほうが効率的ですが、異なる3つの変数が作られたのを確認するため、7~9行目ではあえて1行づつ出力しています。
実行結果
TOYOTA / MAZDA / GM /
配列からそれぞれ新たな変数を作る
2つの配列からそれぞれ変数名と値の組み合わせを作ります。
$week_en = [ 'mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun' ];
$week_ja = [ '月', '火', '水', '木', '金', '土', '日' ];
for ( $i = 0; $i <= 7; $i++ ) {
if ( preg_match( '/^[a-zA-Z_]\w*$/', $week_en[ $i ] ) ) {
${$week_en[ $i ]} = $week_ja[ $i ];
echo ${$week_en[ $i ]};
}
}1行目:変数名とする配列を用意します。
2行目:代入する値の配列です。
3行目:2つの配列のインデックスがずれてはいけないのでforを使ってループします。
4行目:変数名にする文字列が英数アンダースコアであるかを正規表現でチェックしています。
5行目:配列の要素$week_en[$i]を使って可変変数${$week_en[$i]}を定義し、$week_ja[$i]を代入しています。ここで配列$week_enの中身がそのまま変数名になっています。
6行目:可変変数をechoしています。
結果:「月火水木金土日」と出力されます。
実行結果
月火水木金土日
まとめ
場合によっては可変変数を使わなくとも単純な配列操作で事足りてしまうと思いますが、あらかじめ決められた変数名が配列として用意されている場合などは可変変数が活躍するかもしれません──。
ちなみに安全のため、可変変数にする文字列は正規表現でのチェック推奨です。
最後まで読んでいただきありがとうございました。

