この記事の内容は?
PHP初心者が知っておきたい型変換とは?
PHPはWebサーバ上で動作するスクリプト言語の1つです。PHPを書くエンジニアは世界中に数多くいて、今日も様々なサーバ上で動いています。
一方で他の言語と比べると簡単に導入し動作させることができるので、プログラミング初心者が初めて学習する言語としても人気があります。
そこで、この記事ではPHP初心者がハマりやすい「暗黙的型変換」という項目に絞って解説をしていきます。また、結果的にどのようなプログラムがわかりやすいのかということに注目して見て頂きたいです。
今PHPを学んでいる、またはこれから学ぼうと思っている皆さんの助けとなれば幸いです!
PHPは動的型付け言語
phpは動的型付け言語と呼ばれる言語です。動的型付け言語の特徴を簡単に説明すると「変数に値が代入されるまでその変数の型が確定しない」ということです。
以下のように、実行時に代入された値がその変数の型となります。
$a = "hello" // string型
$b = 100 // int型
$b = true // bool型
このような動的型付け言語の仕様によってハマるポイントの1つが比較です。
特に「意図せず違う型同士の比較を行ってしまう」ようなコードを書いてしまった場合がとても厄介です。
他の言語と同じ感覚で比較演算子「==」を使ってしまうと痛い目に見ることがあります。
PHPの比較演算子「==」の挙動
以下は変数aと変数bを比較してもし一致していたら”同じです”と出力し、違っていたら”違います”と出力するコードです。
if ($a == $b) {
echo '同じです';
} else {
echo '違います';
}
一見単純に見える上記のコードは一体どのような動作をするのでしょうか?いくつか例を挙げて見てみましょう。
例1
入力値 : $a = 1, $b = 1
出力値 : “同じです”
$a, $b ともにint型の値1の入力です。この入力の場合、プログラムは “同じです” という文字を出力します。
これは想像通りの動作であり、とてもわかりやすい結果です。
例2
入力値 : $a = “hello”, $b = “hello”
出力値 : “同じです”
$a, $b ともにstring型の値”hello”の入力です。この入力の場合、プログラムは “同じです” という文字を出力します。
これもまた想像通りの動作であると思います。
例3
入力値 : $a = 0, $b = “0”
出力値 : “同じです”
$aはint型の0、 $bはstring型”0″という入力です。この入力の場合、プログラムは “同じです” という文字を出力します。
これは果たして意図した動作でしょうか?$aはなんらかの計算結果として0という値をとり、$bはたまたま入力された文字列が”0″だっただけかもしれません。
例4
入力値 : $a = 120, $b = “00000120”
出力値 : “同じです”
$aはint型の0、 $bはstring型”00000120″という入力です。この入力でも、プログラムは “同じです” という文字を出力します。
おいおいさすがにこれは違うだろと思うのですが、これでも上記プログラムは同じであると判定します。
例5
入力値 : $a = 0, $b = “東京大学大学院”
出力値 : “同じです”
$aはint型の0、 $bはstring型”東京大学大学院”という入力です。この入力でも、プログラムは “同じです” という文字を出力します。
0と東大は違うというかむしろ対極にある存在な気がしますが、同じであると出力されてしまいます。
例3, 4, 5の結果は比較を行っている「==」演算子によって引き起こされる問題の1つです。
「==」演算子は「比較する2つの変数の型を合わせてから値を比較する」という挙動をします。
つまり上記の例でいくと$aにint型の値がきた場合、$bを「無理やりint型に変換」してから比較するという挙動をします。
例3の場合、$a がint型ですので$bをint型に変換します。暗黙的に以下のようなプログラムが追記されるイメージです。
$b = (int) $b // $b = (int) "0" のようにして数値の0になる
なんとなく想像できたでしょうか?
例4, 例5もパッと見は意味不明ですが、根本的にはこの暗黙的な(無理やりな)型変換によって引き起こされる挙動です。
例4は、phpの「string型からint型に型変換する場合1 ~ 9以外で始まる文字を無視する」という仕様が影響しています。
そのため、0埋めされている最初の5文字が消えたのです。
例5も例4の仕様の変換ルールによって「数字に変換できるものがなかった」ので0になってしまったということになります。
PHPの暗黙的型変換によるバグをなくすために
それではこのような想定されていない挙動をどうやって防ぐかを説明します。一番簡単な方法は「===」演算子を使う方法です。
「===」 演算子は「比較する変数の値と型が同じかどうか」を比較する演算子です。つまり「==」演算子のように型が合わない場合に暗黙的に変換してしまうのではなく、そもそも型が合わなければ一致したとはみなさないという厳密な比較をするということです。
厳密な比較が有用な点は「比較が成功とした場合、型まで確定していることが保障されている」点です。
そのif文を通ったのであれば2つの変数が完全に一致しているので、暗黙的型変換によるバグに悩まされることもなく、プログラムを読む側も余計な考慮をすることなく読むことができます。
未来の自分も含め他人のプログラムを読む時には考慮すべきことが少なければ少ないほど読みやすいものです。
状況が限定的ですが次のような方法もあります。
「値がない」または「値がある」ことだけを判定したいのであれば、比較に「empty」関数や「is_null」関数を使うことができます。
例えば下記のようなプログラムを書くのであれば、
if ($a == 0) {
echo '$aは0です';
}
以下のようにempty関数で丸めてしまった方がプログラムとしてはわかりやすいです。
if (empty($a)) {
echo '$aは空です';
}
前者のコードも後者のコードも結果的にはstring型の”0″がきてもtrueと判定されてしまいます。
しかし前者のプログラムではその挙動が想定されているかどうかがかなり微妙です。
後者のプログラムだと空文字(“”)や空配列([])も含めてtrueにしてしまっていますが、意図が明確になっているため見やすいプログラムです。
厳密に「int型の0」を期待するのであれば「===」演算子を使えば良いですが、そうでない場合、特に値がないことを期待するのであればempty関数等を使った方がわかりやすいものとなるのです。
まとめ
この記事ではPHPにおける「暗黙的型変換」という項目について解説しました。今回はその中でもstring型とint型の変換時におけるハマりやすいポイントを紹介しました。
動的型付け言語の暗黙的型変換に起因するバグを回避するのは熟練者でもなかなか骨が折れます。
しかしハマりやすいポイントさえ抑えておけば、PHPを使うことで静的型付け言語よりもずっと速いスピードで実装を進めることができるようになります。
この記事がその一助となれば幸いです!