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の命令があるではないか!
こういう細かい対応を見ると嬉しかったりする。





