1
2

More than 3 years have passed since last update.

PHP 変数から変数名を取得する(PHP 変数名から変数を取得する)

Last updated at Posted at 2021-09-04

どうしてこんな簡単な事に今まで気づかなかったのだろう...
変数から変数名を取得しようとする場合、変数名はすでにわかっているものなので、逆に、
変数名から変数を取得してもいいのです。

動機

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)|

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2