PHP 5.4.4で==演算子の挙動が変わっていた 73
ストーリー by hylom
==の罠 部門より
==の罠 部門より
あるAnonymous Coward 曰く、
PHPの==演算子は複雑な挙動をすることが知られているが、2012年にリリースされたPHP 5.4.4で変更された==演算子の挙動についての話が話題になっている。
PHP 5.4.4より前は、「'9223372036854775807' == '79223372036854775808'」という式がtrueを返していたのが、PHP 5.4.4ではこれがfalseを返すように変更された、という話なのだが(Bug #54547 wrong equality of string numbers)、この変更により、今度は「'9999999999999999999.0' == '9999999999999999999.1'」という式がtrueになってしまう、という別の問題が発生してしまった模様。
こうなってしまう原因については元記事で説明されているが、PHPにおいて「==」演算子は数値文字列同士を比較する場合、整数や浮動小数点に変換してから比較を行うという挙動をするためらしい。
謎のコピペミス (スコア:5, 参考になる)
×'9223372036854775807' == '79223372036854775808'
○'9223372036854775807' == '9223372036854775808'
なぜこんなコピペミスが発生するのかこんなわかりやすい誤字が残るのか理解できない
Re:謎のコピペミス (スコア:2)
おぉ!やっぱりTypoだったのかよ!
PHPは幾らなんでもおかしいだろと思ったら、そういうことだったのか…
これはさすがに酷過ぎる
もはやスラドの信憑性にも関わるレベル (いや、あればの話だが)
Re:謎のコピペミス (スコア:1)
一瞬、そのくらいPHPの==は信用ならないって意味かと思いましたよw
#shift+'7'をわざわざ打ったようですが…
Re: (スコア:0)
リンク先を見るまで、mod 2^32かなにかで、整数型として比較されているとかそういう話だと思って読んでた。
Re: (スコア:0)
それに気づくあなたこそ、只者でないとお見受けしました。
まあ元のタレコミがそうなってるので、1文字も間違えずに
コピペできているということでオッケーです。
予言: php5.7 では (スコア:3, おもしろおかしい)
「====」演算子が仕様に追加される。
そして、5.8 では「=====」演算子が、
6.0 では「=」の数によって一致している確立が一桁ずつ上がる(「==」は99%一致、「===」は99.9%一致)仕組みになり、
6.1 では「=5=」(「=」7つ分の一致率)のような表記が導入される。
Re:予言: php5.7 では (スコア:1)
6.1 では「=5=」(「=」7つ分の一致率)のような表記が導入される。
「=(ΦωΦ)=」はどんな意味を持つ演算子になるんだろうかにゃ。
Re:予言: php5.7 では (スコア:2)
「=('v')=」
「=('o')=」
「=('3')=」
「=('8')=」
Re: (スコア:0)
/.で声出して笑ったのは久しぶりだ
Re:予言: php5.7 では (スコア:1)
6.1 では「=5=」(「=」7つ分の一致率)のような表記が導入される。
「=(ΦωΦ)=」はどんな意味を持つ演算子になるんだろうかにゃ。
比較関数としてユーザ定義関数"ΦωΦ()"を使った比較を行う。
PHPでの==演算子は複雑な挙動 (スコア:1)
複雑っつーかイカれた挙動だよね
Re:PHPでの==演算子は複雑な挙動 (スコア:1)
こういった挙動こそがPHPの個性
Re:PHPでの==演算子は複雑な挙動 (スコア:1)
同意同意。ちょーっとした十徳ナイフみたいな小道具的なもん目指してて
PHPそこまで厳密なモン提供したいわけじゃなかったはず。
'9223372036854775807' == '79223372036854775808'
と
'9999999999999999999.0' == '9999999999999999999.1'
どっちがマシ?って言われたら後者だから。
こ れ で い い の だ 。
たぶん。 おそらく。 きっと。 めいびー。 あいほーぷそー。
Re:PHPでの==演算子は複雑な挙動 (スコア:1)
障害も個性ってやつですね。わかります。
Re:PHPでの==演算子は複雑な挙動 (スコア:2)
「バグは夜更け過ぎに仕様に変わるだろう」だっけ?
#高度に複雑化した仕様はバグと見分けがつかない
Re:PHPでの==演算子は複雑な挙動 (スコア:2)
>そんな大きな数誰も扱わないからOK
もし本当にそうであるならば、仕様変更しなければ良かったんですよ。
だって誰も使わないんでしょ?
Re: (スコア:0)
というか、これを問題にしたい人はPHPに何を求めているのかと。
UI(HTML)描画とDBアクセス以外の複雑なことをPHPでするなよ、と思うわけですが、
PHPしか使わせてもらえないか、PHPしか使えないか、なんでしょうね。
#かわいそうに
Re:PHPでの==演算子は複雑な挙動 (スコア:1)
クソ以外のなにものでもない。
PHP実装者の頭の中をのぞいてみたいもんだ。
Re: (スコア:0)
小さな親切大きなお世話の良い例
仕様ではなくてバグだよね (スコア:1)
仕様であるかのような言い回しが気持ち悪いわー
Re:仕様ではなくてバグだよね (スコア:1)
なんでもかんでも仕様と言い張るなら、「PHPの仕様は複雑すぎて人間に理解できるものではないから、たとえば、PHPを避けるべきだ」としか言いようがないよな。
Re: (スコア:0)
型の適当さ(適当に比較してくれ、結果は受け入れるからさ)、がPHPのメリット(デメリット?!)だし、そのおかげでプログラミングに入りやすくした、というのは大いにある。問題のあるコードも量産してるけど。
そういう土壌があるから、この程度のこと気にもしてない人がほとんどなんだろうなぁ。
こんな大きな数値を比較することなんてそうそうないし。
気にする人は === してるはず。
Re: (スコア:0)
他のプログラミング言語には存在しない曖昧比較演算子「≒」を実装していると考えれば画期的なのかもしれない…
どこまでの範囲を「大体同じ」とみなすかは実装者の気分とやる気次第ということで
マニュアルに比較するなと書いてある。 (スコア:1)
RTFMただその一言では
Re:マニュアルに比較するなと書いてある。 (スコア:1)
あくまで「こういう仕様」ですよね
実際Excelでも,「=」を使った文字列比較は大文字小文字を区別しません
区別してほしければEXACTを使って比較するべきであり,それが仕様です
PHPでは「==」を使った比較はこういう動作であり,厳密な比較が必要であれば「===」を使うべきというそれだけのことですよね
Re:マニュアルに比較するなと書いてある。 (スコア:2)
えっ…
7.1 - 7.2 = 0.1
という風に、他言語に比べて極めて「直観的」な結果を返すものもある。
PHPerの直観とやらはバグってるようだな…
===を使えば良いだけのような (スコア:0)
その辺が問題になるようなプログラムなら===を使っているだろうし実害はない気がする。
Re:===を使えば良いだけのような (スコア:2, すばらしい洞察)
浮動小数点数を直接比較して等しいかどうかを調べてはいけません
Re: (スコア:0)
それが正しいと思うのに
なんでみんな文句言ってるんだ?
Re: (スコア:0)
文字列同士の比較の話だから
Re: (スコア:0)
PHP を使う人たちは
(0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1) == 1.0
がtrueにならないと騒ぐ人が多くていまでも不思議な演算が == ではされている。
俺の思った比較じゃないと思う人が多ければその人たちの為に演算結果が変わるのが
PHP じゃないかと思う。
Re:===を使えば良いだけのような (スコア:1)
> [2012-04-11 07:47 UTC] foobla at spambog dot com
> I don't think it's about PHP_MAX_INT, rather about the maximum precision of a double/float. "==" converts both strings to numbers (after spending CPU cycles to detect whether they look like numbers), as described in http://www.phpsadness.com/sad/47 [phpsadness.com]
>
> once converted, the floats seem to actually *be* equal, even with "===":
>
> php -r '
> $a = (double)"9223372036854775807";
> $b = (double)"9223372036854775808";
> var_dump($a, $b, $a == $b, $a === $b);
> '
> float(9.2233720368548E+18)
> float(9.2233720368548E+18)
> bool(true)
> bool(true)
ということで、実害ありそうな。
なお、perl でやってみたところ、
$a == $b は true、$a eq $b は(当然)false でした。
問題の本質は、== を文字比較に使用しているところでしょう。
Re:===を使えば良いだけのような (スコア:1)
doubleにキャストしてしまってる時点でダメなんじゃないの?
その後どうしようがキャストした時点で値が違うんだから、==による暗黙の型変換なんか意味がない。
ちなみにうちではこうなった。
$ php -v
PHP 5.4.24 (cli) (built: Jan 19 2014 21:32:15)
$ php -r '
> $a = "9223372036854775807";
> $b = "9223372036854775808";
> var_dump($a, $b, $a == $b, $a === $b);
> '
string(19) "9223372036854775807"
string(19) "9223372036854775808"
bool(false)
bool(false)
$php -r "var_dump('9223372036854775807'=='9223372036854775808');"
bool(false)
$ php -r "var_dump('9999999999999999999.0' == '9999999999999999999.1');"
bool(true)
$ php -r '
> $a = "9999999999999999999.0";
> $b = "9999999999999999999.1";
> var_dump($a == $b, $a === $b);
> '
bool(true)
bool(false)
Re:===を使えば良いだけのような (スコア:1)
ええ。
内部的にdoubleにキャストしているため
== と === で変化がない、という意味です。
Re:===を使えば良いだけのような (スコア:1)
普通ならそうだと思う。
だが、「PHPプログラマを舐めるな!」と私は言いたい。
そんな常識が奴らには通用しないから。
そもそも、それらの演算子があることを知ってるかどうか……。orz
Re: (スコア:0)
何が入ってくるか判らないのならstrcmpが無難じゃないかな。
桁溢れしそうソートなら
usort($a, 'bccomp');
にすれば良いだけだしなぁ。
Re:===を使えば良いだけのような (スコア:3, 参考になる)
strcmp は「なんかよく分からない値→文字列」の変換をかましてから、文字列同士を比較するので、変換で何が起きるかをきちんと把握していていない限り使っちゃダメ、だそうです。
上記記事では、 pow(2,52) と pow(2,52)+10 が strcmp では同一と判定されてしまう、という例が示されています。結論としては === を使え、ということのようです。
Re: (スコア:0)
memcmpないの?
Re: (スコア:0)
JavaScriptでも、たまにこれしないでバグになる。
19桁と20桁の数値比較で true を返す……だと?! (スコア:0)
やるな、PHP!
ファンキーだぜ!!
#リンク先記事だとちゃんと桁はあってますね
Re: (スコア:0)
桁だけ合っててもどっちみちファンキーだと思うんだが
PHPを知らない人間には理解できない (スコア:0)
正直、PHPを知らない人間には理解できないとしか言いようが無い
'9223372036854775807' == '9223372036854775808' は文字列の比較だから、当然true
'9999999999999999999.0' == '9999999999999999999.1' も文字列の比較だから、当然false
9999999999999999999.0 == 9999999999999999999.1 は浮動小数点数の比較だから、言語仕様上どのような値を返すことになっているのか注意しろ(あるいは使うな)
という他のプログラミング言語の常識は通用しないのか......................
PHPの==は両辺を適当に【型キャストしてから】比較するような演算子~というのも良く分からない(なんでわざわざキャストする仕様なの?)
Re: (スコア:0)
JavaScript でも同じような型変換が行われるような…
Re: (スコア:0)
> '9223372036854775807' == '9223372036854775808'
< false
> '9999999999999999999.0' == '9999999999999999999.1'
< false
型変換するのは左右の型が違う時。
> '9223372036854775807' == 9223372036854775808
< true
> '9999999999999999999.0' == 9999999999999999999.1
< true
# 「JavaScriptでも~」って言う人が複数いて不安になった。
Re:PHPを知らない人間には理解できない (スコア:1)
> 複数いて
たぶん同じ人じゃないかな。
Re: (スコア:0)
JavaScriptをPHPみたいなクソ言語と一緒にしないでくれ
Re: (スコア:0)
インタプリタのスクリプト言語なんかは些細なことで(?)ランタイムエラーが発生してアボートしないように、気をきかせ適当な型キャストしてるんだろうとは思うが、やっぱり気持ち悪い
0.99999...==1 (スコア:0)
みたいなもの?
Re: (スコア:0)
http://ansaikuropedia.org/wiki/1%3D2 [ansaikuropedia.org]
むしろこっち
おととし来やがれ (スコア:0)
2012年にリリースされたバージョンでいま発覚するような仕様なら誰も困ってないよきっと。