どうしてこんな簡単な事に今まで気づかなかったのだろう...
変数から変数名を取得しようとする場合、変数名はすでにわかっているものなので、逆に、
変数名から変数を取得してもいいのです。
動機
PHP デバッグ時、「変数名・値」の対応表を出力したいことがあります。
変数が少ない時は、
echo '$変数名1 = '.$変数名1;
echo '$変数名2 = '.$変数名2;
で十分なのですが、
「多くの変数を、いろんな場所で、どのように変化しているかチェックしたい」
「時々、変数のリストを変更したい(増やしたい)」
「チェックのための行が長すぎるのは嫌!」
そうなってくると、たくさんの場所で、
「変数の配列をユーザー関数で処理したい」
というニーズが出てきます。
ところが、ユーザー関数の内部では「スコープが異なる」ため、ユーザー関数の外部の変数を内部で直接扱う事はできません。「ユーザー関数に(引数として)変数を引き渡す」という作業が必要になります。
しかし、
「変数から変数名を取得する」のはなかなか大変なようです。そこで発想を転換し、
「変数名から変数を取得する」ことにしました。これなら get_defined_vars() を使って、割と簡単にできます。
get_defined_vars()
get_defined_vars() は、それが呼ばれた時点のスコープの全変数を格納した配列を返します。仮に、その配列を$gdv
とすると、変数名→値($gdv[変数名]
)への変換が可能になります。
この関数と変数名をユーザー関数の引数として渡せば、ユーザー関数のスコープの中でも外部の
(訂正前)変数を扱えるようになります。(ユーザー関数に、変数名と変数を同時に渡す事に成功)
(訂正後)変数の値を取得できるようになります。(ユーザー関数に、変数名とその値を同時に渡す事に成功)
変数をチェックしたい場合、変数名は初めからわかっているはずなので、
チェックしたい変数名を、初めからリスト(配列)化しておくことができます。
もし仮に、変数名をプログラムで組み立てている場合は、組み立てられた変数名が何かの変数に格納されているはずなので、それをリストに加えるようにします。
そのリスト(配列)を下記のユーザー関数に渡すと、変数名と値の対応表(HTMLの table 要素)が返されます。
なお、変数名のリスト(配列)はスクリプトの最初の方で変数(リスト変数)に定義しておき、各変数をチェックしたいそれぞれの場所では、ユーザー関数にリスト変数を引き渡すようにします。そうすると、全ての変数名リストを(1か所で)簡単に更新することができるようになります。
使用例
/*
* get_value_table()
* 変数名の配列を、「変数名 | 値」の表に変換する
* $table = get_value_table($name_array, get_defined_vars());
* 第1引数には、チェックしたい変数名の配列を指定する
* 第2引数には、必ず get_defined_vars() を指定する
* 第3引数に false を指定すれば、「未定義(undefined)」を非表示にする
* 第4引数には、table 要素の属性を指定する
* 第5引数には、td 要素の属性を指定する
*/
function get_value_table($name_array, $gdv, $show_undefined = true, $table_attr = 'border=1', $td_attr = 'style="padding:0.3em"') {
$name_value_table = [];
foreach ($name_array as $name) :
if (!array_key_exists($name, $gdv)) :
if ($show_undefined===true) :
$value = '未定義(undefined)';
else :
continue;
endif;
elseif (is_bool($gdv[$name])) :
$value = $gdv[$name]? 'true' : 'false';
elseif (is_numeric($gdv[$name]) || is_string($gdv[$name])) :
$value = $gdv[$name];
elseif (is_array($gdv[$name])) :
$value = '<pre>'.print_r($gdv[$name],true).'</pre>';
else :
$value = (PHP_VERSION_ID >= 80000)? get_debug_type($gdv[$name]) : get_type($gdv[$name]);
endif;
$name_value_table[] = '<tr><td '.$td_attr.'>$'.$name.'<td '.$td_attr.'>'.$value;
endforeach;
return '<table '.$table_attr.'>'.implode("\n", $name_value_table).'</table>';
} // (f) get_value_table()
# 例
# 変数の定義
$_1 = 'some value';
$_2 = 'next value';
$_3 = [1,2,3];
class MyClass{}
$_4 = new MyClass();
$_5 = false;
$_6 = null;
$name_array = ["_1", "_2", "_3", "_4", "_5", "_6", "_7"]; // 変数名の配列(リスト変数)
echo get_value_table($name_array, get_defined_vars()); // 「変数名・値」の表を表示
結果
下記のような表が表示されます。
| $_1
| some value |
| $_2
| next value |
| $_3
| Array |
| | ( |
| | [0] => 1 |
| | [1] => 2 |
| | [2] => 3 |
| | ) |
| $_4
| MyClass |
| $_5
| false |
| $_6
| null |
| $_7
| 未定義(undefined)|