[PHP] compact, extractと変数のスコープ

2018年7月23日月曜日

PHP

[PHP] PHPオブジェクトと配列の変換まとめでは、オブジェクトと配列の変換を取り扱ったけど、スコープ内の変数を配列として取り出すにはどうすればいいか。

globalキーワード

その前にPHPでのスコープとグローバル変数の関係について。

PHPではローカル変数を宣言するためのキーワードはなく、逆にグローバル変数にアクセスするためのglobalキーワードが存在する。
関数内でグローバル変数にアクセスするためにはこんな感じにする。
$foo = 1;
function use_global() {
    global $foo;
    echo $foo .PHP_EOL;
}

use_global();
// 1

Cのように明示的な変数宣言が必要な言語に慣れていると逆な感じもするけど、4行目の$fooがローカル変数なのか、グローバル変数なのか、globalキーワードが存在しなければ区別がつかない。
グローバル変数よりもローカル変数の方がアクセスする機会が多いことを考えると、globalキーワードはそれなりに理にかなっている気がする。

http://php.net/manual/ja/language.variables.scope.php

get_defined_vars関数

get_defined_varsは現在のスコープの変数を配列にして返してくれる。関数内で呼べば、ローカル変数とglobalキーワードで参照しているグローバル変数を取得する。
$foo = 1;
function dump_vars() {
    global $foo;
    $bar = 2;
    $locals = get_defined_vars();
    var_dump($locals);}

dump_vars();
// array(2) {
//   ["foo"]=>
//   &int(1)
//   ["bar"]=>
//   int(2)
// }
http://php.net/manual/ja/function.get-defined-vars.php

compact関数

get_defined_varsはスコープ内の変数を全て配列に変換してくれたけど、特定の変数のみを取り込みたい場合はcompactを使う。

$foo = 1;
function compact_test() {
    global $foo;
    $bar = 2;
    $locals = compact('foo', 'bar');
    var_dump($locals);
}

compact_test();
// array(2) {
//   ["foo"]=>
//   int(1)
//   ["bar"]=>
//   int(2)
// }

ここで、get_defined_varsと異なり"foo"が参照ではなく、値になっていることがわかる。
なので、もしグローバル参照も全て値にした配列にしたければ、get_defined_varsの取得値のキーをcompactに渡せばいい。
$locals = compact(array_keys(get_defined_vars()));
http://php.net/manual/ja/function.compact.php

extract関数

逆に配列の値をスコープ内の変数として展開したい場合はextractを使う。
EXTR_OVERWRITEを指定すると、変数が存在する場合でも上書きする。
globalキーワードでグローバル変数を参照している場合は参照しているグローバル変数に展開する。
$foo = 0;
function extract_test() {
    global $foo;
    extract([ 'foo' => 1, 'bar' => 2 ], EXTR_OVERWRITE);
    echo $bar .PHP_EOL;
    // 2
}

extract_test();
echo $foo .PHP_EOL;
// 1
echo $bar .PHP_EOL;
// 出力なし
http://php.net/manual/ja/function.extract.php