PHPComparison Operators

Comparison Operators

Comparison operators answer a yes-or-no question about two values and always return a boolean. PHP's comparison story has more nuance than most languages because of loose comparison, which converts types before comparing, versus strict comparison, which does not. Understanding the difference — and knowing when PHP's own rules changed between versions — will save you from some of the language's most infamous bugs.

Equality: == vs ===

== (loose equality) converts both operands to a common type before comparing their values. === (strict equality) compares both the value and the type, with no conversion at all. They are two different questions: "do these represent the same value?" versus "are these exactly the same value and type?"

Loose vs strict equality

PHP
<?php
var_dump(1 == "1");     // bool(true)  - "1" converts to 1
var_dump(1 === "1");    // bool(false) - int vs string
var_dump(0 == false);   // bool(true)  - false converts to 0
var_dump(0 === false);  // bool(false) - int vs bool
var_dump(null == false); // bool(true) - both "empty-ish"
bool(true)
bool(false)
bool(true)
bool(false)
bool(true)
Inequality: != and <> vs !==

!= and its older alias <> are the loose-comparison negation of ==; !== is the strict-comparison negation of ===. As with equality, prefer the strict form whenever you can, since it removes an entire category of "why is this true" surprises.

Inequality operators

PHP
<?php
var_dump("5" != 5);   // bool(false) - loose, both numeric
var_dump("5" !== 5);  // bool(true)  - strict, string vs int
bool(false)
bool(true)
Ordering operators

The familiar <, >, <=, and >= compare order — numerically for numbers, alphabetically (byte by byte) for plain strings. When comparing a number to a numeric string, PHP compares them numerically; comparing genuinely non-numeric strings falls back to string comparison rules.

Ordering examples

PHP
<?php
var_dump(5 > 3);          // bool(true)
var_dump("apple" < "banana"); // bool(true) - alphabetical
var_dump("10" > "9");     // bool(true) - both numeric strings, compared as numbers
The PHP 8 loose comparison change

This is the single most important comparison detail to know if you learned PHP from older material. Before PHP 8, comparing a number to a non-numeric string first converted the number to a string, which produced surprising results like 0 == "abc" being true (because "abc" used to convert to 0). PHP 8 changed the rule: a number is now compared to a non-numeric string by converting the number to a string instead, so 0 == "abc" is false. Numeric strings like "123" still compare numerically as before.

0 == 'abc' before and after PHP 8

PHP
<?php
// On PHP 8+:
var_dump(0 == "abc");     // bool(false) - changed from PHP 7's bool(true)
var_dump(0 == "");        // bool(false) - changed as well
var_dump("1" == "01");    // bool(true)  - both numeric strings, compare as numbers
var_dump("10" == "1e1");  // bool(true)  - both numeric, 1e1 = 10
var_dump(100 == "1e2");   // bool(true)  - 1e2 = 100
bool(false)
bool(false)
bool(true)
bool(true)
bool(true)
Do not trust old tutorials on this exact example
`0 == "abc"` is one of the most commonly cited "PHP is weird" examples on the internet, but nearly all of those examples describe PHP 7 behavior. On any PHP 8.x runtime the result is `false`. Always verify comparison examples against the PHP version you are actually running, and when the stakes are real — validating user input, checking API responses — sidestep the ambiguity entirely by using `===`.
The spaceship operator: <=>

The spaceship operator compares two values and returns an integer: -1 if the left side is smaller, 0 if they are equal, and 1 if the left side is larger. It exists mainly to make writing custom sort comparators trivial — the dedicated Null Coalescing & Spaceship page covers that use case in detail.

Spaceship operator

PHP
<?php
var_dump(1 <=> 2); // int(-1)
var_dump(2 <=> 2); // int(0)
var_dump(3 <=> 2); // int(1)
int(-1)
int(0)
int(1)
Comparing arrays

== on two arrays checks that they have the same key/value pairs, regardless of the order the keys appear in. === additionally requires the same order and the same types for every value.

Array comparison

PHP
<?php
$a = ["x" => 1, "y" => 2];
$b = ["y" => 2, "x" => 1];

var_dump($a == $b);  // bool(true)  - same pairs, order ignored
var_dump($a === $b); // bool(false) - different key order
bool(true)
bool(false)

Operator

Meaning

Type-checked?

==

Equal (value only)

No

===

Identical (value and type)

Yes

!= / <>

Not equal (value only)

No

!==

Not identical

Yes

< > <= >=

Ordering

No

<=>

Three-way comparison (-1, 0, 1)

No

  • === and !== never convert types — the safest default for most conditionals.

  • == and != convert types, which is convenient but can hide bugs.

  • PHP 8 fixed the classic 0 == "abc" surprise: it is now false.

  • <=> returns -1, 0, or 1 and is built for sorting callbacks.

Numeric strings are still special-cased
Even under PHP 8's rules, two strings that both look like numbers — `"10"` and `"1e1"` — are still compared numerically under `==`. The PHP 8 change only affects comparisons between a number and a genuinely non-numeric string.
Tip
Default to `===` and `!==` everywhere unless you have a specific, documented reason to allow type conversion. It removes an entire class of bugs and makes your intent unambiguous to anyone reading the code later.