Alternative Syntax
What Is the Alternative Syntax? In simple terms: PHP offers a second way to write control structures — if , foreach , for , while , and switch — that uses a colon ( : ) to open the block and a keyword
What Is the Alternative Syntax?
In simple terms: PHP offers a second way to write control structures — if, foreach, for, while, and switch — that uses a colon (:) to open the block and a keyword such as endif; or endforeach; to close it, instead of curly braces.
Technically: For if, while, for, foreach, and switch, the opening brace { can be replaced with : and the closing brace } with endif;, endwhile;, endfor;, endforeach;, or endswitch;. The behavior is identical; only the syntax differs.
| Brace Syntax | Alternative Syntax |
|---|---|
if (...) { ... } | if (...): ... endif; |
elseif (...) { ... } | elseif (...): ... |
else { ... } | else: ... |
foreach (...) { ... } | foreach (...): ... endforeach; |
for (...) { ... } | for (...): ... endfor; |
while (...) { ... } | while (...): ... endwhile; |
switch (...) { ... } | switch (...): ... endswitch; |
Why It Exists
In files that mix PHP and HTML, a closing brace on its own line says nothing about what it closes:
<?php } ?>
<?php } ?>
<?php } ?>
In a long template, matching these braces to their opening statements is difficult. The alternative syntax names each block's end:
<?php endif; ?>
<?php endforeach; ?>
<?php endif; ?>
That is why the alternative syntax is the standard for PHP templates, including WordPress themes and the plain-PHP view files of many frameworks.
if, elseif, else
Syntax
<?php if (condition): ?>
... HTML ...
<?php elseif (otherCondition): ?>
... HTML ...
<?php else: ?>
... HTML ...
<?php endif; ?>
Example
<?php $unread = 3; ?>
<?php if ($unread === 0): ?>
<p>No new messages.</p>
<?php elseif ($unread === 1): ?>
<p>You have 1 new message.</p>
<?php else: ?>
<p>You have <?= $unread ?> new messages.</p>
<?php endif; ?>
Output (HTML)
<p>You have 3 new messages.</p>
How It Works
- Each condition line ends with
:instead of{. elseifandelsealso end with:.endif;closes the whole structure.- Only the HTML of the matching branch is sent to the browser.
Important: In the alternative syntax, write
elseifas one word.else if (...):causes a parse error, becauseelse ifis really anelsecontaining a newif, which would need its ownendif;.
foreach ... endforeach
<?php
$menu = [
'Home' => '/',
'Courses' => '/courses',
'Contact' => '/contact',
];
$current = '/courses';
?>
<ul class="menu">
<?php foreach ($menu as $label => $url): ?>
<li><a href="<?= $url ?>"<?= $url === $current ? ' class="active"' : '' ?>><?= $label ?></a></li>
<?php endforeach; ?>
</ul>
Output (HTML)
<ul class="menu">
<li><a href="/">Home</a></li>
<li><a href="/courses" class="active">Courses</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
The loop body is plain HTML with short echo tags. A ternary adds class="active" only to the current page's link.
for ... endfor
<?php $totalSteps = 3; ?>
<?php for ($step = 1; $step <= $totalSteps; $step++): ?>
<span class="step">Step <?= $step ?> of <?= $totalSteps ?></span>
<?php endfor; ?>
Output (HTML)
<span class="step">Step 1 of 3</span>
<span class="step">Step 2 of 3</span>
<span class="step">Step 3 of 3</span>
while ... endwhile
The alternative syntax works in pure PHP code as well, although braces are far more common there:
<?php
$countdown = 3;
while ($countdown > 0):
echo "$countdown...\n";
$countdown--;
endwhile;
echo "Go!\n";
Output
3...
2...
1...
Go!
In non-template code, coding standards generally recommend braces. Use the alternative syntax where it improves readability — mainly when switching between PHP and HTML.
switch ... endswitch
<?php $role = 'editor'; ?>
<nav>
<?php switch ($role):
case 'admin': ?>
<a href="/admin">Admin panel</a>
<?php break;
case 'editor': ?>
<a href="/posts">Manage posts</a>
<?php break;
default: ?>
<a href="/profile">My profile</a>
<?php endswitch; ?>
</nav>
Output (HTML)
<nav>
<a href="/posts">Manage posts</a>
</nav>
The Whitespace Rule for switch
PHP does not allow any output — not even whitespace or a newline — between switch (...): and the first case. Writing them in separate PHP blocks with indentation in between causes a parse error:
<?php switch ($role): ?>
<?php case 'admin': ?> <!-- the spaces before this line are output -->
The safe pattern, shown in the example above, keeps switch (...): and the first case inside the same PHP block. Because of this quirk, if/elseif or a match expression that selects a value is often simpler than switch in templates.
Do Not Mix the Two Syntaxes in One Structure
A single control structure must use one syntax throughout:
<?php if ($isLoggedIn): ?>
<p>Welcome!</p>
<?php else { ?> <!-- parse error -->
<p>Please log in.</p>
<?php } ?>
Different structures may use different syntaxes (for example, a braced if in the logic section and an alternative-syntax foreach in the template), but each one must be consistent from start to end.
Whitespace in Templates
PHP removes one newline directly after ?>. This is why lines that contain only a PHP control tag, such as <?php endif; ?>, do not leave blank lines in the output. Two consequences are worth knowing:
- A line that ends with
<?= $value ?>loses its newline, so the next line's content is joined to it. Ending such lines with HTML (for example</span>) keeps the line breaks. - Indentation before a
<?phptag is output as text. It does not matter for HTML rendering, but it can affect whitespace-sensitive output such as plain-text emails.
HTML rendering ignores most whitespace differences, so this mainly affects how the generated source looks.
Practical Example: Product Listing Template
<?php
$products = [
['name' => 'Desk Lamp', 'price' => 1299, 'stock' => 4],
['name' => 'Notebook <A5>', 'price' => 60, 'stock' => 0],
];
?>
<?php if ($products === []): ?>
<p>No products found.</p>
<?php else: ?>
<ul class="products">
<?php foreach ($products as $product): ?>
<li class="<?= $product['stock'] > 0 ? 'in-stock' : 'sold-out' ?>">
<span class="name"><?= htmlspecialchars($product['name']) ?></span>
<span class="price">₹<?= number_format($product['price']) ?></span>
<?php if ($product['stock'] === 0): ?>
<span class="badge">Sold out</span>
<?php elseif ($product['stock'] < 5): ?>
<span class="badge">Only <?= $product['stock'] ?> left</span>
<?php endif; ?>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
Output (HTML)
<ul class="products">
<li class="in-stock">
<span class="name">Desk Lamp</span>
<span class="price">₹1,299</span>
<span class="badge">Only 4 left</span>
</li>
<li class="sold-out">
<span class="name">Notebook <A5></span>
<span class="price">₹60</span>
<span class="badge">Sold out</span>
</li>
</ul>
Step-by-Step Explanation
- Data first: the PHP block at the top prepares the data. In a real application, it would come from a database, and the template would contain only presentation.
- Empty state:
if ($products === []): ... else:shows a message when there is nothing to list. Always handling the empty case avoids rendering an empty<ul>. - Loop:
foreach ... endforeach;repeats the<li>block for each product. - Conditional class: a ternary inside
<?= ?>choosesin-stockorsold-outfor styling. - Escaping:
htmlspecialchars()converts<A5>into<A5>, so a product name can never break the HTML or inject a script. - Badges: a nested
if ... elseif ... endif;shows "Sold out" or a low-stock warning, and nothing for well-stocked items. - Clean output: each line that contains only a control tag ends with
?>, so its newline is removed and no blank lines appear.
Every closing tag (endif;, endforeach;) tells the reader exactly which structure is ending, even in a much longer template.
Alternative Syntax and Template Engines
Template engines provide even more compact syntax built on the same idea, and they escape output automatically:
| Plain PHP (alternative syntax) | Blade (Laravel) | Twig (Symfony) |
|---|---|---|
<?php if ($x): ?> | @if ($x) | {% if x %} |
<?php endif; ?> | @endif | {% endif %} |
<?php foreach ($items as $item): ?> | @foreach ($items as $item) | {% for item in items %} |
<?= htmlspecialchars($name) ?> | {{ $name }} | {{ name }} |
Learning the alternative syntax makes these engines easy to understand, because they follow the same structure.
Common Mistakes
Writing else if: Instead of elseif:
Effect: Parse error.
Fix: Use elseif (...):.
Forgetting the Semicolon After endif, endforeach, …
Effect: Usually works when the closing ?> follows immediately (because ?> implies a semicolon), but fails in pure PHP code.
Fix: Always write endif;, endforeach;, and so on.
Mixing Braces and Alternative Syntax in One Structure
Effect: Parse error.
Fix: Use one syntax per structure.
Output Between switch and the First case
Effect: Parse error.
Fix: Put switch (...): and the first case in the same PHP block, or use if/elseif.
Forgetting to Escape Output in Templates
Effect: Broken HTML and XSS vulnerabilities.
Fix: Wrap every external value in htmlspecialchars() (or use a template engine that escapes automatically).
Best Practices
- Use the alternative syntax in HTML templates; use braces in pure PHP logic.
- Keep logic (queries, calculations) above or outside the template; keep templates to loops, conditions, and output.
- Always handle the empty state of lists.
- Escape every dynamic value with
htmlspecialchars(). - Use
elseifas one word and end every structure with its matchingend...;keyword.
Official reference: https://www.php.net/manual/en/control-structures.alternative-syntax.php