PHP

Editor

PHP Code Syntax Fixer

Installeer de extension vscode-php-cs-fixer voor automatische code formatting voor al je PHP code.

Let op Pas hieronder de USERNAME aan naar jouw eigen username op je Mac.

"vscode-php-cs-fixer.allowRisky": false,
"vscode-php-cs-fixer.config": "",
"vscode-php-cs-fixer.fixOnSave": true,
"vscode-php-cs-fixer.rules": "@PSR1,@PSR2,@Symfony,-yoda_style",
"vscode-php-cs-fixer.toolPath": "",
"vscode-php-cs-fixer.useCache": false,
"vscode-php-cs-fixer.fixOnSave": true,
"vscode-php-cs-fixer.toolPath": "/Users/USERNAME/.composer/vendor/bin/php-cs-fixer",

PHP Namespace Resolver

Om eenvoudig een namespace te kunnen importeren en automatisch te sorteren op lengte volgens de Laravel standaard. Daarvoor gebruiken we de PHP Namespace Resolver.

Algemeen

Om ervoor te zorgen dat elke git commit hetzelfde is, trimmen we alle overbodige whitespace en zetten we altijd een nieuwe lege regel aan het einde van een bestand om onnodige git commits te voorkomen.

Pas deze instellingen aan binnen Visual Studio Code.

"files.insertFinalNewline": true,
"files.trimTrailingWhitespace": true,

Taalgebruik

Alle code, namen en bestanden schrijven we in het Engels. Zodat we geen awkward mix krijgen tussen Nederlands en Engels zoals deze documentatie.

Over het algemeen: probeer alles zo kort (en pittig) maar krachtig te houden.

Naamgeving

Classes

Type Naamgeving Case Voorbeeld
Commands Enkelvoud UpperCamelCase SendInvoiceByEmail
Controllers Enkelvoud + "Controller" UpperCamelCase InvoiceController
Events Enkelvoud UpperCamelCase InvoiceSent
Facades Enkelvoud UpperCamelCase Invoice
Factories Enkelvoud + “Factory” UpperCamelCase InvoiceFactory
Form Requests Enkelvoud + “Request” UpperCamelCase InvoiceRequest
Gate Enkelvoud kebab-case destroy-invoice
Mailables Enkelvoud + “Mail” UpperCamelCase InvoiceReminderMail
Migrations “create/add/drop/rename” + meervoud tabel naam + “table” snake_case CreateInvoicesTable (create_invoices_table)
Models Enkelvoud UpperCamelCase Invoice
Notifications Enkelvoud UpperCamelCase InvoicePaid
Policy Enkelvoud + "Policy" UpperCamelCase InvoicePolicy
Repositories Enkelvoud + “Repository” UpperCamelCase InvoiceRepository
Seeds Enkelvoud + “Seeder” UpperCamelCase InvoiceSeeder
Services Enkelvoud + “Service” UpperCamelCase InvoiceService
Tests Enkelvoud + "Test" UpperCamelCase InvoiceTest
Views Meervoud kebab-case invoices.show

Algemeen

Type Naamgeving Case Voorbeeld
Cache Enkelvoud snake_case invoice_pdf
Files Enkelvoud kebab-case invoice-2018-500.pdf
Helpers Enkelvoud snake_case invoice_number
Route names Meervoud lowercase invoices.show
Route parameters Enkelvoud camelCase invoice
Sessions Enkelvoud snake_case invoice_sent_at
Tables Meervoud snake_case invoices
Translations Engels Normale tekst This is an invoice.
Validation rules Enkelvoud snake_case invoice_is_pdf

Docblocks

Voor het eenvoudig opstellen van Docblocks, kun je deze extension gebruiken: PHP DocBlocker - Visual Studio Marketplace.

Definieer bij elke PHP functie altijd docblock, in deze vorm, waarbij we ook zoveel als mogelijk gebruik maken van typehints.

class Url
{
    /**
     * Create a url from a string.
     *
     * @param string $url
     *
     * @return \Vormkracht10\Url\Url
     */
    public static function fromString(string $url): Url
    {
        // ...
    }
}

Voor variabelen altijd een dockblock definiëren omdat typehints voor variabelen nog niet mogelijk zijn.

// Good

class Foo
{
    /** @var \Vormkracht10\Url\Url */
    protected $url;

    /** @var string */
    protected $name;
}

// Bad

class Foo
{
    protected $url;
    protected $name;
}

// Even better in PHP 7.3

class Foo
{
    protected Url $url;
    protected string $name;
}

Waar mogelijk schrijf je de docblock op één regel.

// Good

/** @var string */

// Bad

/**
 * @var string
 */

Wanneer er meerdere types mogelijk zijn, geef dan de definieer dan de meest voor de handliggende eerst.

// Good

/** @var \Vormkracht10\Foo\Bar|null */

// Bad

/** @var null|\Vormkracht10\Foo\Bar */

Ternary operators

Wanneer een ternary operator kort kan zijn, definieer deze dan kort. En anders gebruik je meerdere regels voor de leesbaarheid.

// Good
$result = $object instanceof Model
    ? $object->name
    : 'A default value';

$name = $isFoo ? 'foo' : 'bar';

// Bad
$result = $object instanceof Model ?
    $object->name :
   'A default value';

If statements

Gebruik altijd brackets {} voor leesbaarheid en nooit zonder.

// Good
if ($goodStatement) {
   ...
}

// Bad
if ($badStatement) ...

Comments

Comments vermijden we zoveel mogelijk door het schrijven van expressieve code. Wanneer je ze toch nodig hebt, schrijf ze dan als volgt:

// There should be space before a single line comment.

/*
 * If you need to explain a lot you can use a comment block. Notice the
 * single * on the first line. Comment blocks don't need to be three
 * lines long or three characters shorter than the previous line.
 */

Whitespace

Statements hebben ruimte nodig om de leesbaarheid optimaal te houden. Tenzij het enkelvoudige en opeenvolgende functies zijn.

// Good
public function getPage($url)
{
    $page = $this->pages()->where('slug', $url)->first();

    if (! $page) {
        return null;
    }

    if ($page['private'] && ! Auth::check()) {
        return null;
    }

    return $page;
}

// Bad: Everything's cramped together.
public function getPage($url)
{
    $page = $this->pages()->where('slug', $url)->first();
    if (! $page) {
        return null;
    }
    if ($page['private'] && ! Auth::check()) {
        return null;
    }
    return $page;
}
// Good: A sequence of single-line equivalent operations.
public function up()
{
    Schema::create('users', function (Blueprint $table) {
        $table->increments('id');
        $table->string('name');
        $table->string('email')->unique();
        $table->string('password');
        $table->rememberToken();
        $table->timestamps();
    });
}

Voeg geen extra lege regels tussen de {} brackets toe.

// Good
if ($foo) {
    $this->foo = $foo;
}

// Bad
if ($foo) {

    $this->foo = $foo;

}

Configuration

Configuratie bestanden moeten volgens de Laravel standaard met kebab-case worden geschreven.

  pdf-generator.php

Configuratie keys moeten volgens snake_case worden geschreven.

return [
    'chrome_path' => env('CHROME_PATH'),
];

Gebruik de env helper alleen binnen configuratie bestanden en niet ergens anders. Gebruik daar altijd een configuratie voor die wel een env helper kan bevatten.

Artisan commands

De namen van commando’s moeten altijd in kebab-case worden geschreven.

// Good
php artisan delete-old-records

// Bad
php artisan deleteOldRecords

Feedback

Geef altijd feedback terug na uitvoer van een commando. Laat iets van je horen!

// in a Command
public function handle()
{
    // do some work

    $this->comment('All records are deleted!');
}

Routing

Alle URLs binnen een app of website moeten in kebab-case worden geschreven.

https://vormkracht10.nl/klantcases/werkbedrijf-rijk-van-nijmegen https://vormkracht10.nl/vacature/backend-developer

Route names

Geef route names ook altijd op in dot notatie, waarbij we de RESTful controller methodes aanhouden en dus ook de namen daarin gelijk houden. Een controller is altijd enkelvoud en een route name is altijd meervoud net als de mappenstructuur van views.

Route::get('klantcases/werkbedrijf-rijk-van-nijmegen', 'CaseController@show')->name('cases.show');

Alle routes beginnen met een REST definitie (GET, POST, PUT, DELETE).

// good: all http verbs come first
Route::get('/', 'HomeController@index')->name('home');
Route::get('klantcases', 'CaseController@index')->middleware('awesome');

// bad: http verbs not easily scannable
Route::name('home')->get('/', 'HomeController@index');
Route::middleware('not-cool')->get('CaseController@index');

Route parameters

Route parameters moeten zo kort mogelijk zijn als een enkelvoudig woord, wanneer niet mogelijk gebruik dan camelCase.

Route::get('klantcases/{case}', 'CaseController@show');

Route paths

Een route begint zonder slash (/) tenzij het de home is en het een lege string zou worden.

// good
Route::get('/', 'HomeController@index');
Route::get('klantcases', 'CaseController@index');

// bad
Route::get('', 'HomeController@index');
Route::get('/klantcases', 'CaseController@index');

Controllers

Controllers noem je enkelvoudig, net als het model met daarachter “Controller” en in camelCase wanneer meerdere woorden nodig zijn.

// good
class CaseController
{
    // ...
}

// bad
class Cases
{
    // ...
}

Houdt de controller namen en methods eenvoudig, gebruik de standaard CRUD woorden wanneer mogelijk (index, create, store, show, edit, update, destroy of delete) en anders een korte duidelijke werkwoord.

Tevens met namespaces in enkelvoud zodat er een duidelijke visuele structuur in code en de mappen worden gebruikt.

// good

namespace App\Http\Controllers\Invoice;

class InvoiceController
{
    public function index()
    {
        // show all invoices
    }
}

namespace App\Http\Controllers\Invoice;

class SendController
{
    public function create()
    {
        // show the send invoice form
    }

    public function store()
    {
        // send the invoice please
    }
}
// bad
namespace App\Http\Controllers;

class InvoiceController
{
    public function index()
    {
        // show all invoices
    }

    public function form()
    {
        // show the send invoice form
    }

    public function send()
    {
        // send the invoice please
    }
}

Views

Views moeten in kebab-case worden genoemd en zo kort mogelijk. Dus een “over ons” pagina wordt “about us” en dus “about-us”.

resources/
  views/
    about-us.blade.php
class AboutUsController
{
    public function show() {
        return view('about-us');
    }
}

Validation

Alle zelf geschreven validatie regels moeten in snake_case.

Validator::extend('is_valid_xml', function ($attribute, $value) {
    return XML::isValid($value);
});

HTML & Blade Templates

Gebruik altijd 4 spaties en nooit tabs.

<a href="/klantcases">Klantcases</a>

Voeg geen spaties toe voor de blade directives.

// good
@if($condition)
    Something
@endif

// bad
@if ($condition)
    Something
@endif

Authorization

Policies moeten in kebab-case en gebruik de CRUD bewoording zoveel als mogelijk.

Gate::define('edit-case', function ($user, $case) {
    return $user->id == $case->user_id;
});
@can('edit-case', $case)
    <a href="{{ route('cases.edit', $case) }}">Edit</a>
@endcan

Translations

Vertalingen voer je door in Slim via de custom @__ tag.

@__('This is a translation')

Binnen de PHP code kun je de standaard underscore functie gebruiken.

echo __('This is a translation')