Making a decision
Programs need to react differently to different situations: show "out of stock" when stock is zero, charge shipping only on small orders, let only signed-in users see their account. The if statement runs a block of code only when a condition is true:
<?php
$stock = 0;
if ($stock === 0) {
echo "Out of stock\n";
}
echo "Done\n";Out of stock
DoneThe condition goes in round brackets, and the code to run goes in curly braces. When the condition is false, PHP skips the block and carries on after it.
else
else gives an alternative block that runs when the condition is false. Exactly one of the two blocks runs:
<?php
$cartTotal = 420;
if ($cartTotal >= 500) {
echo "Free shipping\n";
} else {
$missing = 500 - $cartTotal;
echo "Add $missing more for free shipping\n";
}Add 80 more for free shippingelseif
For more than two possibilities, chain conditions with elseif. PHP tests them from top to bottom and runs the first block whose condition is true, then jumps past the rest of the chain:
<?php
function grade(int $score): string
{
if ($score >= 90) {
return "A";
} elseif ($score >= 75) {
return "B";
} elseif ($score >= 50) {
return "C";
} else {
return "Fail";
}
}
foreach ([95, 80, 75, 40] as $score) {
echo "$score: " . grade($score) . "\n";
}95: A
80: B
75: B
40: FailOrder matters. A score of 95 is also at least 75 and at least 50, but only the first matching branch runs. If you put $score >= 50 first, everyone would get a C. Write the most specific condition first.
You can write else if as two words; with braces it behaves the same as elseif.
Conditions and truthiness
The condition can be any expression. PHP converts its result to a boolean, using the rules from Data types and var_dump: 0, 0.0, '', '0', null, [] and false are false, everything else is true. That allows short checks such as "is the list empty?":
<?php
$cart = [];
if ($cart) {
echo "You have items\n";
} else {
echo "Your cart is empty\n";
}
$coupon = "0";
if ($coupon) {
echo "Coupon: $coupon\n";
} else {
echo "No coupon (the string '0' counts as false!)\n";
}Your cart is empty
No coupon (the string '0' counts as false!)The second case shows why explicit comparisons are often clearer: if ($coupon !== '') says exactly what you mean.
Combining conditions
Use && (and), || (or) and ! (not) from the Operators lesson to combine checks. Brackets make mixed conditions readable:
<?php
$age = 17;
$withParent = true;
$isHoliday = false;
if ($age >= 18 || ($age >= 12 && $withParent)) {
echo "Can enter\n";
}
if (!$isHoliday) {
echo "Shop is open\n";
}Can enter
Shop is openNesting and early returns
An if can contain another if. A little nesting is fine, but several levels quickly become hard to follow:
<?php
if ($user !== null) {
if ($user['active']) {
if ($user['balance'] >= $price) {
echo "Purchase complete";
} else {
echo "Not enough balance";
}
} else {
echo "Account disabled";
}
} else {
echo "Please sign in";
}The same logic is easier to read when the problem cases are handled first and the function returns straight away. This is called using guard clauses or early returns:
<?php
function buy(?array $user, float $price): string
{
if ($user === null) {
return "Please sign in";
}
if (!$user['active']) {
return "Account disabled";
}
if ($user['balance'] < $price) {
return "Not enough balance";
}
return "Purchase complete";
}
echo buy(null, 10) . "\n";
echo buy(['active' => true, 'balance' => 5.0], 10) . "\n";
echo buy(['active' => true, 'balance' => 50.0], 10) . "\n";Please sign in
Not enough balance
Purchase completeEach condition can be read on its own, and the normal path, the purchase, is at the bottom with no indentation.
The alternative syntax
In HTML templates you will see a second way of writing if, with a colon and endif. It reads more cleanly between HTML tags:
<?php if ($stock > 0): ?>
<p class="ok">In stock</p>
<?php else: ?>
<p class="sold-out">Sold out</p>
<?php endif; ?>It behaves exactly like the brace version. Mixing PHP and HTML uses it.
Common mistakes
- Using = instead of === in a condition, which assigns and is almost always true.
- Wrong order in an elseif chain, so a broad condition hides the specific ones after it.
- Forgetting that "0" is false when testing form input.
- Adding a semicolon after the condition:
if ($x > 5); { ... }ends theifimmediately and always runs the block.
Exercise
Write a function shippingFee(float $total, string $country): float that returns 0 for Indian orders of 500 or more, 49 for other Indian orders, 15 for orders to the UK and 20 for anywhere else. Print the fee for (300, India), (800, India), (800, UK) and (800, Japan).
Show one possible answer
<?php
function shippingFee(float $total, string $country): float
{
if ($country === "India") {
return $total >= 500 ? 0 : 49;
}
if ($country === "UK") {
return 15;
}
return 20;
}
foreach ([[300, "India"], [800, "India"], [800, "UK"], [800, "Japan"]] as [$total, $country]) {
echo "$country $total: " . shippingFee($total, $country) . "\n";
}India 300: 49
India 800: 0
UK 800: 15
Japan 800: 20Key points
- if runs a block only when its condition is true. else runs when it is false.
- elseif adds more conditions; PHP checks them in order and runs only the first that is true.
- Conditions are converted to bool, so remember the falsy values: 0, '', '0', null, [] and false.
- Deep nesting is hard to read. Handle the exceptional cases first and return or continue early.