パスワードを忘れた? アカウント作成
11424728 story
PHP

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, 参考になる)

    by Anonymous Coward on 2014年08月11日 14時54分 (#2654736)

    ×'9223372036854775807' == '79223372036854775808'
    ○'9223372036854775807' == '9223372036854775808'
    なぜこんなコピペミスが発生するのかこんなわかりやすい誤字が残るのか理解できない

    • おぉ!やっぱりTypoだったのかよ!
      PHPは幾らなんでもおかしいだろと思ったら、そういうことだったのか…

      これはさすがに酷過ぎる
      もはやスラドの信憑性にも関わるレベル (いや、あればの話だが)

      親コメント
    • by Anonymous Coward on 2014年08月11日 15時01分 (#2654744)

      一瞬、そのくらいPHPの==は信用ならないって意味かと思いましたよw

      #shift+'7'をわざわざ打ったようですが…

      親コメント
      • by Anonymous Coward

        リンク先を見るまで、mod 2^32かなにかで、整数型として比較されているとかそういう話だと思って読んでた。

    • by Anonymous Coward

      それに気づくあなたこそ、只者でないとお見受けしました。

      まあ元のタレコミがそうなってるので、1文字も間違えずに
      コピペできているということでオッケーです。

  • 予言: php5.7 では (スコア:3, おもしろおかしい)

    by nim (10479) on 2014年08月11日 17時07分 (#2654817)

    「====」演算子が仕様に追加される。
    そして、5.8 では「=====」演算子が、
    6.0 では「=」の数によって一致している確立が一桁ずつ上がる(「==」は99%一致、「===」は99.9%一致)仕組みになり、
    6.1 では「=5=」(「=」7つ分の一致率)のような表記が導入される。

  • by Anonymous Coward on 2014年08月11日 14時29分 (#2654714)

    複雑っつーかイカれた挙動だよね

  • by Anonymous Coward on 2014年08月11日 14時48分 (#2654726)

    仕様であるかのような言い回しが気持ち悪いわー

    • by Anonymous Coward on 2014年08月11日 22時15分 (#2655027)

      なんでもかんでも仕様と言い張るなら、「PHPの仕様は複雑すぎて人間に理解できるものではないから、たとえば、PHPを避けるべきだ」としか言いようがないよな。

      親コメント
    • by Anonymous Coward

      型の適当さ(適当に比較してくれ、結果は受け入れるからさ)、がPHPのメリット(デメリット?!)だし、そのおかげでプログラミングに入りやすくした、というのは大いにある。問題のあるコードも量産してるけど。
      そういう土壌があるから、この程度のこと気にもしてない人がほとんどなんだろうなぁ。
      こんな大きな数値を比較することなんてそうそうないし。

      気にする人は === してるはず。

    • by Anonymous Coward

      他のプログラミング言語には存在しない曖昧比較演算子「≒」を実装していると考えれば画期的なのかもしれない…
      どこまでの範囲を「大体同じ」とみなすかは実装者の気分とやる気次第ということで

  • by Anonymous Coward on 2014年08月11日 20時17分 (#2654968)

    RTFMただその一言では

  • by Anonymous Coward on 2014年08月11日 15時00分 (#2654743)

    その辺が問題になるようなプログラムなら===を使っているだろうし実害はない気がする。

    • by Anonymous Coward on 2014年08月11日 17時08分 (#2654818)

      浮動小数点数を直接比較して等しいかどうかを調べてはいけません

      親コメント
      • by Anonymous Coward

        それが正しいと思うのに
        なんでみんな文句言ってるんだ?

        • by Anonymous Coward

          文字列同士の比較の話だから

        • by Anonymous Coward

          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 じゃないかと思う。

    • > [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 でした。
      問題の本質は、== を文字比較に使用しているところでしょう。

      親コメント
      • by Anonymous Coward on 2014年08月11日 17時31分 (#2654830)
        > $a = (double)"9223372036854775807";
        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)
        親コメント
    • by Anonymous Coward on 2014年08月11日 15時51分 (#2654777)

      普通ならそうだと思う。

      だが、「PHPプログラマを舐めるな!」と私は言いたい。
      そんな常識が奴らには通用しないから。

      そもそも、それらの演算子があることを知ってるかどうか……。orz

      親コメント
    • by Anonymous Coward

      何が入ってくるか判らないのならstrcmpが無難じゃないかな。
      桁溢れしそうソートなら
      usort($a, 'bccomp');
      にすれば良いだけだしなぁ。

    • by Anonymous Coward

      JavaScriptでも、たまにこれしないでバグになる。

  • by Anonymous Coward on 2014年08月11日 15時02分 (#2654745)

    やるな、PHP!
    ファンキーだぜ!!

    #リンク先記事だとちゃんと桁はあってますね

    • by Anonymous Coward

      桁だけ合っててもどっちみちファンキーだと思うんだが

  • by Anonymous Coward on 2014年08月11日 18時27分 (#2654887)

    正直、PHPを知らない人間には理解できないとしか言いようが無い

    '9223372036854775807' == '9223372036854775808' は文字列の比較だから、当然true
    '9999999999999999999.0' == '9999999999999999999.1' も文字列の比較だから、当然false
    9999999999999999999.0 == 9999999999999999999.1 は浮動小数点数の比較だから、言語仕様上どのような値を返すことになっているのか注意しろ(あるいは使うな)

    という他のプログラミング言語の常識は通用しないのか......................
    PHPの==は両辺を適当に【型キャストしてから】比較するような演算子~というのも良く分からない(なんでわざわざキャストする仕様なの?)

    • by Anonymous Coward

      JavaScript でも同じような型変換が行われるような…

      • by Anonymous Coward
        JavaScriptでは文字列同士の比較は型変換しないよね。
        > '9223372036854775807' == '9223372036854775808'
        < false
        > '9999999999999999999.0' == '9999999999999999999.1'
        < false

        型変換するのは左右の型が違う時。
        > '9223372036854775807' == 9223372036854775808
        < true
        > '9999999999999999999.0' == 9999999999999999999.1
        < true

        # 「JavaScriptでも~」って言う人が複数いて不安になった。
      • by Anonymous Coward

        JavaScriptをPHPみたいなクソ言語と一緒にしないでくれ

    • by Anonymous Coward

      インタプリタのスクリプト言語なんかは些細なことで(?)ランタイムエラーが発生してアボートしないように、気をきかせ適当な型キャストしてるんだろうとは思うが、やっぱり気持ち悪い

  • by Anonymous Coward on 2014年08月11日 19時07分 (#2654925)

    みたいなもの?

  • by Anonymous Coward on 2014年08月11日 23時40分 (#2655052)

    2012年にリリースされたバージョンでいま発覚するような仕様なら誰も困ってないよきっと。

typodupeerror

ソースを見ろ -- ある4桁UID

読み込み中...