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위에 표시된 루프는 참으로 평가되고 가격은 -1로 설정됩니다. 즉, 0을 'e'로 간주합니다.

어떻게 설명 할 수 있습니까?

가격이 0 (초기화 후)으로 제공되면 동작이 불규칙합니다. 경우에 따라 if가 true로 평가되고 때로는 false로 평가됩니다. *


1
double == 대신 triple ===을 사용하면 예상되는 동작이 나타납니다. 하지만 여전히 이상합니다.
Sérgio Domingues

2
(참조) 충분히 제 PHP의 매뉴얼에 설명 된 타입 저글링 및 도시 유형 비교표
고든

1
가능한 유일한 문자열 유형이 'e'인 경우 is_string ($ item [ "price"]) 검사를 수행 할 수 없습니까? ===보다 조금 더 효율적입니다. [인용 필요한]
지미 린

약한 비교 문자열 사이의 정수 문자열을 정수로 변환됩니다 (대신 정수를 문자열로 "승진"존재의). if((string)$item['price'] == 'e')이상한 행동을 수정합니다. 참조 stackoverflow.com/a/48912540/1579327을 위한 자세한 내용은
파올로

double equals 연산자를 사용할 때 0 (정수)이 다른 문자열과 동일한 @Paolo의 아래 주석에있는 또 다른 경우에 유의하십시오.
Haitham Sweilem

답변:


113

당신은 당신 ==을 위해 유형을 분류하는 것을하고 있습니다.

0은 int이므로이 경우 'e'에는 int 로 캐스트 됩니다. 하나로 구문 분석 할 수 없으며 0. 문자열 '0e'이되고 0일치합니다!

사용하다 ===


14
느슨한 비교의 또 다른 단점.
MC Emperor

5
까다로운 것. 방금이 문제에 부딪 쳤고 string == 0 인 이유에 놀랐습니다. 기억해야합니다.
Grzegorz

2
문자열 키를 반복 할 때도 이것에 내 머리를 긁고 있었지만 배열에는 첫 번째 문자열 키 비교에서 계속 true가되는 초기 '0'인덱스 항목이있었습니다. 내가 어땠어? 어떻게 ... 그래서, 확실히,이 대답은 그것을 정리했습니다! 이 전체 질문에 하나의 답변이 없다는 것에 놀랐습니다. 질문하는 사람이 바보라는 것을 보여주기 위해 간다.
IncredibleHat

48

이것은 PHP가 ==비교 연산자가 나타내는 비교 연산을 수행하는 방식 때문입니다 .

숫자를 문자열과 비교하거나 비교에 숫자 문자열이 포함 된 경우 각 문자열이 숫자로 변환되고 비교가 숫자로 수행됩니다. […] 유형 변환은 비교 일 때 ===또는 !==값뿐만 아니라 유형을 비교하는 것을 포함하기 때문에 발생하지 않습니다 .

첫 번째 피연산자는 숫자 ( 0)이고 두 번째 피연산자는 문자열 ( 'e')이므로 문자열도 숫자로 변환됩니다 ( 다양한 유형과의 비교 참조 ). 문자열 데이터 유형에 대한 매뉴얼 페이지는 문자열을 숫자로 변환 하는 방법을 정의 했습니다.

숫자 컨텍스트에서 문자열을 평가할 때 결과 값과 유형은 다음과 같이 결정됩니다.

문자열에 ' .', ' e'또는 ' E' 문자가 포함되어 있지 않고 숫자 값이 정수 유형 제한 (에서 정의 됨 PHP_INT_MAX)에 맞으면 문자열이 정수로 평가됩니다. 다른 모든 경우에는 부동 소수점으로 평가됩니다.

이 경우 문자열은 'e'이므로 float로 평가됩니다.

값은 문자열의 초기 부분으로 제공됩니다. 문자열이 유효한 숫자 데이터로 시작하는 경우이 값이 사용됩니다. 그렇지 않으면 값은 0(영)이됩니다. 유효한 숫자 데이터는 선택적 부호, 하나 이상의 숫자 (선택적으로 소수점 포함), 선택적 지수입니다. 지수는 ' e'또는 ' E'뒤에 하나 이상의 숫자가 있습니다.

으로 'e'유효한 숫자 데이터로 시작하지 않는, 그것은 떠 평가합니다 0.


3
PHP는 대부분의 모든 것을 쉽게 비교할 수 있도록 설계 한 다음 우리의 하루를 망치기 위해 몇 가지 문제를 던졌습니다. 이것은 PHP의 나머지 디자인 철학과 맞지 않습니다. 속임수가 없으면 철학이 ???
user3338098

1
특히 "e"가 true로 캐스팅되고 ""가 false로 캐스팅되기 때문에
user3338098

20
"ABC" == 0

첫 번째 는 정수로 변환되고 다음true되기 때문에 평가 됩니다 . "ABC"0 0

이것은 PHP 언어 의 이상한 동작입니다. 일반적으로 0문자열로 승격 된 "0"다음 "ABC"결과와 비교됩니다 false. 아마도 그것은 약한 비교가 "ABC" == 0평가 되는 JavaScript와 같은 다른 언어에서 일어나는 일입니다 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

문제는 이중 등호 연산자로 오른쪽 멤버를 왼쪽 유형으로 형변환합니다. 원하는 경우 엄격을 사용하십시오.

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

코드 (위에서 복사)로 돌아가 보겠습니다. 이 경우 대부분의 경우 $ item [ 'price']는 정수입니다 (분명히 e와 같은 경우는 제외). 따라서 PHP의 법칙에 따라 PHP는 "e"정수로 형변환 하여 int(0). (나를 믿지 않습니까? <?php $i="e"; echo (int)$i; ?>).

이를 쉽게 피하려면 유형을 확인하고 암시 적으로 형변환하지 않는 삼중 같음 (정확한 비교) 연산자를 사용하십시오.

추신 : PHP 재미있는 사실 : a == b그것을 암시하지 않습니다 b == a. 예를 들어 뒤집어보십시오. if ("e" == $item['price'])$ item [ 'price']가 항상 정수이면 실제로는 이행되지 않습니다.


7

PHP에는 "0", "false", "off"를 == false로, "1", "on", "true"를 == true로 혼합하여 확인하는 편리한 방법이 있습니다. GET / POST 인수를 구문 분석하는 데 특히 유용합니다.

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

이 사용 사례와는 전혀 관련이 없지만 유사성과 사실을 감안할 때 (문자열) "0"을 거짓으로 검증하는 질문을 할 때 검색 결과가 검색되는 경향이 있습니다. 다른 사람에게 도움이 될 것이라고 생각했습니다.

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


6

===대신 사용해야 합니다==일반 연산자는 유형을 비교하지 않으므로 . 대신 항목을 형변환하려고 시도합니다.

한편 ===고려 항목 유형을 고려합니다.

  • === "같음"을 의미하고
  • == 뜻은 "eeeeh .. 닮았 어"

1
내가 참조. 이제 작동합니다 (타이프 캐스트 포함) :if((string)$item['price']=='e'){ $item['price'] = -1; }
Sérgio Domingues

하지만 그렇게해서는 안됩니다. 바로 사용 ===연산자를
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.