読者です 読者をやめる 読者になる 読者になる

Paradigm Shift Design

ISHITOYA Kentaro's blog.

PHPの文字列に対するisset

んー.PHPを6-7年近く使ってきたけど,初めて知った.

<?php
$string = "hogehoge";
var_dump(isset($string["arienai"]));
?>

の結果は,trueです.
PHP :: Bug #44587 :: Problems whene asking if a key of an array isset, and the variable is not arrayにもあったけど,PHP5.2.0で試しても同じだったから,ずっと昔からの仕様なのかなぁ.ううーん.怖いな.


よく考えたらそんなに変な挙動じゃないのか.

文字列の最初の部分により値が決まります。文字列が、 有効な数値データから始まる場合、この値が使用されます。その他の場合、 値は 0 (ゼロ) となります。有効な数値データは符号(オプション)の後に、 1 つ以上の数字 (オプションとして小数点を 1 つ含む)、 オプションとして指数部が続きます。指数部は 'e' または 'E' の後に 1 つ以上の数字が続く形式です。
PHP: 文字列 - Manual

とあって,PHPでは,

<?php
$string = "hogehoge";
var_dump($string[0]);
?>

は,stringの0番目の文字だから"h"と表示される.で,先ほどの

<?php
$string = "hogehoge";
var_dump(isset($string["arienai"]));
?>

は,文字列stringの"arienai"番目の文字で,"arienai"という文字列は整数に変換されて,$string[0]を参照することになる.


なぜこんなことで引っかかったかというと,文字列が入ってくるか配列が入ってくるかわからない関数で

<?php
function test($data){
    if(isset($data["pattern"]){
        return '/' . $data["pattern"] . '/';
    }else{
        return '/' . $data . '/';
    }
}

test('mogemoge'); //"/m/"
test(array("pattern" => "mogemoge")); //"/mogemoge/"
?>

とかなってて,正しくは

<?php
function test($data){
    if(is_array($data) && isset($data["pattern"]){
        return '/' . $data["pattern"] . '/';
    }else if(is_string($data)){
        return '/' . $data . '/';
    }else{
        throw new Exception("illegal argument");
    }
}

test('mogemoge'); //"/mogemoge/"
test(array("pattern" => "mogemoge")); //"/mogemoge/"
?>

としないといけないと.型あるじゃん!はいいっこなし.