Skip to content

thomascombe/opinionated-php-laravel-guidelines

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

22 Commits
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Opinionated PHP and Laravel guidelines

This project is an opinionated guidelines for PHP and Laravel.

You can find PHP guideline and more specific Laravel guidelines.
These guidelines contain my PHP best practices and also my Laravel best practices.

PHP Version >= 7.4

Table of Contents

Created by gh-md-toc

PHP Guidelines

Use PSR-1 and PSR-2 for code style.

Class organization

namespace My\Class\Namespace;

use ClassInterface;

class MyClass extends ParentClass implements ClassInterface, Serializable
{
    public const PUBLIC_CONSTANTS = 'publicConstants';
    protected const PROTECTED_CONSTANTS = 'protectedConstants';
    private const PRIVATE_CONSTANTS = 'privateConstants';
    
    use SomeTrait;
    use AnotherTrait;
    
    public $publicProperties;
    protected $protectedProperties;
    private $privateProperties;
    
    public function __constructor() {}
    public function __destruct() {}
    
    public function publicMethods() {}
    protected function protectedMethods() {}
    private function privateMethods() {}
}

Methods/classes length

Classes and methods SHOULD be as small as possible.
Methods MUST have only one responsibility, 20 lines is probably a good soft limit.

Example for single responsibility:

// User.php class

// Good βœ…
public function getSummaryDescription(): string 
{
    return sprintf(
        '%s, %d years old, %s',
        $this->getFullName(),
        $this->getAge(),
        $this->getFullAddress()
    );
}

public function getFullName(): string 
{
    //return ...;
}

public function getAge(): int 
{
    //return ...;
}

public function getFullAddress(): string 
{
    //return ...;
}

// Bad ❌
public function getSummaryDescription(): string 
{
    return sprintf(
        '%s %s %s, %d years old, %s %s %s',
        $this->civility,
        ucfirst($this->firstName),
        strtoupper($this->lastName),
        intval($this->age),
        $this->address,
        $this->postalCode,
        $this->city,
    );
}

Variables naming

Variables name NEED to explain your code, code is auto-documented with naming. You HAVE TO avoid generic names.

// This code is just an illustration for variables naming.  
// do not judge the usefulness and effectiveness of this code πŸ™
// Good βœ…
public function getPrettyUsersList(array $users): string 
{
    $prettyUsersList = '';
    
    foreach ($users as $user) {
        $prettyUsersList .= ', ' . $user->getFullName();
    }
    
    return $prettyUsersList;
}

// Bad ❌
// getUsersList name is not description the method
public function getUsersList(array $users): string 
{
    // Variable name is not understandable
    $list = '';
    
    // $item is too generic
    foreach ($users as $item) {
        $list .= ', ' . $item->getFullName();
    }
    
    return $list;
}

Type hinting

You SHOULD use type hinting for parameters and return.

// Good βœ…
class MyClass 
{
    public function myMethod(string $param): void 
    {
        //
    }
}

// Bad ❌
class MyClass 
{
    public function myMethod($param) 
    {
        //
    }
}

Void return

Use void as return type whenever possible to avoid mistakes.

// Good βœ…
class MyClass 
{
    public function myMethod(): void 
    {
        //
    }
}

// Bad ❌
class MyClass 
{
    public function myMethod() 
    {
        //
    }
}

PHPDoc

PhpDoc stands for documentation purposes. Consider to use type hinting insteadof @param or @return

// Good βœ…
class MyClass 
{
    /**
     * Method description if method name can't be understandable
     */
    public function myMethod(string $param): void 
    {
        //
    }
}

// Bad ❌
class MyClass 
{
    /** 
     * @param string $param 
     * @return void 
     */
    public function myMethod(string $param): void 
    {
        //
    }
}

Traits use

If you use PHP traits (and you have to use it!), for better readability and more understandable diffs, each trait SHOULD be on its own line.

// Good βœ…
class MyClass 
{
    use FirstTrait;
    use SecondTrait;
    use SecondTrait {
        SecondTrait::traitMethod as duplicateTraitMethod;
    }
}

// Bad ❌
class MyClass 
{
    use FirstTrait, SecondTrait {
        SecondTrait::traitMethod as duplicateTraitMethod;
    }
}

If statement

You MUST use curly braces for if statements even if there is only one line of code inside.

// Good βœ…
if ($someCondition === true) {
    $this->work();
}

// Very bad ❌
if ($someCondition === true) {$this->work();}

String concatenation

For concatenate strings prefer In-string variables.
You can also use sprintf() for more complex use cases.

// Very good βœ…
$finalString = "My name is {$name}!";

// Good βœ…
$finalString = sprintf(
    'My name is %s!',
    $name
);

// Bad ❌
$finalString = 'My name is ' .$name . '!';

// If you want to update spring
$finalString = "My name is {$name}! I'm {$age} years old";

// Good βœ…
$finalString = sprintf(
    'My name is %s!I\'m %d years old',
    $name,
    $age
);
// Bad ❌
$finalString = 'My name is ' .$name . '! I\'m ' . $age . ' years old';

Function path, happy end

In function, you SHOULD put error check (return, exception) first, this last instruction must be a happy end!

// Good βœ…
private function good(): ?int 
{
    if (!$someCondition) {
        return null;
    }
    
    $this->work();
    
    if (!$anotherCondition) {
        return null;
    }
    
    
    return $this->secondWork();
}

// Bad ❌
private function bad(): ?int 
{
    if ($someCondition) {
        $this->work();
    
        if ($anotherCondition) {
            return $this->secondWork();
        }
    }
    
    return null;
}

This rule keep code readable and remove a lot of nested methods.

Switch

You SHOULD use lookup array as some as possible insteadof switch.
If using PHP8, you SHOULD prefer match

// Good βœ… (lookup array)
function getColorFor(string $role): string
{
    $colorsByRoles = [
        'admin' => 'red',
        'customer' => 'green',
        'guest' => 'grey',
    ];
    return $colorsByRoles[$role] ?? 'yellow';
}
// Good βœ… (match PHP8)
function getColorFor(string $role): string
{
    return match ($role) {
        'admin' => 'red',
        'customer' => 'green',
        'guest' => 'grey',
        default => 'yellow',
    };
}

// Bad ❌
function getColorFor(string $role): string
{
    switch ($role) {
        case 'admin':
            return 'red';
        case 'customer':
            return 'green';
        case 'guest':
            return 'grey';
        default:
            return 'yellow';
    }
}

// Very bad ❌
function getColorFor(string $role): string
{
    if ($role === 'admin') {
        return 'red';
    }
    if ($role === 'customer') {
        return 'green';
    }
    if ($role === 'guest') {
        return 'grey';
    }
    return 'yellow';
}

Laravel Guidelines

// WIP

License

MIT

About

Opinionated PHP and Laravel guideline

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published