PHP If Operators

Su Subhalakshmi Chandran Updated 17 Oct 2026
10 min read ·Lesson 33 of 102
In this post

An if statement is only as reliable as its condition. This lesson focuses on writing conditions : which operators and functions to use for numbers, strings, missing values, types, and lists, and how t

An if statement is only as reliable as its condition. This lesson focuses on writing conditions: which operators and functions to use for numbers, strings, missing values, types, and lists, and how to combine them correctly. Most real bugs in if statements are not in the if itself but in a condition that does not mean exactly what the author intended.


Operators Used in Conditions

Comparison Operators

OperatorMeaningExampletrue When
===Identical$status === 'paid'Same value and type
!==Not identical$code !== ''Different value or type
==Equal (with type juggling)$qty == '5'Equal after conversion
!= / <>Not equal (with type juggling)$a != $bNot equal after conversion
>Greater than$stock > 0Left is larger
<Less than$age < 18Left is smaller
>=Greater than or equal$score >= 40Left is larger or equal
<=Less than or equal$items <= 10Left is smaller or equal

Logical Operators

OperatorMeaningExample
&&Both must be true$age >= 18 && $hasId
||At least one must be true$isAdmin || $isOwner
!Reverses a condition!$isBlocked

Details are in Comparison Operators and Logical Operators. This lesson applies them to common real-world checks.


Checking Numbers and Ranges

Basic Comparisons

<?php
$stock = 4;

if ($stock === 0) {
    echo "Out of stock\n";
} elseif ($stock < 5) {
    echo "Only $stock left\n";
} else {
    echo "In stock\n";
}

Output

Only 4 left

Ranges

PHP has no "between" operator. Combine two comparisons with &&, and decide for each boundary whether it is inclusive (<=, >=) or exclusive (<, >):

<?php
function isBetween(int|float $value, int|float $min, int|float $max): bool
{
    return $value >= $min && $value <= $max;
}

$hour = 18;

if (isBetween($hour, 9, 17)) {
    echo "Support is online\n";
} else {
    echo "Support is offline (hours: 9–17)\n";
}

var_dump(isBetween(17, 9, 17));
var_dump(isBetween(17.5, 9, 17));

Output

Support is offline (hours: 9–17)
bool(true)
bool(false)

Testing the boundary values (here 17) is the quickest way to catch off-by-one mistakes. A helper function with a clear name also documents the rule.

Numbers From Input

Input from forms and URLs is always a string. Convert and validate before comparing:

<?php
$input = '25abc';

$qty = filter_var($input, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 99]]);

if ($qty === false) {
    echo "Quantity must be a whole number from 1 to 99\n";
} else {
    echo "Adding $qty items\n";
}

Output

Quantity must be a whole number from 1 to 99

filter_var() returns an int or false. Comparing with === false matters because a valid result could be falsy in other situations (for example, 0 when zero is allowed).


Checking Strings

Exact Match

<?php
$status = 'shipped';

if ($status === 'shipped' || $status === 'delivered') {
    echo "Tracking available\n";
}

Output

Tracking available

Case-Insensitive Match

<?php
$role = 'Admin';

if (strcasecmp($role, 'admin') === 0) {
    echo "Admin access\n";
}

if (mb_strtolower($role) === 'admin') {
    echo "Admin access (normalized)\n";
}

Output

Admin access
Admin access (normalized)

strcasecmp() returns 0 when the strings are equal ignoring case. Normalizing with mb_strtolower() also works for non-English text. Even better, normalize values once when you receive them, and compare normalized values everywhere else.

Contains, Starts With, Ends With (PHP 8.0+)

<?php
$url = 'https://gocourse.in/php/if-operators';
$file = 'report.PDF';

if (str_starts_with($url, 'https://')) {
    echo "Secure URL\n";
}

if (str_contains($url, '/php/')) {
    echo "PHP section\n";
}

if (str_ends_with(strtolower($file), '.pdf')) {
    echo "PDF document\n";
}

Output

Secure URL
PHP section
PDF document

These functions return real booleans, so they can be used directly as conditions — unlike strpos(), which returns 0 for a match at the start (see Search in Strings).

Empty Strings and Whitespace

<?php
$comment = "   ";

if ($comment === '') {
    echo "Exactly empty\n";
}

if (trim($comment) === '') {
    echo "Empty or only whitespace\n";
}

Output

Empty or only whitespace

A field containing only spaces is not ''. Trim user input before checking whether it is empty.


Checking for Missing or Empty Values

PHP offers several tools that look similar but answer different questions:

CheckQuestion It Answers
isset($x)Does $x exist and is it not null?
$x === nullIs the value exactly null? (Warning if $x does not exist.)
empty($x)Is $x missing or falsy ('', '0', 0, 0.0, null, false, [])?
$x === ''Is the value exactly an empty string?
array_key_exists('k', $arr)Does the key exist, even if its value is null?
count($arr) > 0 / $arr !== []Does the array contain any elements?

How They Behave

Valueisset()empty()=== null=== ''
(undefined)falsetrueWarning, then trueWarning, then false
nullfalsetruetruefalse
''truetruefalsetrue
'0'truetruefalsefalse
0truetruefalsefalse
' ' (spaces)truefalsefalsefalse
[]truetruefalsefalse
'PHP'truefalsefalsefalse

The empty() Trap

empty() treats '0' and 0 as empty. That is wrong when zero is a meaningful answer:

<?php
$form = ['children' => '0', 'nickname' => ''];

if (empty($form['children'])) {
    echo "empty(): children is missing\n";
}

if (!isset($form['children']) || trim($form['children']) === '') {
    echo "explicit: children is missing\n";
} else {
    echo "explicit: children = {$form['children']}\n";
}

Output

empty(): children is missing
explicit: children = 0

The user answered "0 children", but empty() reports the field as missing. The explicit check treats only a missing key or a blank value as missing. Prefer explicit checks for user input; use empty() only when every falsy value really should count as empty.

Optional Values With ??

<?php
$query = [];

if (($query['debug'] ?? '') === '1') {
    echo "Debug mode\n";
} else {
    echo "Normal mode\n";
}

Output

Normal mode

?? supplies a default when the key is missing, which avoids "Undefined array key" warnings without a separate isset() call.


Checking Types

<?php
$values = [42, '42', 4.2, null, ['a'], new DateTime()];

foreach ($values as $value) {
    $type = get_debug_type($value);

    if (is_int($value)) {
        echo "$type: integer\n";
    } elseif (is_numeric($value)) {
        echo "$type: numeric (int-like or float-like)\n";
    } elseif (is_array($value)) {
        echo "$type: array with " . count($value) . " element(s)\n";
    } elseif ($value instanceof DateTimeInterface) {
        echo "$type: a date object\n";
    } elseif ($value === null) {
        echo "$type: no value\n";
    }
}

Output

int: integer
string: numeric (int-like or float-like)
float: numeric (int-like or float-like)
null: no value
array: array with 1 element(s)
DateTime: a date object
Function / Operatortrue For
is_int(), is_float(), is_string(), is_bool(), is_array()That exact type
is_numeric()Numbers and numeric strings ('42', '4.2', '1e3')
is_null()null (same as === null)
instanceofObjects of a class, subclass, or interface

Note that is_numeric() accepts strings, so '42' passes it but fails is_int(). With type declarations on function parameters, many of these checks become unnecessary, because PHP enforces the types (see Type Declarations in Functions).


Checking Membership in a List

in_array() With Strict Mode

<?php
$allowedPlans = ['free', 'pro', 'business'];
$plan = 'Pro';

if (in_array(strtolower($plan), $allowedPlans, true)) {
    echo "Valid plan\n";
}

Output

Valid plan

Always pass true as the third argument. Without it, in_array() compares loosely (==), which can match unexpected values.

Many Equality Checks → in_array() or match

Instead of:

if ($day === 'Sat' || $day === 'Sun') { ... }

write:

if (in_array($day, ['Sat', 'Sun'], true)) { ... }

The list is easier to extend and read. When each value should produce a different result, use match (see PHP Match).

Keys vs Values

<?php
$prices = ['pen' => 15, 'book' => null];

var_dump(isset($prices['book']));
var_dump(array_key_exists('book', $prices));
var_dump(in_array(15, $prices, true));

Output

bool(false)
bool(true)
bool(true)
  • isset() is false because the value is null.
  • array_key_exists() is true because the key exists.
  • in_array() searches the values, not the keys.

Combining and Negating Conditions

Group With Parentheses

<?php
$isAdmin = false;
$isAuthor = true;
$isPublished = false;

if ($isAdmin || ($isAuthor && !$isPublished)) {
    echo "You can edit this draft\n";
}

Output

You can edit this draft

&& binds more tightly than ||, so the parentheses do not change the result here — but they make the intended grouping obvious.

Negate the Whole Condition

<?php
$age = 16;
$hasConsent = false;

if (!($age >= 18 || $hasConsent)) {
    echo "Registration not allowed\n";
}

if ($age < 18 && !$hasConsent) {
    echo "Registration not allowed (simplified)\n";
}

Output

Registration not allowed
Registration not allowed (simplified)

The second form applies De Morgan's law: "not (A or B)" equals "not A and not B". Positive, simplified conditions are usually easier to read than negated groups.

Name Complex Conditions

<?php
$order = ['total' => 1800, 'country' => 'IN', 'weight_kg' => 3];

$isDomestic = $order['country'] === 'IN';
$isLight = $order['weight_kg'] <= 5;
$qualifiesByTotal = $order['total'] >= 999;

if ($isDomestic && $isLight && $qualifiesByTotal) {
    echo "Free shipping\n";
}

Output

Free shipping

Each part of the rule has a name, so the if reads like the business rule itself.


Practical Example: Validating a Signup Form

<?php
function validateSignup(array $input): array
{
    $errors = [];

    $name = trim($input['name'] ?? '');
    $email = trim($input['email'] ?? '');
    $age = filter_var($input['age'] ?? '', FILTER_VALIDATE_INT);
    $plan = $input['plan'] ?? '';
    $terms = $input['terms'] ?? null;

    if ($name === '') {
        $errors['name'] = 'Name is required.';
    } elseif (mb_strlen($name) > 50) {
        $errors['name'] = 'Name must be at most 50 characters.';
    }

    if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
        $errors['email'] = 'Enter a valid email address.';
    }

    if ($age === false || $age < 13 || $age > 120) {
        $errors['age'] = 'Age must be between 13 and 120.';
    }

    if (!in_array($plan, ['free', 'pro'], true)) {
        $errors['plan'] = 'Choose the free or pro plan.';
    }

    if ($terms !== 'yes') {
        $errors['terms'] = 'You must accept the terms.';
    }

    return $errors;
}

print_r(validateSignup([
    'name' => '   ',
    'email' => 'priya@',
    'age' => '0',
    'plan' => 'gold',
]));

print_r(validateSignup([
    'name' => 'Priya',
    'email' => 'priya@example.com',
    'age' => '24',
    'plan' => 'pro',
    'terms' => 'yes',
]));

Output

Array
(
    [name] => Name is required.
    [email] => Enter a valid email address.
    [age] => Age must be between 13 and 120.
    [plan] => Choose the free or pro plan.
    [terms] => You must accept the terms.
)
Array
(
)

How Each Condition Works

FieldConditionWhy It Is Written This Way
Nametrim(...) === '', then mb_strlen() > 50Whitespace-only names are rejected; length counts characters, not bytes
Emailfilter_var(..., FILTER_VALIDATE_EMAIL) === falseUses PHP's validator and a strict check against false
Age$age === false || $age < 13 || $age > 120false means "not an integer"; short-circuiting ensures the range checks run only on real integers
Plan!in_array($plan, [...], true)Allow-list with strict comparison
Terms$terms !== 'yes'Only the exact expected value counts as acceptance; a missing checkbox gives null

Separate if statements are used because several fields can be invalid at once, and the user should see all errors together. The elseif inside the name check is used because "required" and "too long" cannot both apply.


Common Mistakes

MistakeEffectBetter Condition
if ($x = 5)Assignment; always trueif ($x === 5)
if (strpos($s, 'a'))Match at position 0 treated as falseif (str_contains($s, 'a'))
if (empty($qty)) for numeric input0 treated as missingif (trim($qty) === '') then validate
if ($input == 0)Loose comparison with stringsValidate, then === 0
if (in_array($v, $list))Loose matchingin_array($v, $list, true)
if (!$a > 5)(!$a) > 5if (!($a > 5)) or if ($a <= 5)
`if ($a$b && $c)`Grouping unclearAdd parentheses

Best Practices

  • Use strict comparisons (===, !==) and strict in_array().
  • Trim and validate input before comparing it; compare typed values, not raw strings.
  • Choose the right existence check: isset(), ??, array_key_exists(), or an explicit === ''.
  • Avoid empty() for values where 0 or '0' are valid.
  • Prefer boolean-returning functions (str_contains(), filter_var() with strict checks) over position-returning ones in conditions.
  • Name complex conditions and use parentheses when mixing && and ||.

Official reference: https://www.php.net/manual/en/language.operators.comparison.php

0 Comments

Reviewed before they appear

No comments yet.

PHP
PHP Home PHP Switch PHP Match Alternative Syntax PHP Loops While Loop Do While Loop For Loop Foreach Loop Nested Loops Break Statement PHP Home PHP Intro PHP Install PHP Built-in Web Server PHP Syntax PHP Tags PHP and HTML PHP Comments PHP Multiline Comments PHP Variables Variables Scope PHP Casting Logical Operators Null Coalescing Operator Spaceship Operator Operator Precedence Continue Statement Modify Strings PHP If...Else...Elseif PHP If Modify Strings PHP If Operators PHP Functions Concatenate Strings PHP If...Else Slicing Strings User-defined Functions Slicing Strings PHP Shorthand if Escape Characters Default Argument Values PHP Nested if Pass by Reference String Interpolation Named Arguments PHP File Upload Variadic Functions Return Values Search in Strings Multibyte Strings Type Declarations in Functions PHP Numbers PHP Math PHP Floats PHP Random Numbers PHP Constants PHP Properties PHP Methods PHP Constructor Constructor Property Promotion PHP Cookies PHP Destructor PHP Access Modifiers Readonly Properties PHP Sessions PHP Inheritance Method Overriding PHP Filters The final Keyword CSRF Protection PHP Filters Advanced Session Security Secure Cookies PHP Magic Constants File Upload Security PHP Callback Functions PHP Operators Filesystem Security PHP JSON Arithmetic Operators Error Reporting in Production Hiding PHP Assignment Operators PHP Configuration (php.ini) Comparison Operators PHP Command Line (CLI) PHP Exceptions Increment / Decrement Operators Migrating to PHP 8 PHP Form Validation PHP Form Required PHP Form URL/E-mail Error Handling Form Input Sanitizing Escaping Output (htmlspecialchars) Custom Error Handler Checkbox, Radio and Select Inputs Sticky Forms PHP Form Complete PHP Date and Time Date Formatting
Ask about this post
AI Ask about this post

Ask questions about PHP If Operators and get answers drawn from it.

Signed-in readers only.