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,
readonlyproperties and classes,matchand 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 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.lockpins exact versions. - Why
- No manual
requirelines, and every environment installs the same versions.
composer create-project laravel/laravel shop
composer require laravel/sanctum
composer install --no-dev --optimize-autoloader
composer auditWatch 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.
// 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
belongsToandhasManydefine 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.
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.
$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: 130Watch 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.
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.