Backend development: PHP

Sefism.

Chapter 01

Modern PHP and Laravel essentials

How PHP serves requests, the modern language features worth using, and how Laravel wires services and models together.

The PHP request lifecycle

Also called PHP-FPM, OPcache, Octane, FrankenPHP

What
Classic PHP is share-nothing: PHP-FPM boots the app for each request and throws all state away at the end. OPcache keeps compiled code in memory. Laravel Octane (with FrankenPHP, Swoole or RoadRunner) keeps the app booted between requests.
Why
Share-nothing makes memory leaks and cross-request bugs rare and scaling simple. Octane cuts boot time but brings back long-running process concerns.
Example
Under PHP-FPM a static array used as a cache is empty on every request. Under Octane the same array survives and grows, and a singleton holding the current user can leak it to the next request.

Watch out

Storing request data in singletons or static properties after moving to Octane.

Modern PHP types, enums and readonly

Also called strict_types, enum, readonly, strict types

What
PHP 8 has typed properties, union types, backed enums, readonly properties and classes, match and constructor property promotion. declare(strict_types=1) stops silent type juggling.
Why
Types make bugs fail loudly and early, and enums replace magic strings for statuses and roles.
PHP
<?php declare(strict_types=1);

enum Status: string
{
  case Active = 'active';
  case Banned = 'banned';
}

final readonly class Money
{
  public function __construct(public int $cents) {}
}

Watch out

Relying on loose comparison ==, where "abc" == 0 was true before PHP 8; use ===.

Composer and autoloading

Also called Composer, PSR-4, composer.lock, autoloading

What
Composer installs packages from Packagist and generates a PSR-4 autoloader that maps namespaces to folders. composer.lock pins exact versions.
Why
No manual require lines, and every environment installs the same versions.
Shell
composer create-project laravel/laravel shop
composer require laravel/sanctum
composer install --no-dev --optimize-autoloader
composer audit

Watch out

Running composer update on a server instead of composer install, which ignores the lockfile.

Laravel service container

Also called IoC container, service provider, facades

What
Laravel builds your classes and resolves their constructor dependencies automatically. Service providers bind interfaces to implementations; facades are static-looking shortcuts to container services.
Why
Controllers ask for an interface, and you can swap the real gateway for a fake in tests with one binding.
PHP
// AppServiceProvider::register()
$this->app->singleton(PaymentGateway::class, fn () =>
  new StripeGateway(config('services.stripe.secret')));

class CheckoutController
{
  public function __construct(
    private PaymentGateway $payments,
  ) {}
}

Watch out

Calling env() outside config files: after php artisan config:cache it returns null.

Eloquent models and relationships

Also called Eloquent, ORM, Active Record

What
Eloquent is Laravel's Active Record ORM: each model maps to a table, and methods like belongsTo and hasMany define relationships you can query and eager load.
Why
Everyday CRUD, relationships, casts and scopes take a few lines, while you can still drop to the query builder or raw SQL.
PHP
class Post extends Model
{
  protected $fillable = ['title', 'body'];

  public function author(): BelongsTo
  {
    return $this->belongsTo(User::class, 'user_id');
  }
}

Watch out

Passing $request->all() to create on a model with $guarded = [], which lets users set any column (mass assignment).

PHP arrays and collections

Also called array, array_map, Laravel collection

What
A PHP array is both an ordered list and a key-value map. Functions such as array_map, array_filter and array_column transform arrays, and Laravel wraps them in fluent Collections.
Why
Request input, query results and config all arrive as arrays, so most everyday PHP is array handling.
PHP
$orders = [
    ['id' => 1, 'total' => 40],
    ['id' => 2, 'total' => 90],
];
$big = array_filter($orders, fn ($o) => $o['total'] > 50);
$ids = array_column($orders, 'id');        // [1, 2]
$byId = array_column($orders, null, 'id'); // keyed by id
$sum = collect($orders)->sum('total');     // Laravel: 130

Watch out

Forgetting that array_filter keeps the original keys, so the result may not start at 0; wrap it in array_values.

PHP errors and exceptions

Also called try catch, throw, exception handler

What
Modern PHP throws exceptions for most failures, handled with try, catch and finally. Custom exception classes describe domain errors, and Laravel's handler turns uncaught ones into HTTP responses.
Why
Clear exception types let one handler map "not found" to 404 and validation failures to 422, instead of scattering checks through controllers.
PHP
class OrderNotFound extends RuntimeException {}
function findOrder(array $orders, int $id): array
{
    return $orders[$id]
        ?? throw new OrderNotFound("Order $id");
}

try {
    findOrder([], 7);
} catch (OrderNotFound $e) {
    http_response_code(404);
}

Watch out

Catching Exception everywhere and logging nothing, which hides real bugs.

01 · Modern PHP and Laravel essentials1 / 10