switch case の 型

PHPでもっともやってしまいがちな if,case文での変数型違いによる予想外の通過

プログラム組んでる最中に引っかかったのでなんとなく調べてみた。


今まで勘違いしてた点が2箇所あった・・
これはまずい、かなりまずい気がするけど見直すのは・・無理だ!
気づいたら直していこう・・。

勘違いしてたのは以下の2点

function case_string_1( $str )
{	
	switch( $str )
	{
		case '1':
			return '1';
			break;

		default:
			return "-";
			break;
	}
}
echo case_string_1( (int)1 );  // 1
echo case_string_1( (string)1 );  // 1

これで どちらも1が返ってくることは理解はしていた。
けれども

switch( (int)$str )

と、したときにどちらも defaultを通って 「-」が返ってくるものだと思い込んでいた。

この結果を見て気づいたが、考えてみれば比較してるのって「case」じゃないか!
でもって「case」自体が型見てないからキャスト意味ねぇ・・。

function case_if_AeqA( $str )
{	
	switch( $str )
	{
		case ( $str==="A" ):
			return '1';
			break;

		default:
			return "-";
			break;
	}
}
echo case_if_AeqA( 0 );  // 1
echo case_if_AeqA( 1 );  // -

case文での比較 括弧で括ればできるんだー とかなり昔に思ってたが違った模様
なんかやり方あるんだっけ・・

あ、そっか。
switchで投げたものと比較するんだから switchにはTRUEを入れないとだめなのか。

function case_if_AeqA( $str )
{	
	switch( TRUE )
	{
		case ( $str==="A" ):
			return '1';
			break;

		default:
			return "-";
			break;
	}
}
echo case_if_AeqA( 0 );  // -
echo case_if_AeqA( 1 );  // -
echo case_if_AeqA( 'A' );  // 1

できたできた。
でも、過去のプログラムやばい気がするな〜


色々な結果

関数トレース値返り値
case_int_0''0
NULL0
'0'0
00
'1''-'
1'-'
'1.5''-'
1.5'-'
false0
true'-'
'A'0
case_string_0'''-'
NULL'-'
'0''0'
0'0'
'1''-'
1'-'
'1.5''-'
1.5'-'
false'0'
true'-'
'A''-'
case_int_1'''-'
NULL'-'
'0''-'
0'-'
'1'1
11
'1.5''-'
1.5'-'
false'-'
true1
'A''-'
case_string_1'''-'
NULL'-'
'0''-'
0'-'
'1''1'
1'1'
'1.5''-'
1.5'-'
false'-'
true'1'
'A''-'
case_string_foo'''-'
NULL'-'
'0''-'
0'foo'
'1''-'
1'-'
'1.5''-'
1.5'-'
false'-'
true'foo'
'A''-'
case_if_0eq0'''-'
NULL'-'
'0''-'
0'( $str===0 )'
'1''-'
1'-'
'1.5''-'
1.5'-'
false'-'
true'-'
'A''-'
case_if_AeqA'''-'
NULL'-'
'0''-'
0'-'
'1''-'
1'-'
'1.5''-'
1.5'-'
false'-'
true'-'
'A''( $str==="A" )'
case_if_false'''( true )'
NULL'( true )'
'0''( true )'
0'( true )'
'1''( true )'
1'( true )'
'1.5''( true )'
1.5'( true )'
false'( true )'
true'( true )'
'A''( true )'





★以下 テストで使用したプログラム
とても適当すぎる。
気が向いたら整形しよう・・。

<?

function td( $str,$res ){
	$var['str'] = var_export($str,true);
	$var['res'] = var_export($res,true);
	$response = "";
	foreach( $var as $key=>$value ){
		if( $key == 'res' ){
			switch($value){
				case 'true':
					$color = '#bbdbf3';
					break;
				case 'false':
					$color = 'red';
					break;
					
				case "'-'":
					$color = '#e0b5d3';
					break;
					
				default:
					$color = '#FFFFFF';
					break;
			}
		}
		$response .=  '<td style="background-color:'.$color.'">'.$value.'</td>';
	}
		
return $response;
}
function function_res( $function,$str ){
	$a = $function($str);
return td( $str, $a );
}



$function_list = array(
		'case_int_0'=>0,
		'case_string_0'=>'0',
		'case_int_1'=>1,
		'case_string_1'=>'1',
		'case_string_foo'=>'foo',
		'case_if_0eq0'=>'( $str===0 )',
		'case_if_AeqA'=>'( $str==="A" )',
		'case_if_false'=>'( true )',
		
		);

function test( $str )
{
	
	switch( (int)$str )
	{
		case false:
			$add = 'falseIN';
		case true:
			$add .= ':trueIN';
			return $add;
			break;

		default:
			return "-";
			break;
	}
}

	
$list = array(    "",       NULL,       "0",       0,       "1",       1,   "1.5",       1.5,           FALSE,TRUE
			,'A');




$table[$f] .= '<table border="1">';
$table[$f] .= '<tr><td style="background-color:#a8a8a8;color:#FFFFFF;">関数</td><td style="background-color:#a8a8a8;color:#FFFFFF;">トレース値</td><td style="background-color:#a8a8a8;color:#FFFFFF;">返り値</td></tr>';
foreach( $function_list as $f=>$trace )
{
	eval('
	function '.$f.'( $str )
	{
		
		switch( '.( (preg_match('/^\((.*)\)$/',$trace)?'true':'$str') ).' )
		{
			case '.( (preg_match('/^\((.*)\)$/',$trace)?$trace:var_export($trace,true)) ).':
				return '.var_export($trace,true).';
				break;
	
			default:
				return "-";
				break;
		}
	}
	');
	echo '<pre style="text-align:left;">
	function '.$f.'( $str )
	{
		
		switch( '.( (preg_match('/^\((.*)\)$/',$trace)?'true':'$str') ).' )
		{
			case '.( (preg_match('/^\((.*)\)$/',$trace)?$trace:var_export($trace,true)) ).':
				return '.var_export($trace,true).';
				break;
	
			default:
				return "-";
				break;
		}
	}
	</pre>
	';
	$i = 0;
	foreach( $list as $v )
	{
		$table[$f] .= '<tr>'."\n";
		$i===0 ? $table[$f] .= '<th rowspan="'.count($list).'">'.$f.'</th>' : '';
		$table[$f] .= function_res($f,$v);
		$table[$f] .= '</tr>'."\n";
		$i++;
	}
	
}

	

$table[$f] .= '</table>';
?>
<html>
<head>
</head>
<body>
<?= $mes; ?>
<?= implode( "\n",$table ); ?>
</body>
</html>