PHPで数字の配列の中に偶数があるか?という判定用の関数を作成したいとする。
配列の中に偶数が一つでもあればtrue(真)を返すわけだから、
<?php function isEven($arr){ foreach($arr as $int){ if($int % 2 === 0) return true; } return false; }
このように偶数があった場合にreturn true;で終わらせたくなるけれども、本当にこれで良いのか?疑問が生じた。
何故疑問が生じたか?というと、PHPのVLDでforとforeachを比較するの記事で、
foreach.php
<?php $arr = range(1, 100000); foreach($arr as $i => $v){ //以後の処理は省略 }
$ php -d vld.active=1 -d vld.execute=0 /path/to/dir/foreach.php Finding entry points Branch analysis from position: 0 2 jumps found. (Code = 77) Position 1 = 6, Position 2 = 9 Branch analysis from position: 6 2 jumps found. (Code = 78) Position 1 = 7, Position 2 = 9 Branch analysis from position: 7 1 jumps found. (Code = 42) Position 1 = 6 Branch analysis from position: 6 Branch analysis from position: 9 1 jumps found. (Code = 62) Position 1 = -2 Branch analysis from position: 9 filename: /path/to/dir/foreach.php function name: (null) number of ops: 11 compiled vars: !0 = $arr, !1 = $v, !2 = $i line #* E I O op fetch ext return operands ------------------------------------------------------------------------------------- 2 0 E > INIT_FCALL 'range' 1 SEND_VAL 1 2 SEND_VAL 100000 3 DO_ICALL $3 4 ASSIGN !0, $3 3 5 > FE_RESET_R $5 !0, ->9 6 > > FE_FETCH_R ~6 $5, !1, ->9 7 > ASSIGN !2, ~6 8 > JMP ->6 9 > FE_FREE $5 6 10 > RETURN 1 branch: # 0; line: 2- 3; sop: 0; eop: 5; out0: 6; out1: 9 branch: # 6; line: 3- 3; sop: 6; eop: 6; out0: 7; out1: 9 branch: # 7; line: 3- 3; sop: 7; eop: 8; out0: 6 branch: # 9; line: 3- 6; sop: 9; eop: 10; out0: -2 path #1: 0, 6, 7, 6, 9, path #2: 0, 6, 9, path #3: 0, 9,
foreach文の処理の最後に、FE_FREEでforeach内で使用した変数を解放している(たぶん)。
であれば、冒頭のコードでforeachの最中でreturnで関数自体から抜けてしまったら、foreach内で余計なメモリの使用分が残ってしまうのではないか?
ということで調べてみることにした。
下記のようなコードを作成して、オペコードを調べてみた。
<?php function isEven($arr){ foreach($arr as $int){ if($int % 2 === 0) return true; } return false; } $array = array(3, 5, 2, 1, 7); if(isEven($array) ){ echo "is even"; }else{ echo "no even"; }
オペコードは下記の通り(isEven関数の処理のところだけピックアップ)
Function iseven: Finding entry points Branch analysis from position: 0 2 jumps found. (Code = 77) Position 1 = 2, Position 2 = 9 Branch analysis from position: 2 2 jumps found. (Code = 78) Position 1 = 3, Position 2 = 9 Branch analysis from position: 3 2 jumps found. (Code = 43) Position 1 = 6, Position 2 = 8 Branch analysis from position: 6 1 jumps found. (Code = 62) Position 1 = -2 Branch analysis from position: 8 1 jumps found. (Code = 42) Position 1 = 2 Branch analysis from position: 2 Branch analysis from position: 9 1 jumps found. (Code = 62) Position 1 = -2 Branch analysis from position: 9 filename: /path/to/dir/foreach.php function name: isEven number of ops: 12 compiled vars: !0 = $arr, !1 = $int line #* E I O op fetch ext return operands ------------------------------------------------------------------------------------- 2 0 E > RECV !0 3 1 > FE_RESET_R $2 !0, ->9 2 > > FE_FETCH_R $2, !1, ->9 4 3 > MOD ~3 !1, 2 4 IS_IDENTICAL ~4 ~3, 0 5 > JMPZ ~4, ->8 6 > FE_FREE $2 7 > RETURN <true> 3 8 > > JMP ->2 9 > FE_FREE $2 6 10 > RETURN <false> 7 11* > RETURN null branch: # 0; line: 2- 3; sop: 0; eop: 1; out0: 2; out1: 9 branch: # 2; line: 3- 3; sop: 2; eop: 2; out0: 3; out1: 9 branch: # 3; line: 4- 4; sop: 3; eop: 5; out0: 6; out1: 8 branch: # 6; line: 4- 4; sop: 6; eop: 7; out0: -2 branch: # 8; line: 3- 3; sop: 8; eop: 8; out0: 2 branch: # 9; line: 3- 7; sop: 9; eop: 11 path #1: 0, 2, 3, 6, path #2: 0, 2, 3, 8, 2, 9, path #3: 0, 2, 9, path #4: 0, 9, End of function iseven
なんとforeachの途中でreturn trueで抜ける箇所と、foreachを終えた時の二箇所にFE_FREEの命令があるではないか!
こういう細かい対応を見ると嬉しかったりする。