PHP Development Standards

PSR-[0-4]

  • PSR stands for Proposing a Standards Recommendation.
  • PSR-0 (Autoloading Standard)
  • PSR-1 (Basic Coding Standard)
  • PSR-2 (Coding Style Guide)
  • PSR-3 (Logger Interface)
  • PSR-4 (Improved Autoloading, can replace PSR-0)

PSR-1

  1. PHP source files must use only the <?php and <?= tags.
  2. Source code encoding must be UTF-8 without BOM.
  3. A source file should either declare symbols (classes, functions, constants) or perform side effects (e.g., output, config changes), but not both.
  4. Namespaces and classes must follow the PSR-0 standard.
  5. Class names must be written in StudlyCaps.
  6. Class constants must use only uppercase letters and underscores.
  7. Method names must be written in camelCase.

PSR-2

  • Files must end with a single blank line.
  • Line endings must be Unix LF.
  • The closing tag ?> must be omitted in pure PHP files.
  • Indentation must be 4 spaces.
  • Line length should be kept at most 80 characters.
  • PHP keywords, including true, false, and null, must be lowercase.
  • Namespaces
    • One blank line after the namespace declaration.
    • All use declarations must be placed after the namespace declaration.
    • Only one use keyword per statement.
    • One blank line after the use block.
<?php
namespace App\Models;

use Psr\Log\LoggerInterface;
use App\Exceptions\DatabaseException as DBException;
use App\Services\ConfigService;

class User
{
}

  • extends and implements must be on the same line as the class name, and the opening brace must be on a new line.
<?php
namespace App\Models;

class User extends BaseModel implements \ArrayAccess, \JsonSerializable
{
}

  • Properties must declare their visibility (public, protected, or private).
  • Methods must declare their visibility. The opening brace must be on a new line. Parameters: first parameter after a space, comma and space between parameters, functon name and opening parenthesis must have a space. Default values should be spaced.
<?php
namespace App\Models;

class User extends BaseModel implements \ArrayAccess, \JsonSerializable
{
    public function fetchDetails(string $username, int $age, string $gender = 'unknown')
    {
        // method body
    }
}

  • When using abstract or final, they must be placed before the visibility declaration. static must be placed after visibility.
<?php
namespace App\Core;

abstract class AbstractFactory
{
    protected static $instances = [];

    abstract protected function createInstance(string $type);

    final public static function getInstance(string $type): self
    {
        // method body
    }
}

  • Function calls
    • No spaces before or after parentheses.
    • No space before a comma, one space after.
    • For multi-line arguments, each argument on its own line.
<?php
bar();
$foo->bar($arg1);
Foo::bar($arg2, $arg3);

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

  • Control structures
<?php
if ($condition) {
    // if body
} elseif ($otherCondition) {
    // elseif body
} else {
    // else body
}

switch ($statusCode) {
    case 200:
        echo 'OK';
        break;
    case 301:
    case 302:
        echo 'Redirect';
        // no break
    case 404:
        echo 'Not Found';
        return;
    default:
        echo 'Unknown';
        break;
}

while ($iterator->valid()) {
    // structure body
}

do {
    // execute at least once
} while ($running);

for ($index = 0; $index < $max; $index++) {
    // for body
}

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

try {
    // try body
} catch (InvalidArgumentException $exception) {
    // catch body
} catch (RuntimeException $exception) {
    // catch body
}

  • Closures
<?php
$add = function(int $a, int $b): int {
    return $a + $b;
};

$multiplyWithFactor = function(int $value) use ($factor): int {
    return $value * $factor;
};

// Multi-line examples
$processData = function (
    string $input,
    array $options,
    int $timeout = 30
) {
    // body
};

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

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

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

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

PSR-3

  • Logger Interface

PSR-4

  • Improved autoloading.
  • The term "class" refers to classes, interfaces, traits, and other similar structures.
  • A fully qualified class name has the following structure:
    \<Namespace>(\<SubNamespace>)*\<ClassName>
  • A fully qualified class name must have a top-level namespace ("vendor namespace").
  • It may have one or more sub‑namespaces.
  • It must have a final class name.
  • Underscores in any part have no special meaning.
  • Letters can be any combination of upper‑ and lower‑case.
  • All class names are case‑sensitive.
  • The contiguous sequence of namespace and sub‑namespaces before the class name (minus the leading separator) is the "namespace prefix", which must correspond to at least one "base directory".
  • The sub‑namespaces after the prefix must match the base directory structure, using the namepsace separator as directory separator.
  • The final class name must match the file name, with a .php extension.
  • Autoloader implementations must not throw exceptions, must not trigger errors of any level, and should have no return value.

Tags: PHP PSR PSR-1 PSR-2 PSR-3

Posted on Sun, 16 Aug 2026 16:01:03 +0000 by vboyz