PHPLogical Operators

Logical Operators

Logical operators combine boolean expressions into more complex conditions: "is the user logged in and an admin?", "is the value empty or negative?". PHP offers two spellings for the same three core operations — symbolic (&&, ||) and word-based (and, or) — and they are not perfectly interchangeable. Knowing why is one of the more important gotchas in the language.

AND, OR, and NOT

&& evaluates to true only when both sides are true. || evaluates to true when at least one side is true. ! flips a boolean: true becomes false and vice versa.

&&, ||, and !

PHP
<?php
$age = 20;
$hasTicket = true;

var_dump($age >= 18 && $hasTicket); // bool(true)
var_dump($age >= 65 || $hasTicket); // bool(true)
var_dump(!$hasTicket);              // bool(false)
bool(true)
bool(true)
bool(false)
xor

xor (exclusive or) returns true when exactly one side is true — if both sides are true or both are false, it returns false. It has no symbolic equivalent in PHP.

xor

PHP
<?php
var_dump(true xor false);  // bool(true)  - exactly one is true
var_dump(true xor true);   // bool(false) - both true
var_dump(false xor false); // bool(false) - both false
bool(true)
bool(false)
bool(false)
Short-circuit evaluation

Both &&/and and ||/or are short-circuiting: PHP stops evaluating as soon as the overall result is already determined. For &&, if the left side is false, the right side is never evaluated because the whole expression must be false regardless. For ||, if the left side is true, the right side is skipped. This is not just an optimization — it is commonly relied on to avoid errors.

Short-circuiting avoids an error

PHP
<?php
$user = null;

// Safe: if $user is falsy, the property access on the right never runs
if ($user && $user->isActive()) {
    echo "Active user";
} else {
    echo "No active user";
}
No active user

Had PHP evaluated both sides unconditionally, $user->isActive() on a null value would raise a fatal error. Short-circuiting is exactly what makes this common defensive pattern work.

The precedence trap: and/or vs &&/||

This is the classic PHP interview question, and it is a genuine, documented gotcha rather than trivia. && and || have higher precedence than = (assignment), which is what you would expect. But and and or have lower precedence than =. That difference means swapping && for and in an assignment can silently change what gets stored in your variable.

The and/&& assignment trap

PHP
<?php
$result = true && false;
var_dump($result); // bool(false) - as expected

$result = true and false;
var_dump($result); // bool(true)  - surprising!
bool(false)
bool(true)

In the second line, because = binds tighter than and, PHP parses it as ($result = true) and false — the assignment happens first with just true, and the and false part is evaluated but its result is thrown away. This is almost never the intent, and it is exactly why the symbolic operators are the safer default.

Prefer && and || over and/or in conditions with assignment
Reserve `and`, `or`, and `xor` for rare readability cases where no assignment is involved in the same statement — for example, control flow like `die("message") or exit;` patterns you might see in older code. Anywhere you are assigning the result of a logical expression to a variable, use `&&` and `||` to avoid the precedence trap shown above.

Operator

Meaning

Precedence vs =

&&

Logical AND

Higher than =

||

Logical OR

Higher than =

!

Logical NOT

Higher than =

and

Logical AND

Lower than =

or

Logical OR

Lower than =

xor

Logical exclusive OR

Lower than =

  • &&/|| bind tighter than =; and/or bind looser than =.

  • Both forms short-circuit: the right side is skipped once the result is already known.

  • xor is true only when exactly one operand is true.

  • Short-circuiting is commonly used to guard against calling a method on null.

!important reads naturally but is easy to miss
`!` binds very tightly, so `!$a && $b` means `(!$a) && $b`, not `!($a && $b)`. When negating a compound condition, wrap it in parentheses explicitly — `!($a && $b)` — so the intent is unmistakable at a glance.
Tip
Default to `&&` and `||` in all everyday code, including conditions and assignments. Save `and`/`or` for the handful of control-flow idioms where their low precedence is intentional, and even then, comment why.