関連記事
PHPマニュアル要点まとめ #12「型:数値形式の文字列」
この記事の動画版はこちら(画像クリックでYoutubeに飛びます)
PHPのオフィシャルマニュアルを分かりやすく噛み砕いて解説するシリーズです。
今回は「型」の章から「数値形式の文字列」を読んでいきます。
言語リファレンス > 型 >「数値形式の文字列」の補足解説です。
マニュアルページを見ながらご覧ください。
数値形式の文字列【要点まとめ】
PHPでは、文字列として定義されていたとしても、そのデータが数値として解釈出来る場合、PHPが自動的に数値として解釈してくれる仕組みがあります。
整数の場合は「int」、小数の場合は「float」として自動解釈されます。
PHPのバージョンによって、動作の挙動は多少異なりますが、PHP8.0.0以降では以下のような仕様で解釈されます。
WHITESPACES \s*
LNUM [0-9]+
DNUM ([0-9]*)[\.]{LNUM}) | ({LNUM}[\.][0-9]*)
EXPONENT_DNUM (({LNUM} | {DNUM}) [eE][+-]? {LNUM})
INT_NUM_STRING {WHITESPACES} [+-]? {LNUM} {WHITESPACES}
FLOAT_NUM_STRING {WHITESPACES} [+-]? {EXPONENT_DNUM} {WHITESPACES}
NUM_STRING ({INT_NUM_STRING} | {FLOAT_NUM_STRING})
ただ、これを見てもちょっと分かりづらいので、具体的な例を見ていきましょう。
文字列が数値として解釈されるのはどのような場合かと言うと、例えば、以下のように文字列が足し算などの算術演算に指定された場合です。
$foo = 1 + "10.5";
通常、数値と文字列の足し算は行うことが出来ませんが、PHPでは、文字列が数値として解釈出来る場合、自動的に数値に変換して計算してくれます。
この例だと、1+10.5=11.5という結果が出ます。
以下のような指数表記の場合も、自動的にfloat型として解釈してくれます。
$foo = 1 + "-1.3e3";
ちなみに、intとfloatの違いについては以下の記事で解説していますので、よく分からないという方は併せて学習してみてくださいね。
次に、このように文字列が数値として解釈出来ない場合です。
$foo = 1 + "bob-1.3e3";
このような場合は、PHPは「TypeError」というエラーを発生させます。
ただし、これはPHP8.0.0以降で導入された動作であり、PHP8.0.0より前のバージョンでは、数値として解釈出来ない文字列は全て「0」として解釈され、1 + 0 = 1という結果になり、これが意外とバグの原因になっていたりしました。
その辺りを考慮して、PHP8.0.0では仕様が変わったということですね。
次に、「数値から始まる文字列」の場合は、警告を出しつつ先頭部分の数値を数値として解釈してくれます。
$foo = 1 + "10 Small Pigs";
例えば、この例の場合は、先頭の「10」の部分が数値として解釈され、E_WARNINGという警告を出しつつ、1 + 10の計算をしてくれます。
これらの例も同様ですね。
$foo = 4 + "10.2 Little Piggies"; $foo = "10.0 pigs " + 1; $foo = "10.0 pigs " + 1.0;
ちなみに、PHP8.0.0よりも前のバージョンでは、発生する警告はE_WARNINGよりもエラーレベルの低いE_NOTICEでした。
PHPでは、文字列を数値として解釈する必要が発生した場合、以下の流れで判定を行います。
1. 文字列が数値の場合、かつそれが int 型の範囲 (PHP_INT_MAX で定義されています) に含まれる場合、int に解決されます。 そうでない場合、float に解決されます。
まず、その文字列が数値として解釈出来るかどうかを判定します。
数値として解釈出来、それがintの範囲内であれば、int型として解釈します。
intの範囲外であれば、float型として解釈されます。
2. 文脈が 先頭から始まる数値形式の文字列を許す場合、 かつ値が文字列の場合は、次のように解決されます: 文字列の先頭部分が数値形式の文字列、かつそれが int 型の範囲 (PHP_INT_MAX で定義されています) に含まれる場合、int に解決されます。 そうでない場合、float に解決されます。 それに加えて、エラーレベル E_WARNING が発生します。
次に、文字列の先頭が数値で始まっているかどうかを判定します。
数値で始まっていた場合、その数値がintの範囲内であれば、int型として解釈します。
intの範囲外であれば、float型として解釈されます。
3. 文字列が数値でない場合、 TypeError がスローされます。
そして、文字列が数値として解釈出来ない場合は、TypeErrorを発生させます。
このような流れですね。
なお、PHP8.0.0とそれ以前のバージョンによる動作の違いは以下のようになります。
PHP 8.0.0 より前のバージョンでは、 先頭に ホワイトスペースがある場合にだけ、 文字列は数値と見なされていました。 数値の後に ホワイトスペースがある場合は、 その文字列は 先頭から始まる 数値形式の文字列とみなされていました。
PHP 8.0.0 より前のバージョンでは、 文字列が数値の文脈で使われる場合、既に述べたステップと同じ処理を行いますが、 以下の違いがあります:
・先頭から始まる数値形式の文字列の場合、 E_WARNING ではなく、 E_NOTICE が発生していました。
・文字列が数値でない場合、 E_WARNING が発生し、 0 が返されていました。
PHP 7.1.0 より前のバージョンでは、 E_NOTICE も E_WARNING も発生していませんでした。