php.psr-12.lab

PHP.PSR-12.lab

Laboratory of PSR-12: Extended Coding Style.

This repository is a standalone part of a larger project: PHP.lab β€” a curated knowledge base and laboratory for PHP engineering.

Usage

To run the example application with Docker use command:

docker compose up -d

After creating the Docker container the Composer dependencies have to be defined and installed:

docker compose exec application composer require --dev squizlabs/php_codesniffer \
&& docker compose application composer install

Tom make PHP Code Sniffer commands easily accessible run:

docker compose exec application ln -s /var/www/vendor/bin/phpcs /usr/local/bin/phpcs \
&& docker compose exec application ln -s /var/www/vendor/bin/phpcbf /usr/local/bin/phpcbf

To run PHP Code Sniffer use command:

docker compose exec application /var/www/vendor/bin/phpcs

or, if the shortcut has been created:

docker compose exec application phpcs

To update Composer dependencies use command (should be done before the command below):

docker compose exec application composer update

To login into the Docker container use command:

docker exec -it psr-1-example-app /bin/bash

License

This project is licensed under the GPL-3.0 - see LICENSE.md.

Official documentation

PHP-FIG PRS-12 Official documentation

What are PSRs

PSR stands for PHP Standard Recommendation.

Overview

This specification extends, expands and replaces PSR-2, the coding style guide and requires adherence to PSR-1, the basic coding standard.

Like PSR-2, the intent of this specification is to reduce cognitive friction when scanning code from different authors. It does so by enumerating a shared set of rules and expectations about how to format PHP code. This PSR seeks to provide a set way that coding style tools can implement, projects can declare adherence to and developers can easily relate to between different projects. When various authors collaborate across multiple projects, it helps to have one set of guidelines to be used among all those projects. Thus, the benefit of this guide is not in the rules themselves but the sharing of those rules.

PSR-2 was accepted in 2012 and since then a number of changes have been made to PHP which has implications for coding style guidelines. Whilst PSR-2 is very comprehensive of PHP functionality that existed at the time of writing, new functionality is very open to interpretation. This PSR, therefore, seeks to clarify the content of PSR-2 in a more modern context with new functionality available, and make the errata to PSR-2 binding.

Previous language versions

Throughout this document, any instructions MAY be ignored if they do not exist in versions of PHP supported by your project.

Example

This example encompasses some of the rules below as a quick overview:

<?php

declare(strict_types=1);

namespace Vendor\Package;

use Vendor\Package\{ClassA as A, ClassB, ClassC as C};
use Vendor\Package\SomeNamespace\ClassD as D;

use function Vendor\Package\{functionA, functionB, functionC};

use const Vendor\Package\{ConstantA, ConstantB, ConstantC};

class Foo extends Bar implements FooInterface
{
    public function sampleFunction(int $a, int $b = null): array
    {
        if ($a === $b) {
            bar();
        } elseif ($a > $b) {
            $foo->bar($arg1);
        } else {
            BazClass::bar($arg2, $arg3);
        }
    }

    final public static function bar()
    {
        // method body
    }
}

– PSR Documentation

The PSR-1 documentation within the PHP.lab project is here

General

Code MUST follow all rules outlined in PSR-1. πŸ”—

The term StudlyCaps in PSR-1 MUST be interpreted as PascalCase where the first letter of each word is capitalized including the very first letter. πŸ”—

Files

✀ File ending character

All PHP files MUST use the Unix LF (linefeed) line ending only. πŸ”—

A newline (frequently called line ending, end of line (EOL), next line (NEL) or line break) is a control character or sequence of control characters in character encoding specifications such as ASCII, EBCDIC, Unicode, etc. This character, or a sequence of characters, is used to signify the end of a line of text and the start of a new one.

The Unicode standard defines a number of characters that conforming applications should recognize as line terminators:

LF is recognized by POSIX standard oriented systems: Unix and Unix-like systems (Linux, macOS, *BSD, AIX, Xenix, etc.), QNX 4+, Multics, BeOS, Amiga, RISC OS, and others.

CR+LF is recognized by Windows, MS-DOS compatibles, Atari TOS, DEC TOPS-10, RT-11, CP/M, MP/M, OS/2, Symbian OS, Palm OS, Amstrad CPC, and most other early non-Unix and non-IBM operating systems

The line ending character can be set in the code editor or IDE settings (usually it is LF by default).

✀ File ending line

All PHP files MUST end with a non-blank line, terminated with a single LF. πŸ”—

index.php

<?php

require_once (__DIR__ . '/../vendor/autoload.php');

use PHPLab\StandardPSR12\HtmlDoc;
use PHPLab\StandardPSR12\HtmlDocAuthor;

$htmlDoc = new HtmlDoc();
$htmlDocAuthor = new HtmlDocAuthor();
$htmlDoc->setAuthor($htmlDocAuthor);

require_once('view.php');

✀ Omitting of the ending PHP tag ?>

The closing ?> tag MUST be omitted from files containing only PHP. πŸ”—

HtmlDocAuthor.php

<?php

namespace PHPLab\StandardPSR1;

class HtmlDocAuthor
{
    const EMAIL_DOMAIN = 'php.lab';

    public $name = 'Some Author';
    public $email = 'author@' . self::EMAIL_DOMAIN;
}

Lines

✀ Line length hard limit

There MUST NOT be a hard limit on line length. πŸ”—

✀ Line lenght soft limit

The soft limit on line length MUST be 120 characters. πŸ”—

✀ Line length recomended limit

Lines SHOULD NOT be longer than 80 characters. πŸ”—

Lines longer than that SHOULD be split into multiple subsequent lines of no more than 80 characters each. πŸ”—

✀ Trailing whitespaces at the end of lines

There MUST NOT be trailing whitespace at the end of lines πŸ”—

✀ Blank lines for redability

Blank lines MAY be added to improve readability and to indicate related blocks of code except where explicitly forbidden. πŸ”—

index.php

<?php

require_once (__DIR__ . '/../vendor/autoload.php');

use PHPLab\StandardPSR12\HtmlDoc;
use PHPLab\StandardPSR12\HtmlDocAuthor;

$htmlDoc = new HtmlDoc();
$htmlDocAuthor = new HtmlDocAuthor();
$htmlDoc->setAuthor($htmlDocAuthor);

require_once('view.php');

HtmlDocAuthor.php

<?php

namespace PHPLab\StandardPSR1;

class HtmlDocAuthor
{
    const EMAIL_DOMAIN = 'php.lab';

    public $name = 'Some Author';
    public $email = 'author@' . self::EMAIL_DOMAIN;
}

✀ Allowed number of statements per line

There MUST NOT be more than 1 statement per line. πŸ”—

index.php

<?php

require_once (__DIR__ . '/../vendor/autoload.php');

use PHPLab\StandardPSR12\HtmlDoc;
use PHPLab\StandardPSR12\HtmlDocAuthor;

$htmlDoc = new HtmlDoc();
$htmlDocAuthor = new HtmlDocAuthor();
$htmlDoc->setAuthor($htmlDocAuthor);

require_once('view.php');

Indenting

✀ Indenting character

Code MUST use spaces for indenting and MUST NOT use tabs for indenting. πŸ”—

MUST NOT use tabs for indenting.

✀ Indenting length

Code MUST use an indent of 4 spaces for each indent level. πŸ”—

HtmlDoc.php

<?php

namespace PHPLab\StandardPSR1;

class HtmlDoc
{
    public $languageCode = 'en-GB';
    public $charset = 'utf-8';
    public $language = 'english';
    public $description = 'PSR-1 example document';
    public $keywords = 'php,psr,psr-1';
    public $author;
    public $title = 'Some PSR-1 example page';
    public $header = 'PSR-1 example';
    public $footer = 'Copyright PHP.lab 2024';
    public $content = 'Hi, there!';

    public function setAuthor($htmlDocAuthor)
    {
        $this->author = [
            'name' => $htmlDocAuthor->name,
            'email' => $htmlDocAuthor->email,
        ];
    }
}

Header of a PHP file

✀ Header of a PHP file contents

The header of a PHP file may consist of a number of different blocks. πŸ”—

✀ Blank line separators of the blocks in a header of a PHP file

If present, each of the blocks MUST be separated by a single blank line and MUST not contain a blank line. πŸ”—

✀ Order of the blocks in a header of a PHP file

Each block MUST be in the order listed below, although blocks that are not relevant may be omitted:

HtmlDoc.php

<?php

/*
 * This file is part of the PHP.lab package.
 *
 * (c) 2026 Katarzyna KrasiΕ„ska <katheroine@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

declare(strict_types=1);

namespace PHPLab\StandardPSR12;

use PHPLab\StandardPSR12\HtmlDocAuthor;

class HtmlDoc
{
}

✀ Header of the files with mix of HTML and PHP

When a file contains a mix of HTML and PHP, any of the above sections may still be used. πŸ”—

If so, they MUST be present at the top of the file, even if the remainder of the code consists of a closing PHP tag and then a mixture of HTML and PHP. πŸ”—

view.php

<?php

/*
 * This file is part of the PHP.lab package.
 *
 * (c) 2026 Katarzyna KrasiΕ„ska <katheroine@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

declare(strict_types=1);

namespace PHPLab\StandardPSR12;

use PHPLab\StandardPSR12\HtmlDocAuthor;

$htmlDoc = new HtmlDoc();
$htmlDocAuthor = new HtmlDocAuthor();
$htmlDoc->setAuthor($htmlDocAuthor);

?>
<!doctype html>
<html lang="<?= $htmlDoc->languageCode ?>">
  <head>
    <meta charset="<?= $htmlDoc->charset ?>">
    <meta name="language" content="<?= $htmlDoc->language ?>">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="<?= $htmlDoc->description ?>">
    <meta name="keywords" content="<?= $htmlDoc->keywords ?>">
    <meta name="author" content="<?= $htmlDoc->author['name'] ?> <<?= $htmlDoc->author['email'] ?>>">
    <title><?= $htmlDoc->title ?></title>
  </head>
  <body>
    <?php if (isset($htmlDoc->header)): ?>
    <header>
        <?= $htmlDoc->header ?>
    </header>
    <?php endif; ?>
    <?php if (isset($htmlDoc->content)): ?>
    <div id="content">
        <?= $htmlDoc->content ?>
    </div>
    <?php endif; ?>
    <?php if (isset($htmlDoc->footer)): ?>
    <footer>
        <?= $htmlDoc->footer ?>
    </footer>
    <?php endif; ?>
  </body>
</html>

✀ Opening <?php tag

When the opening <?php tag is on the first line of the file, it MUST be on its own line with no other statements unless it is a file containing markup outside of PHP opening and closing tags. πŸ”—

Directives

✀ Declare statements formatting

Declare statements MUST contain no spaces and MUST be exactly declare(strict_types=1) (with an optional semi-colon terminator). πŸ”—

HtmlDocAuthor.php

<?php

declare(strict_types=1);

namespace PHPLab\StandardPSR12;

class HtmlDocAuthor
{
    const EMAIL_DOMAIN = 'php.lab';

    public $name = 'Some Author';
    public $email = 'author@' . self::EMAIL_DOMAIN;
}

✀ Block declare statements formatting

Block declare statements are allowed and MUST be formatted as below. Note position of braces and spacing:

declare(ticks=1) {

Β Β Β Β // some code

}

πŸ”—

✀ Strict types declaration formatting in files containing markup outside PHP opening and closing tags

When wishing to declare strict types in files containing markup outside PHP opening and closing tags, the declaration MUST be on the first line of the file and include an opening PHP tag, the strict types declaration and closing tag. πŸ”—

For example:

<?php declare(strict_types=1) ?>
<html>
<body>
    <?php
        // ... additional PHP code ...
    ?>
</body>
</html>

– PSR Documentation

view.php

<?php declare(strict_types=1) ?>
<!doctype html>
<html lang="<?= $htmlDoc->languageCode ?>">
  <head>
    <meta charset="<?= $htmlDoc->charset ?>">
    <meta name="language" content="<?= $htmlDoc->language ?>">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="<?= $htmlDoc->description ?>">
    <meta name="keywords" content="<?= $htmlDoc->keywords ?>">
    <meta name="author" content="<?= $htmlDoc->author['name'] ?> <<?= $htmlDoc->author['email'] ?>>">
    <title><?= $htmlDoc->title ?></title>
  </head>
  <body>
    <?php if (isset($htmlDoc->header)): ?>
    <header>
        <?= $htmlDoc->header ?>
    </header>
    <?php endif; ?>
    <?php if (isset($htmlDoc->content)): ?>
    <div id="content">
        <?= $htmlDoc->content ?>
    </div>
    <?php endif; ?>
    <?php if (isset($htmlDoc->footer)): ?>
    <footer>
        <?= $htmlDoc->footer ?>
    </footer>
    <?php endif; ?>
  </body>
</html>

Imports

The following example illustrates a complete list of all blocks:

<?php

/**
 * This file contains an example of coding styles.
 */

declare(strict_types=1);

namespace Vendor\Package;

use Vendor\Package\{ClassA as A, ClassB, ClassC as C};
use Vendor\Package\SomeNamespace\ClassD as D;
use Vendor\Package\AnotherNamespace\ClassE as E;

use function Vendor\Package\{functionA, functionB, functionC};
use function Another\Vendor\functionD;

use const Vendor\Package\{CONSTANT_A, CONSTANT_B, CONSTANT_C};
use const Another\Vendor\CONSTANT_D;

/**
 * FooBar is an example class.
 */
class FooBar
{
    // ... additional PHP code ...
}

– PSR Documentation

✀ Use declarations placement

Import statements MUST never begin with a leading backslash. πŸ”—

use \PHPLab\StandardPSR12\HtmlDoc;
use \PHPLab\StandardPSR12\HtmlDocAuthor;
use PHPLab\StandardPSR12\HtmlDoc;
use PHPLab\StandardPSR12\HtmlDocAuthor;
✀ Fully qualified import statements

Import statements MUST always be fully qualified. πŸ”—

use StandardPSR12\HtmlDoc;
use HtmlDocAuthor;
use PHPLab\StandardPSR12\HtmlDoc;
use PHPLab\StandardPSR12\HtmlDocAuthor;
✀ Import with compound namespaces

Compound namespaces with a depth of more than two MUST NOT be used. πŸ”—

Therefore the following is the maximum compounding depth allowed:

<?php

use Vendor\Package\SomeNamespace\{
    SubnamespaceOne\ClassA,
    SubnamespaceOne\ClassB,
    SubnamespaceTwo\ClassY,
    ClassZ,
};

And the following would not be allowed:

<?php

use Vendor\Package\SomeNamespace\{
    SubnamespaceOne\AnotherNamespace\ClassA,
    SubnamespaceOne\ClassB,
    ClassZ,
};

– PSR Documentation

use PHPLab\StandardPSR12\{
    HtmlDoc,
    HtmlDocAuthor,
    Language\EngGBLangTrait
};
use PHPLab\{
    StandardPSR12\HtmlDoc,
    StandardPSR12\HtmlDocAuthor
};

use PHPLab\StandardPSR12\Language\EngGBLangTrait;
use PHPLab\{
    StandardPSR12\HtmlDoc,
    StandardPSR12\HtmlDocAuthor,
    StandardPSR12\Language\EngGBLangTrait
};

Keywords, types & predefined constants

✀ Keywords case

All PHP reserved keywords MUST be in lower case. πŸ”—

Any new keywords added to future PHP versions MUST be in lower case. πŸ”—

The PHP constants true, false, and null should be in lower case too.

✀ Types case

All PHP reserved types MUST be in lower case. πŸ”—

Any new types added to future PHP versions MUST be in lower case. πŸ”—

✀ Types short/log forms

Short form of type keywords MUST be used i.e. bool instead of boolean, int instead of integer etc. πŸ”—

User.php

class User
{
    public bool $registered = true;
    public int $level = 10;
}

Operators

✀ Multiple spaces around an operator

When space is permitted around an operator, multiple spaces MAY be used for readability purposes. πŸ”—

$this->email = 'author@'
    . self::EMAIL_DOMAIN;

Unary operators

✀ Space between the operator and operand in the increment & decrement operators

The increment/decrement operators MUST NOT have any space between the operator and operand. πŸ”—

$this->level++;
✀ Space within the parentheses in type casting operators

Type casting operators MUST NOT have any space within the parentheses. πŸ”—

$isWorking = (bool) $this->level;

Binary operators

✀ Spaces around the binary arithmetic, comparison, assignment, bitwise, logical, string, and type operators

All binary arithmetic, comparison, assignment, bitwise, logical, string, and type operators MUST be preceded and followed by at least one space. πŸ”—

$this->email = 'author@' . self::EMAIL_DOMAIN;

Ternary operators

✀ Spaces around the characters of the conditional operator

The conditional operator, also known simply as the ternary operator, MUST be preceded and followed by at least one space around both the ? and : characters. πŸ”—

$label = empty($this->nickname) ? $this->firstName : $this->nickname;
✀ Spaces around the characters of the conditional operator when the middle operand is omitted

When the middle operand of the conditional operator is omitted, the operator MUST follow the same style rules as other binary comparison operators. πŸ”—

$isActive = $this->isRegistered ?: (bool) $this->level;

Control structures

✀ Space after control structure keyword

There MUST be one space after the control structure keyword. πŸ”—

✀ Space after opening parethensis in control structure

There MUST NOT be a space after the opening parenthesis. πŸ”—

✀ Space before closing parethensis in control structure

There MUST NOT be a space before the closing parenthesis. πŸ”—

✀ Space between closing parethensis and opening brace

There MUST be one space between the closing parenthesis and the opening brace. πŸ”—

✀ Closing brace placement in control structure

The closing brace MUST be on the next line after the body. πŸ”—

✀ Control structure body indention

The structure body MUST be indented once. πŸ”—

✀ Control structure body placement

The body MUST be on the next line after the opening brace. πŸ”—

✀ Control structure body enclosed by braces to indicate control structure body regardless of the number of statements it contains

The body of each structure MUST be enclosed by braces. πŸ”—

This standardizes how the structures look and reduces the likelihood of introducing errors as new lines get added to the body. πŸ”—

if (! $this->isRegistered) {
    $status = self::STATUS_HALTING;
} elseif ($this->level > 10) {
    $status = self::STATUS_INVOLVED;
} else {
    $status = self::STATUS_CERTAIN;
}

Control structure if - elseif - else

An if structure looks like the following. Note the placement of parentheses, spaces, and braces; and that else and elseif are on the same line as the closing brace from the earlier body.

<?php

if ($expr1) {
    // if body
} elseif ($expr2) {
    // elseif body
} else {
    // else body;
}

– PSR Documentation

if (! $this->isRegistered) {
    $status = self::STATUS_HALTING;
} elseif ($this->level > 10) {
    $status = self::STATUS_INVOLVED;
} else {
    $status = self::STATUS_CERTAIN;
}
✀ Keywords else if or keyword elseif

The keyword elseif SHOULD be used instead of else if so that all control keywords look like single words. πŸ”—

if (! $this->isRegistered) {
    $status = self::STATUS_HALTING;
} else if ($this->level > 10) {
    $status = self::STATUS_INVOLVED;
} else {
    $status = self::STATUS_CERTAIN;
}
if (! $this->isRegistered) {
    $status = self::STATUS_HALTING;
} elseif ($this->level > 10) {
    $status = self::STATUS_INVOLVED;
} else {
    $status = self::STATUS_CERTAIN;
}
✀ Splitting expression in parentheses across multiple lines

Expressions in parentheses MAY be split across multiple lines, where each subsequent line is indented at least once. πŸ”—

✀ First condition placement when expression is split across multiple lines

When doing so, the first condition MUST be on the next line. πŸ”—

✀ Closing parenthesis and opening brace placement when expression is split across multiple lines

The closing parenthesis and opening brace MUST be placed together on their own line with one space between them. πŸ”—

✀ Boolean operators between conditions placement when expression is split across multiple lines

Boolean operators between conditions MUST always be at the beginning or at the end of the line, not a mix of both. πŸ”—

<?php

if (
    $expr1
    && $expr2
) {
    // if body
} elseif (
    $expr3
    && $expr4
) {
    // elseif body
}

– PSR Documentation

if (
    $this->isRegistered
    && $this->level > 10
) {
    $status = self::STATUS_INVOLVED;
}

Control structure switch - case

switch ($status) {
    case self::STATUS_HALTING:
        $description = "Started to use the application.";
        break;
    case self::STATUS_CERTAIN:
        $description = "Using the application.";
        break;
    case self::STATUS_INVOLVED:
        $description = "Engeged in using the application";
        break;
    default:
        $description = "";
        break;
}
✀ Statement case indention

A switch structure looks like the following. Note the placement of parentheses, spaces, and braces.

<?php

switch ($expr) {
    case 0:
        echo 'First case, with a break';
        break;
    case 1:
        echo 'Second case, which falls through';
        // no break
    case 2:
    case 3:
    case 4:
        echo 'Third case, return instead of break';
        return;
    default:
        echo 'Default case';
        break;
}

– PSR Documentation

The case statement MUST be indented once from switch. πŸ”—

✀ Keyword break indention

The break keyword (or other terminating keywords) MUST be indented at the same level as the case body. πŸ”—

✀ Comment when fall-through is intentional in a non-empty case body
switch ($status) {
    case self::STATUS_HALTING:
        $description = "Started to use the application.";
        break;
}

There MUST be a comment such as // no break when fall-through is intentional in a non-empty case body. πŸ”—

switch ($status) {
    case self::STATUS_HALTING:
        // the same as following;
    case self::STATUS_CERTAIN:
        $description = "Using the application.";
        break;
}
✀ Splitting expression in parentheses across multiple lines

Expressions in parentheses MAY be split across multiple lines, where each subsequent line is indented at least once. πŸ”—

✀ First condition placement when expression is split across multiple lines

When doing so, the first condition MUST be on the next line. πŸ”—

✀ Closing parenthesis and opening brace placement when expression is split across multiple lines

The closing parenthesis and opening brace MUST be placed together on their own line with one space between them. πŸ”—

✀ Boolean operators between conditions placement when expression is split across multiple lines

Boolean operators between conditions MUST always be at the beginning or at the end of the line, not a mix of both. πŸ”—

<?php

switch (
    $expr1
    && $expr2
) {
    // structure body
}

– PSR Documentation

switch (
    (bool) $status
    && $this->isRegistered
) {
}

Control structure while, do - while

A while statement looks like the following. Note the placement of parentheses, spaces, and braces.

<?php

while ($expr) {
    // structure body
}

– PSR Documentation

Control structure while

while ($quantity > 0) {
    $visualisation .= '*';

    $quantity--;
}
✀ Splitting expression in parentheses across multiple lines

Expressions in parentheses MAY be split across multiple lines, where each subsequent line is indented at least once. πŸ”—

✀ First condition placement when expression is split across multiple lines

When doing so, the first condition MUST be on the next line. πŸ”—

✀ Closing parenthesis and opening brace placement when expression is split across multiple lines

The closing parenthesis and opening brace MUST be placed together on their own line with one space between them. πŸ”—

✀ Boolean operators between conditions placement when expression is split across multiple lines

Boolean operators between conditions MUST always be at the beginning or at the end of the line, not a mix of both. πŸ”—

<?php

while (
    $expr1
    && $expr2
) {
    // structure body
}

– PSR Documentation

while (
    $quantity > 0
    && $this->isRegistered
) {
}

Control structure do - while

do {
    $visualisation .= '#';

    $upgrade--;
} while ($upgrade > 0);

✀ Splitting expression in parentheses across multiple lines

Expressions in parentheses MAY be split across multiple lines, where each subsequent line is indented at least once. πŸ”—

✀ First condition placement when expression is split across multiple lines

When doing so, the first expression MUST be on the next line. πŸ”—

✀ Closing parenthesis and opening brace placement when expression is split across multiple lines

The closing parenthesis and opening brace MUST be placed together on their own line with one space between them. πŸ”—

<?php

do {
    // structure body;
} while ($expr);

– PSR Documentation

do {
} while (
    $upgrade > 0
    && $this->isRegistered
);

Control structure for

A for statement looks like the following. Note the placement of parentheses, spaces, and braces.

<?php

for ($i = 0; $i < 10; $i++) {
    // for body
}

– PSR Documentation

for ($i = 1; $i <= $skillsCount; $i++) {
    $visualisation .= $i . '. ' . $skills[$i - 1] . ', ';
}
✀ Splitting expression in parentheses across multiple lines

Expressions in parentheses MAY be split across multiple lines, where each subsequent line is indented at least once. πŸ”—

✀ First expression placement when expression is split across multiple lines

When doing so, the first expression MUST be on the next line. πŸ”—

✀ Closing parenthesis and opening brace placement when expression is split across multiple lines

The closing parenthesis and opening brace MUST be placed together on their own line with one space between them. πŸ”—

<?php

for (
    $i = 0;
    $i < 10;
    $i++
) {
    // for body
}

– PSR Documentation

for (
    $i = 1;
    $i <= $skillsCount;
    $i++) {
}

Control structure foreach

A foreach statement looks like the following. Note the placement of parentheses, spaces, and braces.

<?php

foreach ($iterable as $key => $value) {
    // foreach body
}

– PSR Documentation

foreach ($this->skills as $skillCodename => $skill) {
    $skillPresentation($skillCodename, $skill);
}

Closures & Functions

A function declaration looks like the following. Note the placement of parentheses, commas, spaces, and braces:

<?php

function fooBarBaz($arg1, &$arg2, $arg3 = [])
{
    // function body
}

– PSR Documentation

$skillPresentation = function ($skillCodename, $skill) use ($levelMarkChar, $newLineSeq) {
    print($skill['name'] . ': ' . $skill['level'] . $newLineSeq);
};
✀ Space after function keyword in closure definition

Closures MUST be declared with a space after the function keyword. πŸ”—

✀ Space after function name in function definition

Function names MUST NOT be declared with space after the method name. πŸ”—

function separate()
{
    print('<br>');
}

Argument list

<?php

namespace Vendor\Package;

class ClassName
{
    public function foo(int $arg1, &$arg2, $arg3 = [])
    {
        // method body
    }
}

– PSR Documentation

The following are examples of closures with and without argument lists and variable lists split across multiple lines.

<?php

$longArgs_noVars = function (
    $longArgument,
    $longerArgument,
    $muchLongerArgument
) {
   // body
};

$noArgs_longVars = function () use (
    $longVar1,
    $longerVar2,
    $muchLongerVar3
) {
   // body
};

$longArgs_longVars = function (
    $longArgument,
    $longerArgument,
    $muchLongerArgument
) use (
    $longVar1,
    $longerVar2,
    $muchLongerVar3
) {
   // body
};

$longArgs_shortVars = function (
    $longArgument,
    $longerArgument,
    $muchLongerArgument
) use ($var1) {
   // body
};

$shortArgs_longVars = function ($arg) use (
    $longVar1,
    $longerVar2,
    $muchLongerVar3
) {
   // body
};

Note that the formatting rules also apply when the closure is used directly in a function or method call as an argument.

<?php

$foo->bar(
    $arg1,
    function ($arg2) use ($var1) {
        // body
    },
    $arg3
);

– PSR Documentation

✀ Space after opening parethensis of argument list in closure definition/call

There MUST NOT be a space after the opening parenthesis of the argument list. πŸ”—

✀ Space before closing parethensis of argument list in closure definition/call

There MUST NOT be a space before the closing parenthesis of the argument. πŸ”—

✀ Space before coma on argument list in closure definition/call

In the argument list, there MUST NOT be a space before each comma. πŸ”—

✀ Space after coma on argument list in closure definition/call

In the argument list, there MUST be one space after each comma. πŸ”—

<?php

bar();
$foo->bar($arg1);
Foo::bar($arg2, $arg3);

– PSR Documentation

function ($skillCodename, $skill)

✀ Closure arguments with default values placement in closure definition/call

Closure arguments with default values MUST go at the end of the argument list. πŸ”—

function ($skillCodename = 'programming', $skill = ['name' => 'Programming', 'level' => 3])

✀ List of function/closure arguments split acros multi lines in closure definition/call

Argument lists MAY be split across multiple lines, where each subsequent line is indented once. πŸ”— πŸ”— πŸ”—

✀ Arguments placement on list of function/closure arguments split acros multi lines in closure definition/call

When doing so, the first item in the list MUST be on the next line. πŸ”— πŸ”— πŸ”—

<?php

$foo->bar(
    $longArgument,
    $longerArgument,
    $muchLongerArgument
);
<?php

somefunction($foo, $bar, [
  // ...
], $baz);

$app->get('/hello/{name}', function ($name) use ($app) {
    return 'Hello ' . $app->escape($name);
});

– PSR Documentation

✀ Number of arguments per line on list of function/closure arguments split acros multi lines in closure definition/call

There MUST be only one argument per line. πŸ”— πŸ”—

✀ Closing parenthesis and opening brace in closure with list of closure arguments split acros multi lines in closure definition/call

When the argument list is split across multiple lines, the closing parenthesis and opening brace MUST be placed together on their own line with one space between them. πŸ”—

<?php

namespace Vendor\Package;

class ClassName
{
    public function aVeryLongMethodName(
        ClassTypeHint $arg1,
        &$arg2,
        array $arg3 = []
    ) {
        // method body
    }
}

– PSR Documentation

function (
    $skillCodename,
    $skill
) {
}

Keyword use

✀ Space before use keyword in closure definition

Closures MUST be declared with a space before the use keyword. πŸ”—

✀ Space after use keyword in closure definition

Closures MUST be declared with a space after the use keyword. πŸ”—

✀ Keyword use in closure declaration

If the use keyword is present, the colon MUST follow the use list closing parentheses with no spaces between the two characters. πŸ”—

Variable list

The following are examples of closures with and without argument lists and variable lists split across multiple lines.

<?php

$longArgs_noVars = function (
    $longArgument,
    $longerArgument,
    $muchLongerArgument
) {
   // body
};

$noArgs_longVars = function () use (
    $longVar1,
    $longerVar2,
    $muchLongerVar3
) {
   // body
};

$longArgs_longVars = function (
    $longArgument,
    $longerArgument,
    $muchLongerArgument
) use (
    $longVar1,
    $longerVar2,
    $muchLongerVar3
) {
   // body
};

$longArgs_shortVars = function (
    $longArgument,
    $longerArgument,
    $muchLongerArgument
) use ($var1) {
   // body
};

$shortArgs_longVars = function ($arg) use (
    $longVar1,
    $longerVar2,
    $muchLongerVar3
) {
   // body
};

Note that the formatting rules also apply when the closure is used directly in a function or method call as an argument.

<?php

$foo->bar(
    $arg1,
    function ($arg2) use ($var1) {
        // body
    },
    $arg3
);

– PSR Documentation

✀ Space after opening parethensis of variable list in closure definition/call

There MUST NOT be a space after the opening parenthesis of the variable list. πŸ”—

✀ Space before closing parethensis of variable list in closure definition/call

There MUST NOT be a space before the closing parenthesis of the variable list. πŸ”—

✀ Space before coma on variable list in closure definition/call

In the variable list, there MUST NOT be a space before each comma. πŸ”—

✀ Space after coma on variable list in closure definition/call

In the variable list, there MUST be one space after each comma. πŸ”—

function ($skillCodename, $skill) use ($levelMarkChar, $newLineSeq)

✀ List of closure variables split acros multi lines in closure definition/call

Variable lists MAY be split across multiple lines, where each subsequent line is indented once. πŸ”—

✀ Variables placement in list of closure variables split acros multi lines in closure definition/call

When doing so, the first item in the list MUST be on the next line. πŸ”—

✀ Number of variables per line on list of closure variables split acros multi lines in closure definition/call

There MUST be only one variable per line. πŸ”—

✀ Closing parenthesis and opening brace in closure with list of closure variables split acros multi lines in closure definition/call

When the ending list of variables is split across multiple lines, the closing parenthesis and opening brace MUST be placed together on their own line with one space between them. πŸ”—

function ($skillCodename, $skill) use (
    $levelMarkChar,
    $newLineSeq
) {
}
✀ Space between method name and opening parenthesis in function call

When making a function call, there MUST NOT be a space between the method or function name and the opening parenthesis. πŸ”—

$skillPresentation($skillCodename, $skill);

Braces

✀ Opening brace placement in closure definition/call

The opening brace MUST go on the same line. πŸ”—

✀ Closing brace placement in closure definition/call

Closing brace MUST go on the next line following the body. πŸ”—

function ($skillCodename, $skill) use (
    $levelMarkChar,
    $newLineSeq
) {
}

Keyword return

✀ Return type declaration in closure definition

If a return type is present, it MUST follow the same rules as with normal functions and methods. πŸ”—

function ($skillCodename, $skill) use ($levelMarkChar, $newLineSeq): void

Classes

Extending classes

✀ Keyword extends placement in class definition

The extends keyword MUST be declared on the same line as the class name. πŸ”—

<?php

namespace Vendor\Package;

use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

class ClassName extends ParentClass implements \ArrayAccess, \Countable
{
    // constants, properties, methods
}

– PSR Documentation

class User extends Technician
{
}
✀ List of extends split acros multi lines in class definition

Lists of extends (in the case of interfaces) MAY be split across multiple lines, where each subsequent line is indented once. πŸ”—

When doing so, the first item in the list MUST be on the next line, and there MUST be only one interface per line. πŸ”—

<?php

namespace Vendor\Package;

use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

class ClassName extends ParentClass implements
    \ArrayAccess,
    \Countable,
    \Serializable
{
    // constants, properties, methods
}

– PSR Documentation

interface Evidentiable extends
    Presentable,
    Identifiable
{
}

Implementing interfaces

<?php

namespace Vendor\Package;

use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

class ClassName extends ParentClass implements \ArrayAccess, \Countable
{
    // constants, properties, methods
}

– PSR Documentation

✀ Keyword implements placement in class definition

The implements keyword MUST be declared on the same line as the class name. πŸ”—

<?php

namespace Vendor\Package;

use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

class ClassName extends ParentClass implements \ArrayAccess, \Countable
{
    // constants, properties, methods
}

– PSR Documentation

class Person implements Presentable
{
}
✀ List of implements split acros multi lines in class definition

Lists of implements MAY be split across multiple lines, where each subsequent line is indented once. πŸ”—

When doing so, the first item in the list MUST be on the next line, and there MUST be only one interface per line. πŸ”—

<?php

namespace Vendor\Package;

use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

class ClassName extends ParentClass implements
    \ArrayAccess,
    \Countable,
    \Serializable
{
    // constants, properties, methods
}

– PSR Documentation

class Person implements
    Presentable,
    Identifiable
{
}
✀ Opening brace placement in class definition

The opening brace for the class MUST go on its own line. πŸ”—

Opening braces MUST be on their own line and MUST NOT be preceded or followed by a blank line. πŸ”—

✀ Closing brace placement in class definition

The closing brace for the class MUST go on the next line after the body. πŸ”—

Closing braces MUST be on their own line and MUST NOT be preceded by a blank line. πŸ”—

Any closing brace MUST NOT be followed by any comment or statement on the same line. πŸ”—

class Person
{
}

Using traits

✀ Keyword use placement in class definition

The use keyword used inside the classes to implement traits MUST be declared on the next line after the opening brace. πŸ”—

<?php

namespace Vendor\Package;

use Vendor\Package\FirstTrait;

class ClassName
{
    use FirstTrait;
}

– PSR Documentation

class Technician
{
    use Skilled;
}
✀ Number of trait including per line in class definition

Each individual trait that is imported into a class MUST be included one-per-line and each inclusion MUST have its own use import statement. πŸ”—

<?php

namespace Vendor\Package;

use Vendor\Package\FirstTrait;
use Vendor\Package\SecondTrait;
use Vendor\Package\ThirdTrait;

class ClassName
{
    use FirstTrait;
    use SecondTrait;
    use ThirdTrait;
}

– PSR Documentation

class Technician extends Person
{
    use Educated;
    use Skilled;
}
✀ Closing brace after the use import placement in class definition

When the class has nothing after the use import statement, the class closing brace MUST be on the next line after the use import statement. πŸ”—

<?php

namespace Vendor\Package;

use Vendor\Package\FirstTrait;

class ClassName
{
    use FirstTrait;
}

– PSR Documentation

✀ Blank line after the use import placement in class definition

Otherwise, it MUST have a blank line after the use import statement. πŸ”—

<?php

namespace Vendor\Package;

use Vendor\Package\FirstTrait;

class ClassName
{
    use FirstTrait;

    private $property;
}

– PSR Documentation

class Technician extends Person
{
    use Educated;
    use Skilled;

    public function isVirtual(): bool
    {
        $isVirtual = ! empty($this->educations) && ! empty($this->skills);

        return $isVirtual;
    }
}
✀ Keywords insteadof and as

When using the insteadof and as operators they must be in separated lines with indentations. πŸ”—

<?php

class Talker
{
    use A;
    use B {
        A::smallTalk insteadof B;
    }
    use C {
        B::bigTalk insteadof C;
        C::mediumTalk as FooBar;
    }
}

– PSR Documentation

class Technician extends Person
{
    use Educated {
        Educated::isVirtual insteadof Skilled;
    }

    use Skilled {
        Skilled::isVirtual as isSkilled;
    }
}

Keywords abstract, final & static

<?php

namespace Vendor\Package;

abstract class ClassName
{
    protected static $foo;

    abstract protected function zim();

    final public static function bar()
    {
        // method body
    }
}

– PSR Documentation

✀ Keyword abstract placement

When present, the abstract declarations MUST precede the visibility declaration. πŸ”—

abstract protected function hasMiddleName(): bool;

✀ Keyword final placement

When present, the final declarations MUST precede the visibility declaration. πŸ”—

final public function isVirtual(): bool

✀ Keyword static placement

When present, the static declaration MUST come after the visibility declaration. πŸ”—

public static function getCount(): int

Class constants

✀ Class constant visiblity declaration

Visibility MUST be declared on all constants if your project PHP minimum version supports constant visibilities (PHP 7.1 or later). πŸ”—

public const STATUS_HALTING = 'halting';
public const STATUS_CERTAIN = 'certain';
public const STATUS_INVOLVED = 'involved';

Class properties

✀ Property visiblity declaration

A property declaration looks like the following:

<?php

namespace Vendor\Package;

class ClassName
{
    public $foo = null;
    public static int $bar = 0;
}

– PSR Documentation

Visibility MUST be declared on all properties. πŸ”—

private static $count;
protected $isRegistered = false;
public $level = 0;
✀ Single underscore prefix in property names for indication of non-public visibility

Property names MUST NOT be prefixed with a single underscore to indicate protected or private visibility. πŸ”—

That is, an underscore prefix explicitly has no meaning. πŸ”—

private static $_count = 0;
protected $_isRegistered = false;
public $level = 0;
private static $count = 0;
protected $isRegistered = false;
public $level = 0;
✀ Keyword var (used to declare property)

The var keyword MUST NOT be used to declare a property. πŸ”—

var static $count = 0;
var $isRegistered = false;
var $level = 0;
private static $count;
protected $isRegistered = false;
public $level = 0;
✀ Property type declaration

There MUST be a space between type declaration and property name. πŸ”—

private static int $count = 0;
protected bool $isRegistered = false;
public int $level = 0;
✀ Property declarations per statement

There MUST NOT be more than one property declared per statement. πŸ”—

public int $level = 0, $score = 5;
public int $level = 0;
public int $score = 5;

Class methods

A method declaration looks like the following. Note the placement of parentheses, commas, spaces, and braces:

<?php

namespace Vendor\Package;

class ClassName
{
    public function fooBarBaz($arg1, &$arg2, $arg3 = [])
    {
        // method body
    }
}

– PSR Documentation

✀ Single underscore prefix in method names for indication of non-public visibility

Method names MUST NOT be prefixed with a single underscore to indicate protected or private visibility. πŸ”—

That is, an underscore prefix explicitly has no meaning. πŸ”—

protected function _hasMiddleName()
{
    return false;
}
protected function hasMiddleName()
{
    return false;
}
✀ Method visiblity declaration

Visibility MUST be declared on all methods. πŸ”—

abstract protected function hasMiddleName();

public function getName()
{
    $name = $firstName
        . $this->hasMiddleName() ? $this->middleName : ' '
        . $lastName;

    return $name;
}

public function getPesel()
{
    return $this->pesel;
}
✀ Space after method name in method definition

Method names MUST NOT be declared with space after the method name. πŸ”—

public function getPesel()

✀ Space after opening parethensis of argument list in method definition/call

There MUST NOT be a space after the opening parenthesis. πŸ”—

✀ Space before closing parethensis of argument list in method definition/call

There MUST NOT be a space before the closing parenthesis. πŸ”—

✀ Space before coma on argument list in method definition/call

In the argument list, there MUST NOT be a space before each comma. πŸ”—

✀ Space after coma on argument list in method definition/call

In the argument list, there MUST be one space after each comma. πŸ”—

<?php

bar();
$foo->bar($arg1);
Foo::bar($arg2, $arg3);

– PSR Documentation

public function setName($firstName, $middleName, $lastName)

✀ List of method arguments with reference operator

When using the reference operator & before an argument, there MUST NOT be a space after it. πŸ”—

public function setAuthor(HTMLDocAuthor &$htmlDocAuthor)

✀ List of method arguments with variadic three dot operator

There MUST NOT be a space between the variadic three dot operator and the argument name. πŸ”—

public function process(string $algorithm, ...$parts)
{
    // processing
}

– PSR Documentation

public function addEducations(...$educations)

✀ List of method arguments with reference and variadic three dot operators

When combining both the reference operator and the variadic three dot operator, there MUST NOT be any space between the two of them. πŸ”—

public function process(string $algorithm, &...$parts)
{
    // processing
}

– PSR Documentation

✀ Method arguments with default values placement

Method and function arguments with default values MUST go at the end of the argument list. πŸ”—

<?php

namespace Vendor\Package;

class ClassName
{
    public function foo(int $arg1, &$arg2, $arg3 = [])
    {
        // method body
    }
}

– PSR Documentation

public function setName($firstName, $lastName, $middleName = '')

✀ List of method arguments split acros multi lines in method definition/call

Argument lists MAY be split across multiple lines, where each subsequent line is indented once. πŸ”—

✀ Arguments placement on list of method arguments split acros multi lines in method definition/call

When doing so, the first item in the list MUST be on the next line, and there MUST be only one argument per line. πŸ”—

✀ Number of arguments per line on list of method arguments split acros multi lines in method definition/call

There MUST be only one argument per line. πŸ”—

✀ Closing parenthesis and opening brace in method with list of method arguments split acros multi lines in method definition

When the argument list is split across multiple lines, the closing parenthesis and opening brace MUST be placed together on their own line with one space between them. πŸ”—

<?php

namespace Vendor\Package;

class ClassName
{
    public function aVeryLongMethodName(
        ClassTypeHint $arg1,
        &$arg2,
        array $arg3 = []
    ) {
        // method body
    }
}

– PSR Documentation

public function setName(
    $firstName,
    $lastName,
    $middleName = '') {
}
✀ Single argument being split across multiple lines in method call

A single argument being split across multiple lines (as might be the case with an anonymous function or array) does not constitute splitting the argument list itself. πŸ”—

<?php

$foo->bar(
    $longArgument,
    $longerArgument,
    $muchLongerArgument
);
<?php

somefunction($foo, $bar, [
  // ...
], $baz);

$app->get('/hello/{name}', function ($name) use ($app) {
    return 'Hello ' . $app->escape($name);
});

– PSR Documentation

<?php

$foo->bar(
    $longArgument,
    $longerArgument,
    $muchLongerArgument
);
<?php

somefunction($foo, $bar, [
  // ...
], $baz);

$app->get('/hello/{name}', function ($name) use ($app) {
    return 'Hello ' . $app->escape($name);
});

– PSR Documentation

✀ Return type declaration in method definition

When you have a return type declaration present, there MUST be one space after the colon followed by the type declaration. The colon and declaration MUST be on the same line as the argument list closing parenthesis with no spaces between the two characters. πŸ”—

<?php

declare(strict_types=1);

namespace Vendor\Package;

class ReturnTypeVariations
{
    public function functionName(int $arg1, $arg2): string
    {
        return 'foo';
    }

    public function anotherFunction(
        string $foo,
        string $bar,
        int $baz
    ): string {
        return 'foo';
    }
}

– PSR Documentation

public function getName(): string

✀ Return type declaration with nullable type in method definition

In nullable type declarations, there MUST NOT be a space between the question mark and the type. πŸ”—

<?php

declare(strict_types=1);

namespace Vendor\Package;

class ReturnTypeVariations
{
    public function functionName(?string $arg1, ?int &$arg2): ?string
    {
        return 'foo';
    }
}

– PSR Documentation

public function getPesel(): ?int

✀ Opening brace placement in method definition

The opening brace MUST go on its own line. πŸ”—

✀ Closing brace placement in method definition

The closing brace MUST go on the next line following the body. πŸ”—

✀ Comments or statements following closing brace in method definition

Any closing brace MUST NOT be followed by any comment or statement on the same line. πŸ”—

public function getName(): string
{
}
✀ Space between method name and opening parenthesis in method call

When making a method call, there MUST NOT be a space between the method or function name and the opening parenthesis. πŸ”—

$htmlDoc->setAuthor($htmlDocAuthor);

Class instantiating

✀ Parentheses in class instantiating

When instantiating a new class, parentheses MUST always be present even when there are no arguments passed to the constructor. πŸ”—

new Foo();

– PSR Documentation

$user = new User();

Anonymous classes

Anonymous Classes MUST follow the same guidelines and principles as closures in the above section.

<?php

$instance = new class {};

– PSR Documentation

✀ Opening brace, class keyword and list of implements placement

The opening brace MAY be on the same line as the class keyword so long as the list of implements interfaces does not wrap. If the list of interfaces wraps, the brace MUST be placed on the line immediately following the last interface. πŸ”—

<?php

// Brace on the same line
$instance = new class extends \Foo implements \HandleableInterface {
    // Class content
};

// Brace on the next line
$instance = new class extends \Foo implements
    \ArrayAccess,
    \Countable,
    \Serializable
{
    // Class content
};

– PSR Documentation

$human = new class {};
$human = new class implements
    Identifiable,
    Presentable
{
};