せかいろぐ

ほぼ自分用備忘録

JavaScriptとPHPの無名関数内での変数の扱い

無名関数内で外側のスコープの変数へアクセスする時の違い(JavaScript, PHP 5.3以降)


JavaScriptでは、あるスコープ内で指定された変数が見つからない時、自動的に外側のスコープへ探しに行きます。
従って、以下のコードを実行すれば、

function test(){
	var hello = "Hello, world!";
	var myFunc = function(){
		console.log(hello);
	};
	myFunc();
}
test();

Hello, world!


このような結果が得られ、無名関数内から外側のスコープの変数にアクセスできていることがわかります。


しかし、これをPHPて同じように書いて実行すると、

<?php
function test(){
	$hello = "Hello, world!";
	$myFunc = function(){
		echo($hello);
	};
	$myFunc();
}
test();
?>

Notice: Undefined variable: hello in ...


$helloが見つからないと怒られます。
PHPの無名関数において外側のスコープの変数へアクセスするには、以下のようにuseを用います。

<?php
function test(){
	$hello = "Hello, world!";
	$myFunc = function() use ($hello){
		echo($hello);
	};
	$myFunc();
}
test();
?>

Hello, world!


次に、無名関数内で外側のスコープの変数の値を変更した場合について。
JavaScriptでは、

function test(){
	var x = 16;
	var square = function(){
		x = x*x;
	};
	square();
	console.log(x);
}
test();

256


このように、無名関数内での変更が外側のスコープでも反映されます。


しかし、これをPHPて同じように書いて実行すると、

<?php
function test(){
	$x = 16;
	$square = function() use ($x){
		$x = $x*$x;
	};
	$square();
	echo($x);
}
test();
?>

16


無名関数内で変数の値を変更しても、外側のスコープの変数の値は変わっていません。
このように、useで渡した変数はデフォルトで値渡しされるので、無名関数内で変数の値を変更する場合、変数名の前に&をつけて明示的に参照渡しします。

<?php
function test(){
	$x = 16;
	$square = function() use (&$x){
		$x = $x*$x;
	};
	$square();
	echo($x);
}
test();
?>

256


ただし、オブジェクトはデフォルトで参照渡しされるので、明示的に参照渡しする必要はありません。
(この辺りは通常の関数に変数を渡す時のルールと同じです)

<?php
function test(){
	$obj = new stdClass();
	$obj->x = 16;
	
	$square = function() use ($obj){
		$obj->x = $obj->x*$obj->x;
	};
	
	$square();
	echo($obj->x);
}
test();
?>

256