skip to content

Under PSR-12, in what order must a PHP file's header blocks appear, and how must declare(strict_types=1) and use imports be written?

level: middleimportance: should knowfreq 28%

answer

  1. tag, docblock, declare, namespace, imports
  2. class, then function, then const imports
  3. one blank line between blocks
  4. exactly declare(strict_types=1)
  5. no leading backslash on imports

basics

~20 s

PSR-12 orders the header as: opening tag, file docblock, declare statements, namespace, class imports, function imports, constant imports, then code, each block separated by one blank line. The declare is written exactly declare(strict_types=1), and imports never start with a backslash.

solid answer

~50 s

PSR-12 section 3 fixes the header: the opening `<?php` tag, a file-level docblock, one or more `declare` statements, the `namespace`, class-based `use` imports, `use function` imports, `use const` imports, then the rest of the code. Blocks that are not needed are omitted; those present are each separated by a **single blank line** and contain no blank line inside. The declaration MUST contain no spaces and be exactly `declare(strict_types=1)`, optionally ending with a semicolon. Imports MUST NOT begin with a leading backslash, because they are always fully qualified. Group imports are allowed, but compound namespaces deeper than two levels are not. In files that mix HTML and PHP, the strict-types declaration goes on the first line as `<?php declare(strict_types=1) ?>`. On PHP 8.4 and later, note that PSR-12's own example uses `int $b = null`, which is now deprecated; write `?int $b = null`.

code

php · 7 lines
php
<?php declare(strict_types=1) ?>
<!doctype html>
<html>
<body>
    <p><?= htmlspecialchars($title, ENT_QUOTES) ?></p>
</body>
</html>

go deeper

for a junior

Remember the order: tag, docblock, declare, namespace, class imports, function imports, constant imports. One blank line between blocks.

for a middle

Know the exact declare spelling, the no-leading-backslash rule, the two-level limit on grouped imports, and the first-line form for files mixing HTML and PHP.

for a senior

Point out what PSR-12 leaves open (import sorting, newer syntax) and where its frozen examples now clash with the language, such as implicitly nullable parameters since PHP 8.4.

for a principal

Use the fixed header as a codebase-wide invariant that tooling can rely on, for example checking that every file declares strict types in the same place.

## The header order PSR-12 section 3 lists the blocks that may form the top of a PHP file. If present, they MUST appear in this order: 1. The opening `<?php` tag. 2. The file-level docblock. 3. One or more `declare` statements. 4. The `namespace` declaration. 5. One or more class-based `use` import statements. 6. One or more function-based `use function` import statements. 7. One or more constant-based `use const` import statements. 8. The remainder of the code. Each block that is present MUST be separated from the next by **a single blank line** and MUST NOT contain a blank line itself. Irrelevant blocks are simply left out. When `<?php` is on the first line, it MUST be on its own line unless the file contains markup outside PHP tags. ## A compliant header ```php <?php /** * Invoice export for the billing module. */ declare(strict_types=1); namespace Acme\Billing\Export; use Acme\Billing\{Invoice, InvoiceLine}; use Psr\Log\LoggerInterface; use function Acme\Billing\formatMoney; use function sprintf; use const Acme\Billing\DEFAULT_CURRENCY; final class CsvExporter { // ... } ``` ## The declare rules - Declare statements MUST contain **no spaces** and MUST be **exactly** `declare(strict_types=1)`, with an optional semicolon. `declare(strict_types = 1);` is not compliant. - In a file that contains markup outside PHP tags, the strict-types declaration MUST be on the first line, with the opening tag, the declaration and the closing tag together: `<?php declare(strict_types=1) ?>`. - Block declare statements, such as `declare(ticks=1) { ... }`, are allowed with the brace on the same line. The formatting is PSR-12's concern; what `strict_types` changes about type checking is a separate topic in the language itself. ## The import rules | Rule | Compliant | Not compliant | |---|---|---| | no leading backslash | `use Acme\Billing\Invoice;` | `use \Acme\Billing\Invoice;` | | separate blocks by kind | classes, blank line, `use function`, blank line, `use const` | functions mixed in with class imports | | group depth at most two | `use Vendor\Package\SomeNamespace\{SubnamespaceOne\ClassA, ClassZ};` | a group entry such as `SubnamespaceOne\AnotherNamespace\ClassA` | | one blank line around each block | as above | imports glued to the namespace line | Imports are always fully qualified from the root namespace, which is why a leading backslash adds nothing and is forbidden. ## Reading a non-compliant header ```php <?php namespace Acme\Billing; declare(strict_types = 1); use \Acme\Billing\Invoice; use function sprintf; use Psr\Log\LoggerInterface; ``` This header breaks PSR-12 in several ways: 1. `declare` comes after `namespace`; declares belong before it. 2. `declare(strict_types = 1)` contains spaces; it must be exactly `declare(strict_types=1)`. 3. `use \Acme\...` has a leading backslash. 4. A `use function` import sits between class imports; class imports come first as one block, then function imports. 5. There are no blank lines separating the blocks. Beyond style, PHP itself rejects this file: `declare(strict_types=1)` must be the very first statement in a file, so placing it after `namespace` is a fatal compile error, not only a PSR-12 violation. ## Things PSR-12 does not settle - **Ordering within a block**: PSR-12 does not require alphabetical order. Many teams add it through their tooling. - **Unused imports**: not addressed by PSR-12; tools can remove them. - **Newer syntax**: PSR-12 is frozen, so later features fall to PER Coding Style. ## A trap in PSR-12's own example The overview example of PSR-12 declares `public function sampleFunction(int $a, int $b = null): array`. That was normal when PSR-12 was accepted, but an **implicitly nullable parameter**, a typed parameter whose default is `null` without a `?` or `|null`, is **deprecated since PHP 8.4**. On PHP 8.5, write `?int $b = null` or `int|null $b = null`. Copying the example verbatim produces deprecation notices; it is a reminder that a frozen style guide can age faster than the language. ## Why the header is standardised A fixed header lets a reader find the namespace and dependencies of any file at a glance, keeps diffs of import changes small and predictable, and makes `declare(strict_types=1)` easy to check for across a codebase, since it always sits in the same place, spelled the same way.

  • Is `declare(strict_types = 1);` PSR-12 compliant?
    No. PSR-12 requires declare statements to contain no spaces and to be exactly `declare(strict_types=1)`, with an optional semicolon. PHP accepts the spaced form without complaint, which is why a style checker is the only thing that catches it.
  • Does PSR-12 require imports to be sorted alphabetically?
    No. It fixes the order of the blocks (class imports, then `use function`, then `use const`) and the blank lines between them, but not the order of statements within a block. Alphabetical sorting is a common team addition, usually enforced by the same tooling that applies PSR-12.

saying these in an interview costs you the question

  • Writes declare(strict_types = 1) with spaces and calls it PSR-12 compliant.
  • Starts import statements with a leading backslash.
  • Puts use function imports before class imports.
  • Places declare(strict_types=1) after the namespace declaration.
  • Copies PSR-12's int $b = null example unchanged into PHP 8.4+ code.