Why PHP Doesn't Need a Closing ?> Tag — And Why That's Actually a Good Thing

If you've written PHP inside a .php file and noticed that omitting the closing ?> tag doesn't break anything, you're not imagining it. The file runs perfectly, output is correct, and PHP doesn't complain. VS Code might not even flag it as an issue.

So what's going on?


First, Understand What ?> Actually Does

The closing tag ?> is an instruction to the PHP parser — it says:

"Stop processing PHP here. Everything after this point is raw HTML/text — send it directly to the output buffer."

So in a mixed HTML + PHP file, it makes perfect sense:


    <?php
    $name = "Gagan";
    ?>
    <h1>Hello, <?php echo $name; ?></h1>
    <p>Welcome to my site.</p>

Here ?> is necessary because you're switching between PHP mode and HTML mode multiple times. The parser needs to know when to stop treating content as PHP code.


So Why Does a Pure PHP File Work Without It?

When your file contains only PHP — no HTML after the last line — the parser reaches the end of the file and simply stops. There is no HTML waiting to be sent, nothing to switch to. The closing tag's job was already done by the file ending.

PHP's parser behavior is:

"If I reach EOF while still in PHP mode, that's fine. I'll just stop here."


    <?php

    class UserService
    {
        public function getUser(int $id): array
        {
            return ['id' => $id, 'name' => 'Gagan'];
        }
    }

No ?> at the bottom. PHP reads the opening <?php, processes everything, hits EOF, and exits cleanly. Full success.


The Real Reason You Should OMIT ?>

This is where it gets interesting — and practical.

The Whitespace / Newline Problem

When you add ?> at the end of a file, PHP does something you might not expect. Any whitespace, newline, or blank line that exists after the closing tag gets sent to the output buffer as raw content.

   
    <?php

    function add(int $a, int $b): int
    {
        return $a + $b;
    }

    ?>

See that blank line after ?>? PHP sends that as output. A literal \n character is now part of your response — before any of your actual intended output.

Now imagine this file is included in a larger application:


    <?php
    // some-functions.php is included here
    require_once 'some-functions.php';

    header('Content-Type: application/json');
    echo json_encode(['status' => 'ok']);

You'll get this error:

Warning: Cannot modify header information - headers already sent by
(output started at some-functions.php:9)

A single invisible newline broke your headers. This kind of bug is notoriously difficult to track down, especially in large codebases where files are required/included across many layers.

The fix? Never add ?> in the first place.


What PSR-12 Says

PHP-FIG's PSR-12 standard is explicit about this:

"A file SHOULD either declare symbols (classes, functions, constants, etc.) or cause side-effects (e.g. generate output, change .ini settings, etc.) but SHOULD NOT do both. The closing ?> tag MUST be omitted from files containing only PHP."

Laravel, Symfony, WordPress (modern code), and virtually every professional PHP codebase follow this rule. If you open any controller, model, or service class in Laravel, you will never see a closing ?>.


When IS ?> Required?

Only in one scenario — files that intentionally mix PHP and HTML, like template files:


    <!DOCTYPE html>
    <html>

    <head>
        <title><?php echo $pageTitle; ?></title>
    </head>

    <body>
        <?php if ($isLoggedIn): ?>
            <p>Welcome, <?php echo $userName; ?></p>
        <?php else: ?>
            <p>Please log in.</p>
        <?php endif; ?>
    </body>

    </html>

Here, ?> is doing real work — it's toggling the parser between PHP mode and HTML output mode. You need it here. But notice — even this file doesn't need a closing ?> at the very end, because there's no PHP block left to close after the final HTML line.


Summary Table

File Type

Closing ?>

Pure PHP class / service / controller

Omit — always

Pure PHP config / constants file

Omit — always

PHP + HTML mixed template

Use it between blocks, omit at end

PHP file included via require / include

Omit — headers risk



The Bottom Line

PHP was designed to be embedded inside HTML, which is why ?> exists at all. But when a file is pure PHP, the closing tag is not just unnecessary — it's a silent bug waiting to happen. An accidental newline after it can corrupt headers, break JSON responses, and ruin session handling.

VS Code removing it automatically (or not flagging its absence) isn't a quirk — it's the editor agreeing with PSR-12. Omit the closing tag in every pure PHP file, every time, without exception.

No comments:

Post a Comment

PHP & Laravel — Zero to Hero Episode 15: Installing Laravel on Windows 11 — Complete Guide

What Are We Doing in This Post? Core PHP is done. Fourteen episodes of solid foundation. Now we install Laravel. But here is the honest trut...