# PHP

# Fundamentals

# Follow PSR

Always follow PSR.

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

# Quality Coding

# Use strict comparison ===

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.

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:

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

Good:

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

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

# Use multi-line 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:

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

Good:

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

# Don't use abbreviations

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

Embrace long 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:

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

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

Good:

$type = $type ?: 'book';

$user = $user ?? User::find(1);
$user ??= User::find(1); // PHP 7.4 
  • 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:

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:

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

# Design Patterns

# Follow SOLID principles

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

# Design fluent classes

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

$paymentService = new PaymentService();

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

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

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