PHPが0を文字列と等しいと見なすのはなぜですか?


111

次のコードがあります。

$item['price'] = 0;
/* Code to get item information goes in here */
if($item['price'] == 'e') {
    $item['price'] = -1;
}

これは、アイテムの価格を0に初期化し、それに関する情報を取得することを目的としています。価格が「e」として通知される場合、売りではなく交換を意味し、負の数としてデータベースに保存されます。

アイテムがボーナスであるか、価格が後で設定されるため、価格を0のままにする可能性もあります。

ただし、価格が設定されておらず、初期値が0の場合、if上記のループはtrueと評価され、価格は-1に設定されます。つまり、0は「e」と等しいと見なします。

これはどのように説明できますか?

価格が0として提供された場合(初期化後)、動作は不安定になります。ifがtrueと評価される場合とfalseと評価される場合があります。*


1
double ==の代わりにtriple ===を使用すると、期待される動作が得られることがわかりました。しかし、それはまだ奇妙です。
セルジオドミンゲス

2
(リファレンス)タイプジャグリングの章のPHPマニュアルで十分に説明され、タイプ比較表
Gordon

1
可能な文字列タイプが「e」のみの場合、is_string($ item ["price"])チェックを実行できませんか?===よりも少し効率的です。[要出典]
ジミー・リン

弱い比較ストリングの間の整数、文字列、整数に変換される(代わりに文字列に「昇格」される整数)。if((string)$item['price'] == 'e')奇妙な行動を修正します。詳細については、stackoverflow.com / a / 48912540/1579327ご覧ください
Paolo

@Paoloによる以下のコメントの別のケースに注意してください。二重等号演算子を使用する場合、0(整数)は他の文字列と等しくなります。
ハイタムスウェイレム

回答:


113

あなたはあなたの==ためにタイプを分類することをしています。

0はintなので、この場合は'e'int にキャストされます。これは1つとしては解析できず、になり0ます。文字列'0e'0一致します。

使用する ===


14
粗雑な比較のもう1つの欠点
MC皇帝

5
トリッキーなもの。これにぶつかっただけで、なぜstring == 0なのかと驚かされました。覚えておいてください。
Grzegorz 2016

2
文字列キーでループしているときにも、これに頭を悩ませていましたが、配列には最初の「ゼロ」のインデックス項目があり、最初の文字列キーの比較でtrueを維持していました。どうだった?どのように...それで、確かに、確かに、この答えはそれをクリアしました!この質問全体が1つの答えを受け入れていないことに驚いています。一部の質問者がジャークであることを示しに行きます。
IncredibleHat

48

これは、==比較演算子が示す比較演算が PHPでどのように行われるかによるものです。

数値を文字列と比較する場合、または比較に数値文字列が含まれる場合、各文字列は数値に変換され、比較は数値的に実行されます。[…]比較の際、===または!==タイプと値の比較が含まれる場合、タイプ変換は行われません。

最初のオペランドは数値(0)で、2番目のオペランドは文字列('e')であるため、文字列も数値に変換されますさまざまなタイプとの比較も参照)。文字列データ型のマニュアルページでは、文字列から数値への変換方法を定義しています

文字列が数値コンテキストで評価される場合、結果の値と型は次のように決定されます。

文字列に文字 ' .'、 ' e'、または ' E' が含まれておらず、数値が整数型の制限(で定義されているPHP_INT_MAX)に適合する場合、文字列は整数として評価されます。それ以外の場合はすべて、floatとして評価されます。

この場合、文字列は'e'なので、浮動小数点数として評価されます。

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

'e'有効な数値データで起動しない、それが浮かぶように評価します0


3
phpはほとんどすべてを簡単に比較できるように設計しており、私たちの一日を台無しにするためにいくつかの落とし穴を投げ入れます。これは、他のPHPの設計哲学と一致しません。欺瞞が哲学でない限り???
user3338098 2015

1
特に「e」がtrueにキャストされ、「」がfalseにキャストされるため
user3338098 '19

20
"ABC" == 0

最初に整数に変換され、次にと比較されるtrueため、評価されます。 "ABC"0 0

これは、PHP言語の奇妙な動作です。通常0、文字列に昇格"0""ABC"れ、結果と比較されると予想されますfalse。たぶん、JavaScriptのような他の言語では、弱い比較が"ABC" == 0評価されるのは、このためfalseです。

厳密な比較を行うと、問題が解決します。

"ABC" === 0

を評価しfalseます。

しかし、数値を文字列として比較する必要がある場合はどうなりますか?

"123" === 123

false左項と右項のタイプが異なるために評価されます。

実際に必要なのは、PHP型ジャグリングの落とし穴のない弱い比較です。

解決策は、用語を文字列に明示的に昇格し、比較を実行することです(厳密または弱いことはもはや問題ではありません)。

(string)"123" === (string)123

です

true

ながら

(string)"123" === (string)0

です

false


元のコードに適用:

$item['price'] = 0;
/*code to get item information goes in here*/
if((string)$item['price'] == 'e') {
    $item['price'] = -1;
}

9

==演算子は、タイプが異なる場合でも値の一致を試みます。例えば:

'0' == 0 will be true

タイプの比較も必要な場合は、===演算子を使用します。

'0' === 0 will be false

9

あなたの問題は、二重の等価演算子です。これは、右側のメンバーを左側のタイプに型キャストします。必要に応じて、strictを使用してください。

if($item['price'] == 'e') {
    $item['price'] = -1;
}

コードに戻りましょう(上記のコピー)。この場合、ほとんどの場合、$ item ['price']は整数です(eと等しい場合を除きます)。そのため、PHPの法則により、PHPは"e"整数に型キャストされ、が生成されint(0)ます。(私を信じていませんか?<?php $i="e"; echo (int)$i; ?>

これを簡単に回避するには、型をチェックし、暗黙的に型キャストしない、トリプル等価(完全比較)演算子を使用します。

PS:PHPの面白い事実:それa == bが意味するわけではありませんb == a。あなたの例を取り、それを逆にしてくださいif ("e" == $item['price'])


7

「0」、「false」、「off」の組み合わせを== falseとして検証し、「1」、「on」、「true」を== trueとして検証するためのPHPにはかなり見過ごされがちな便利なメソッドがあります。これは、GET / POST引数の解析に特に役立ちます。

filter_var( $item['price'], FILTER_VALIDATE_BOOLEAN );

これはこのユースケースに完全に関連しているわけではありませんが、類似性と事実を考えると、これは(string) "0"をfalseとして検証するという質問をするときに検索結果がよくある傾向があるため、他の人の役に立つと思いました。

http://www.php.net/manual/en/filter.filters.validate.php


6

===代わりに使用する必要があります==通常の演算子は型を比較しないため、あります。代わりに、アイテムを型キャストしようとします。

一方、===アイテムの種類を考慮に入れます。

  • === 「等しい」を意味し、
  • == 「eeeeh ..ちょっと見える」という意味です

1
そうですか。これは(タイプキャストで)機能します。if((string)$item['price']=='e'){ $item['price'] = -1; }
SérgioDomingues '27

しかし、そうすべきではありません。ちょうど使用===オペレータ
tereško

3

同じ奇妙な振る舞いに遭遇しながら、私がやった例で示すのが最善だと思います。私のテストケースを参照してください。うまくいけば、動作をよりよく理解するのに役立ちます。

// Normal comparison using the == Operator
echo (0 == "0"); // true
echo (0 == "a"); // true
echo (0 == "safta!"); // true
echo (1000 == "bla"); // false. It appears that PHP has a weird behavior only with the number / string 0 / "0" according to the past 3 examples.
echo (23 == "23"); // true. So as we said, PHP has a problem (not a problem but weird behavior) only when the number / string 0 (or "0") is present
echo (23 == "24"); // false. values aren't equal (unlike last example). The type is less relevant with the == operator as we can see.

// Now using the === and !== Operators
echo ("0" === 0); // false, since === requires both value and type to be the same. Here, type is different (int vs string)
echo ("0" !== 0); // true because they aren't the same in terms of === comparison (type is different and that's why it's true)
echo ("bla" === "blaa"); // false because the values are not the same. The type is the same, but === checks for both equal type and equal value.

//Now using casting and === Operator:
echo ((string)123 === "123"); // true. The casting of the int 123 to string changed it to "123" and now both variables have same value and are of same type
echo ((int)"123" === 123); // true. The casting of the string 123 to int, changed it to int, and now both variables are of same value and type (which is exactly what the === operator is looking for)

// Now using casting and == Operator. Basically, as we've seen above, the == care less for the
// type of var, but more to the value. So the casting is less relevant here, because even
// without casting, like we saw earlier, we can still compare string to int with the == operator
// and if their value is same, we'll get true. Either way, we will show that:
echo ((string)123 == "123"); // true. The casting of the int 123 to string changed it to "123" and now both vars have same value and are of same type
echo ((int)"123" == 123); // true. The casting of the string 123 to int, changed it to int, and now both vars are of same value and type (which is exactly what the === operator is looking for)

素晴らしいテスト、私は同じことをしましたが、私は素晴らしいテーブルを作りました。私の答えを見てください
IAMTHEBEST

0

基本的に、===型の安全性を保証するために、常に演算子を使用してください。

ここに画像の説明を入力してください

ここに画像の説明を入力してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.