前回のPHPのガベージコレクションを見るの記事で、PHPのガベージコレクションの基礎になる参照カウント法を見た。


<?php
$a = new stdClass();
$c = $b = $a;
xdebug_debug_zval('c');

というコードだと、各変数は

zend_ref

この図のような形になる。


このコードを見て、コンストラクトしたオブジェクトをすぐに他の変数に入れる事なんてあるのか?という疑問が速攻で湧いた。

色々と考えてみたら関数が当てはまるということで下記のようなコードを書いてみた。

/path/to/dir/ref.php

<?php
$a = new stdClass();

function f(stdClass $b){
	xdebug_debug_zval('b');
}

f($a);

PHPの関数実行時に値を渡して、関数内で値を受け取った変数をxdebug_debug_zvalで内容を確認してみたらどうなるのだろう?ということで試してみた。

$ php /path/to/dir/ref.php
b: (refcount=2, is_ref=0)=class stdClass {  }

関数内の変数のrefcountが2になっていた。

参照カウント法は関数実行時の値の取扱で重要であることがわかった。




もしかして、今回の内容を利用すれば、PHPのガベージコレクションを学ぶにXdebugを入れるの記事で記載した

関数内で使用した変数はどのタイミングでメモリを解放するのか?

もしくはPHPの関数内の変数の解放は手動で行わなければならないのか?

これらの疑問が解消されるのでは?ということで下記のコードを作成してみた。

/path/to/dir/ref.php

<?php
$a = new stdClass();

function f(stdClass $b){
	xdebug_debug_zval('b');
	return null;
}

$c = f($a);
xdebug_debug_zval('a');

実行後の結果は下記の通り

$ php /path/to/dir/ref.php
b: (refcount=2, is_ref=0)=class stdClass {  }
a: (refcount=1, is_ref=0)=class stdClass {  }

関数fに$aの値を渡し、関数内で$bが$aの値を受け取りつつ、何もせずに関数を終了する。

終了後に$aのrefcountを確認してみると、関数f内の$bの分のカウントがなくなっていた。

この結果からPHPは関数終了時に関数内の変数を解放する事がわかった。


細かい処理の関数の実行であれば、関数内の変数分のメモリについてはあまり意識しなくても良さそうだ。