Upgrading to Laravel 9: Modernizing Your PHP Workflow
Overview
Prerequisites
To follow along, you should have a solid grasp of
Key Libraries & Tools
- Flysystem v3: Powers the
Storagefacade with a rewritten, modern architecture. - Symfony Mailer: Replaces the deprecated Swift Mailer for all email operations.
- Guzzle: The underlying engine for Laravel's HTTP client.
Code Walkthrough
Simplified Route Groups
Laravel 9 introduces a more readable way to group routes that share a single controller. This eliminates the need to repeat the controller class name for every route definition.
use App\Http\Controllers\OrderController;
use Illuminate\Support\Facades\Route;
Route::controller(OrderController::class)->group(function () {
Route::get('/orders/{id}', 'show');
Route::post('/orders', 'store');
});
Previously, you had to pass an array or a string for every single route. The controller() method keeps your routes/web.php file incredibly dry.
Enum Route Binding
With
enum Status: string {
case Shipped = 'shipped';
case Delivered = 'delivered';
}
Route::get('/orders/status/{status}', function (Status $status) {
return $status->value;
});
Syntax Notes
- Anonymous Migrations: By default,
php artisan make:migrationnow usesreturn new class extends Migration. This prevents class name collisions when merging features from different branches. - HTTP Timeouts: The HTTP client now defaults to a 30-second timeout. This prevents hanging processes in your queue workers if a third-party API stops responding.
Practical Examples
- Storage Operations: When using
Storage::put(), be aware that Flysystem v3 now overwrites files by default. Always useStorage::exists()if you need to prevent data loss. - Queue Maintenance: Use the updated
php artisan queue:flush --hours=24to prune old failed jobs without wiping your entire history.
Tips & Gotchas
- Mailer Migration: If you use
withSwiftMessage, you must rename it towithSymfonyMessageto avoid crashes. - Validation Changes: Be careful when validating nested arrays. Laravel9 no longer returns unvalidated keys in the
$request->validated()output, which is a breaking change from version 8.
