Is There a Difference Between !== and != in PHP

Is there a difference between !== and != in PHP?

The != operator compares value, while the !== operator compares type as well.

That means this:

var_dump(5!="5"); // bool(false)
var_dump(5!=="5"); // bool(true), because "5" and 5 are of different types

Difference between not equal operators and != in PHP

In the main Zend implementation there is not any difference. You can get it from the Flex description of the PHP language scanner:

<ST_IN_SCRIPTING>"!="|"<>" {
return T_IS_NOT_EQUAL;
}

Where T_IS_NOT_EQUAL is the generated token. So the Bison parser does not distinguish between <> and != tokens and treats them equally:

%nonassoc T_IS_EQUAL T_IS_NOT_EQUAL T_IS_IDENTICAL T_IS_NOT_IDENTICAL
%nonassoc '<' T_IS_SMALLER_OR_EQUAL '>' T_IS_GREATER_OR_EQUAL

Difference between !== and ==!

The difference is that there is no operator ==!.

This expression:

$a ==! $b

Is basically the same as this:

$a == (!$b)

What's the difference between == and ===?

From http://us.php.net/manual/en/language.operators.comparison.php

$a == $b    Equal   TRUE if $a is equal to $b after type juggling.
$a === $b Identical TRUE if $a is equal to $b, and they are of the same type.
$a != $b Not equal TRUE if $a is not equal to $b after type juggling.
$a <> $b Not equal TRUE if $a is not equal to $b after type juggling.
$a !== $b Not identical TRUE if $a is not equal to $b, or they are not of the same type.

What is the difference between and !=

Forgetting documentation for a minute, let's check out the source code. Let's start with the scanner (lexer):

<ST_IN_SCRIPTING>"!="|"<>" {
return T_IS_NOT_EQUAL;
}

So they parse to the same token. Let's check out the parser:

expr T_IS_NOT_EQUAL expr { zend_do_binary_op(ZEND_IS_NOT_EQUAL, &$$, &$1, &$3 TSRMLS_CC); }

So we know that the opcode that's fired is ZEND_IS_NOT_EQUAL...

Now, let's check out the operation:

static int ZEND_FASTCALL  ZEND_IS_NOT_EQUAL_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE

zval *result = &EX_T(opline->result.var).tmp_var;

SAVE_OPLINE();
ZVAL_BOOL(result, fast_not_equal_function(result,
opline->op1.zv,
opline->op2.zv TSRMLS_CC));

CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}

So there's literally no difference. Since they parse to the same token, they have exactly the same precedence (so the docs are either wrong or misleading). Since they use the same executor, and there's no decision point in the opcode routine, they execute identical code.

So yes, <> and != are 100% interchangeable, and there's absolutely no technical reason to use one over the other.

With that said, there is something significant to gain by being consistent. So I'd recommend just sticking with != and being done with it...

Edit

I've updated the docs to reflect this, and fixed another issue with the precedence order (++ and -- have the same precedence as casting). Check it out on docs.php.net

How do the PHP equality (== double equals) and identity (=== triple equals) comparison operators differ?

Difference between == and ===

The difference between the loosely == equal operator and the strict === identical operator is exactly explained in the manual:

Comparison Operators


┌──────────┬───────────┬───────────────────────────────────────────────────────────┐
│ Example │ Name │ Result │
├──────────┼───────────┼───────────────────────────────────────────────────────────┤
│$a == $b │ Equal │ TRUE if $a is equal to $b after type juggling. │
│$a === $b │ Identical │ TRUE if $a is equal to $b, and they are of the same type. │
└──────────┴───────────┴───────────────────────────────────────────────────────────┘


Loosely == equal comparison

If you are using the == operator, or any other comparison operator which uses loosely comparison such as !=, <> or ==, you always have to look at the context to see what, where and why something gets converted to understand what is going on.

Converting rules

  • Converting to boolean
  • Converting to integer
  • Converting to float
  • Converting to string
  • Converting to array
  • Converting to object
  • Converting to resource
  • Converting to NULL

Type comparison table

As reference and example you can see the comparison table in the manual:

Loose comparisons with ==

┌─────────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬─────────┬───────┬───────┐
│ │ TRUE │ FALSE │ 1 │ 0 │ -1 │ "1" │ "0" │ "-1" │ NULL │ array() │ "php" │ "" │
├─────────┼───────┼───────┼───────┼───────┼───────┼───────┼───────┼───────┼───────┼─────────┼───────┼───────┤
│ TRUE │ TRUE │ FALSE │ TRUE │ FALSE │ TRUE │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │
│ FALSE │ FALSE │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ TRUE │ TRUE │ FALSE │ TRUE │
│ 1 │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │
│ 0 │ FALSE │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ TRUE │ FALSE │ TRUE │ TRUE │
│ -1 │ TRUE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │
│ "1" │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │
│ "0" │ FALSE │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │
│ "-1" │ TRUE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │
│ NULL │ FALSE │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ TRUE │ FALSE │ TRUE │
│ array() │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ TRUE │ FALSE │ FALSE │
│ "php" │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │
│ "" │ FALSE │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │
└─────────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴─────────┴───────┴───────┘

Strict === identical comparison

If you are using the === operator, or any other comparison operator which uses strict comparison such as !== or ===, then you can always be sure that the types won't magically change, because there will be no converting going on. So with strict comparison the type and value have to be the same, not only the value.

Type comparison table

As reference and example you can see the comparison table in the manual:

Strict comparisons with ===

┌─────────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬─────────┬───────┬───────┐
│ │ TRUE │ FALSE │ 1 │ 0 │ -1 │ "1" │ "0" │ "-1" │ NULL │ array() │ "php" │ "" │
├─────────┼───────┼───────┼───────┼───────┼───────┼───────┼───────┼───────┼───────┼─────────┼───────┼───────┤
│ TRUE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │
│ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │
│ 1 │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │
│ 0 │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │
│ -1 │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │
│ "1" │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │
│ "0" │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │
│ "-1" │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │
│ NULL │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │
│ array() │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │
│ "php" │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │
│ "" │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │
└─────────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴─────────┴───────┴───────┘

Not equal to != and !== in PHP

== and != do not take into account the data type of the variables you compare. So these would all return true:

'0'   == 0
false == 0
NULL == false

=== and !== do take into account the data type. That means comparing a string to a boolean will never be true because they're of different types for example. These will all return false:

'0'   === 0
false === 0
NULL === false

You should compare data types for functions that return values that could possibly be of ambiguous truthy/falsy value. A well-known example is strpos():

// This returns 0 because F exists as the first character, but as my above example,
// 0 could mean false, so using == or != would return an incorrect result
var_dump(strpos('Foo', 'F') != false); // bool(false)
var_dump(strpos('Foo', 'F') !== false); // bool(true), it exists so false isn't returned

What is the difference between ' and in PHP?

Basically, single-quoted strings are plain text with virtually no special case whereas double-quoted strings have variable interpolation (e.g. echo "Hello $username";) as well as escaped sequences such as "\n" (newline.)

You can learn more about strings in PHP's manual.

PHP: How does the Not-equal and Not-identical Operators work and are they faster then the Equal or Identical Operators?

Strings are defined as a structure here:

typedef struct {
char *c;
size_t len;
size_t a;
} smart_string;

The equality operator is defined here. (The following three equality operators also perform in essentially the same way, except they skip the address check as it would always be false)

static zend_always_inline zend_bool zend_string_equals(zend_string *s1, zend_string *s2)
{
return s1 == s2 || (ZSTR_LEN(s1) == ZSTR_LEN(s2) && !memcmp(ZSTR_VAL(s1), ZSTR_VAL(s2), ZSTR_LEN(s1)));
}

In case you don't speak C:

First, the address of each string structure is compared, if these are equal then the strings must be equal. Otherwise, further checks are made.

Second, if the addresses are not equal, then the length of each string is compared. This is just an integer equality check as the length is part of the string's structure definition. If the lengths are not equal, false is returned.

Next, the memory contents are checked for each string with memcmp. As memcmp returns 0 if the memory contents are equal, this is negated to return true.

To explicitly answer your question: PHP avoids checking every character of a string, the only case in which every character would be checked is that if every character of the string except for the last character is equal, and that the lengths of the strings are the same.

I must say: If you are really worrying about === being slower than !==, then you really shouldn't be.



Related Topics



Leave a reply



Submit