変数名を変数で表す可変変数とは【PHP】

PHPでは変数名に別の変数を使って表す「可変変数」というものがあり、これを使うと連番や配列を変数名にセットする等、複数の変数を動的に扱うことが可能になります。

そんな「可変変数」の基礎的なことについて解説してみたいと思います。

変数名を別の変数で表すとは?

まずは通常の変数をおさらい

$var = 'foods';
echo $var;

これは普通の変数です。”foods”という文字列が代入されているのでechoすると当然 foods と表示されます。

実行結果
foods
倉庫番
倉庫番

この “foodsという文字列が代入された変数 $var” を “別の変数名” に使いたい場合に可変変数を使用して実現できます。

通常の変数を使って新たな変数を定める

先程の “foodsという文字列が代入されている変数 $var” を使って新たな変数を定めたい場合は次のように書くことができます。

$var  = 'foods';     // 変数に文字列を代入
$$var = 'meet';      // 可変変数に文字列を代入

echo '可変変数 $$var の値は ' . $$var . " です。\n";
echo '可変変数が表す変数 $foods の値は ' . $foods . ' です。';
実行結果
可変変数 $$var の値は meet です。
変数 $foods の値は meet です

1行目で定めた変数$varを使って2行目で新たな変数を定めています。
2行目の変数名である$$var$$varで構成されており、このとき$varには文字列foodsが代入されているので$$var$foodsを表していることになります。

これが変数名が元の変数によって動的に可変する可変変数ということになります。

$$var$foodsを表しているためecho $foods;としても同じ結果になることが確認できます。

配列の場合はインデックスに注意

可変変数が配列であった場合はインデックスを指定する必要がありますが、$$var[1]と書いた場合インデックスが$varと$$varのどちらの[1]なのか曖昧になってしまいます。
つまり次の例では[1]が cars と fruit のどちらを指しているのか判別しかねるということです。

$var  = [ 'foods', 'cars', 'tools' ];
$$var = [ 'meet', 'fruit', 'vegetable' ];
echo $$var[1]; // インデックスが曖昧

この曖昧さを解消するために可変変数の命名に使う部分は{ }で括ることができます。
次の例では7行目のforeachの条件式で可変変数${$var[1]}を使っており、[1]$varのインデックスであることが明示的になっています。

$cat_a = [ 'meet', 'fruit', 'vegetable' ];
$cat_b = [ 'red', 'blue', 'white' ];
$cat_c = [ 'win', 'mac', 'linux' ];

$var   = [ 'cat_a', 'cat_b', 'cat_c' ];

foreach ( ${$var[1]} as $value ) { // { }で括ってインデックスが明示的になっている
	echo $value . ' / ';
}

結果はどうなるでしょうか。

{ }で括られた$var[1]は ‘cat_b’ という文字列を参照しています。
つまり${$var[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しています。
結果:「月火水木金土日」と出力されます。

実行結果
月火水木金土日

まとめ

場合によっては可変変数を使わなくとも単純な配列操作で事足りてしまうと思いますが、あらかじめ決められた変数名が配列として用意されている場合などは可変変数が活躍するかもしれません……
ちなみに安全のため、可変変数にする文字列は正規表現でのチェック推奨です。

タイトルとURLをコピーしました