Skip to content

PHP

Table of contents:

Fundamental

Follow PSR

Always follow PSR.

PSR-12 is the most notable for maintaining a quality and consistent coding style.

Quality Coding

Use strict comparison ===

php
if ($type === 'multiple') {
    return true;
}

The only exception is when you need type juggling with loose comparison ==. Even then, you should prefer casting values into appropriate types then using strict comparison. Loose comparison can have unpredictable result.

Wrap control structures

Always wrap the body of a control structure (if, else, while) with curly braces { } even if it has only one statement.

php
if ($status === 'completed') {
    $this->sendEmail();
}

Use Guard Clauses

Use Guard Clauses, which check for breaking conditions first then exit early. This allows for the rest of the code to flow like what normally happens and prevents nesting indentation.

Bad:

php
function divide(int $num, int $den)
{
    if ($den !== 0 && $num !== 0) {
        return $num / $den;    
    } else {
        if ($den === 0) {
            throw new DivisionByZeroError();
        } else {
            return 0;
        }
    }
}

Good:

php
function divide(int $num, int $den)
{
    if ($den === 0) {
        throw new DivisionByZeroError();
    }
    
    if ($num === 0) {
        return 0;
    }
    
    // Normal flow here
    return $num / $den;
}

A general rule of thumb is to eliminate all else clauses.

Use multiline ternary operations

Each expression in your ternary operation should be on its own line, unless the operation is very short.

Avoid nesting ternary operations.

Bad:

php
return $this->hasUser() ? Person::HAS_USER_TYPE : Person::NO_USER_TYPE;

Good:

php
return $this->hasUser()
    ? Person::HAS_USER_TYPE 
    : Person::NO_USER_TYPE;

Don't use abbreviations

Don't use abbreviations when they're not readily understood by everyone. One acceptable abbreviation is id.

Embrace complete names. They're expressive. It's better to write $order->user than to write $ord->u.

Use short operators

PHP has many great operators that can replace ugly if checks.

Bad:

php
if (! $type) {
    $type = 'book';
}

if (is_null($user)) {
    $user = User::find(1);
}

Good:

php
$type = $type ?: 'book';

$user = $user ?? User::find(1);
$user ??= User::find(1); // PHP 7.4+

Prefer nullable type to union type

php
public ?string $name; // Good
public string|null $name; // Bad

Specify void return type

If a function returns nothing, specify void.

php
public function scopePublished(Builder $query): void
{
    $query->
    ...
}

Type all properties instead of relying on docblock

Bad:

php
/** @var string */
public $name;

Good:

php
public string $name;
  • No fully qualified class name usage. Use import.
  • No leading slash in class usage.
  • Trailing commas on arrays.
  • Space after the Not Operator (!).
  • There should be no unused imports.

PHP_CodeSniffer is a very good package to help automate these checks for you. Refer to their documentation for usage: https://github.com/squizlabs/PHP_CodeSniffer.

Programming Techniques

Store times in UTC

Store all times in UTC in the database. Compare, manipulate, and operate times in UTC.

You can display times in a different timezone based on your application's configuration or user's preference.

Use lookup tables

Instead of writing repetitive if elseif or switch statements, use an array to look up the wanted value based on the key you have.

Bad:

php
if ($order->product->option->type === 'mp3') {
    $type = 'music';
} elseif ($order->product->option->type === 'pdf') {
    $type = 'book';
} elseif ($order->product->option->type === 'epub') {
    $type = 'book';
} else {
    $type = 'other';
}

Good:

php
$type = [
    'mp3' => 'music',
    'pdf' => 'book',
    'epub' => 'book',
][$order->product->option->type] ?? 'other';

Since PHP 8, you can use match to achieve the same result conveniently:

php
$type = match($order->product->option->type) {
    'mp3' => 'music',
    'pdf', 'epub' => 'book',
    default => 'other',
};

Design Patterns

Follow SOLID principles

SOLID is a matured methodology to develop applications. This article explains them very well in a PHP context.

Design fluent classes

A fluent class has methods that return to the object itself. Design it in a way so that upon usage you can chain its methods.

php
$paymentService = new PaymentService();

$paymentService->authenticate($token)
    ->setOrder($order)
    ->setAmount(100);

if ($subscription) {
    $paymentService->subscribe();
}

$paymentService->connect()
    ->charge();