Code quality
Code is read more often than it is written. When the whole project is formatted the same way and a program finds the obvious mistakes, it is easier to work with, alone or in a team. There is a shared coding standard for that, and tools that enforce it by themselves.
The PSR-12 standard
PSR-12 is the community's agreement on how to format PHP code. The main rules:
| Rule | Example |
|---|---|
| Indentation is 4 spaces | Not a tab |
Class names in PascalCase | OrderService |
Method and variable names in camelCase | getTotal(), $orderId |
| Constants in capital letters | MAX_ITEMS |
| The brace of a class or method on a new line | See below |
The brace of if, for, foreach on the same line | See below |
| One class — one file | src/OrderService.php |
<?php
declare(strict_types=1);
class OrderService
{
private const MAX_ITEMS = 10;
public function canAdd(int $count): bool
{
if ($count >= self::MAX_ITEMS) {
return false;
}
return true;
}
}
echo (new OrderService())->canAdd(3) ? 'allowed' : 'not allowed'; // allowedAutomatic formatting
There is no need to watch the formatting by hand — PHP-CS-Fixer does it:
composer require --dev friendsofphp/php-cs-fixer
vendor/bin/php-cs-fixer fix srcThe command fixes indentation, spaces and braces in every file of the src folder.
Static analysis
A static analyser reads code without running it and finds mistakes that would otherwise show up only for a visitor. The best known is PHPStan:
composer require --dev phpstan/phpstan
vendor/bin/phpstan analyse src --level=5There are ten levels — from the crudest mistakes to very strict checks. You start low and raise the level gradually.
What the analyser finds
<?php
function findUser(int $id): ?array
{
return $id === 1 ? ['name' => 'Anna'] : null;
}
$user = findUser(2);
echo $user['name'] ?? 'not found'; // not foundWithout the ?? operator the line echo $user['name'] would run with a warning as soon as a user is not found. PHPStan notices that in advance: the function may return null, and the code does not account for it. It likewise finds calls to non-existent methods, wrong argument types and unreachable code.
Hints for the analyser
The more precise the types, the more mistakes the analyser sees. What a PHP type cannot express is written in a comment:
<?php
/**
* @param array<int, string> $names
* @return array<string, int>
*/
function countLetters(array $names): array
{
$result = [];
foreach ($names as $name) {
$result[$name] = strlen($name);
}
return $result;
}
echo json_encode(countLetters(['Anna', 'Peter'])); // {"Anna":4,"Peter":5}Composer scripts
To avoid remembering long commands, they are written in composer.json:
{
"scripts": {
"format": "php-cs-fixer fix src",
"analyse": "phpstan analyse src --level=5",
"test": "phpunit",
"check": ["@format", "@analyse", "@test"]
}
}composer checkOne command formats the code, checks it and runs the tests. It is run before every push.
Common mistake
Turning the analyser on at a high level in an old project and getting thousands of remarks is a sure way to abandon it. Start at level 0 or 1, fix what was found, then raise the level. For a large old codebase PHPStan can record existing remarks in a baseline file and demand cleanliness only from new code.