Tout le monde va parler du SDK IA et des passkeys, et c'est de bonne guerre, ça fait de belles démos. Mais la partie de Laravel 13 qui me trotte dans la tête est nettement moins glamour : cette version livre deux réponses contradictoires à la même question, à savoir où ta configuration est censée vivre. Tu peux désormais décorer un job de queue avec un attribut #[WithQueue] qui déclare sa connexion, le nom de la queue, les tentatives et le timeout directement sur la classe. Ou tu peux laisser la classe nue et déclarer tout ça dans un service provider avec Queue::route(), en associant les classes de jobs aux connexions et aux queues en un seul endroit central. Mêmes réglages, deux maisons, et le framework n'a aucun avis sur ton choix. Alors je vais te donner le mien.
<?php
// inside AppServiceProvider::boot()
use App\Jobs\GeneratePdfReport;
use App\Jobs\ProcessPodcast;
use Illuminate\Support\Facades\Queue;
Queue::route(ProcessPodcast::class, connection: 'redis', queue: 'media');
Queue::route(GeneratePdfReport::class, connection: 'sqs', queue: 'exports');D'abord, rendons à César ce qui lui revient : la montée de version est franchement réussie. Si tu es sur PHP 8.3 ou plus récent, la core team promet zéro breaking change dans ton code applicatif et une mise à jour qui tient dans une pause café. Les attributs fonctionnent maintenant à plus de quinze endroits du framework, donc les modèles Eloquent peuvent porter #[Table], #[Fillable] et #[Hidden] au lieu d'une pile de propriétés protected, et tout est opt-in. Tes modèles existants continuent de tourner sans qu'on y touche. Cette retenue mérite un coup de chapeau, parce qu'elle signifie que les décisions intéressantes de cette version sont des choix de style que tu fais délibérément, pas des migrations imposées par une deadline.
Voici ma règle, et je la défendrais dans n'importe quelle revue de code : les décisions de déploiement vont dans le provider, la forme du domaine sur la classe. La connexion sur laquelle tourne un job, le fait que les exports PDF atterrissent sur SQS pendant que le traitement des médias reste sur Redis, ça change quand ta situation ops change, pas quand ta logique métier évolue. Router ça de façon centralisée via Queue::route() signifie que le jour où tu déplaces les exports vers un autre backend, tu touches un provider et zéro classe de job, et chaque point de dispatch reste un simple ProcessPodcast::dispatch($podcast). La liste fillable d'un modèle, en revanche, est intrinsèque à ce qu'est la chose. Elle a sa place sur la classe, et la syntaxe des attributs la fait enfin ressembler à une déclaration plutôt qu'à du bruit.
Le contre-argument honnête, c'est la découvrabilité, et je m'y suis déjà brûlé dans d'autres écosystèmes. Quand un nouveau coéquipier ouvre GeneratePdfReport et ne voit rien sur l'endroit où il s'exécute, il doit savoir que le provider existe. Quiconque a fait de la spéléologie dans une base de code Spring à la recherche du fichier XML qui explique tout connaît cette douleur, et la version avec attributs garde toute l'histoire greppable dans un seul fichier. Je reste quand même sur le routage central pour l'infra, parce que le mode de défaillance de la config éparpillée est pire : cinquante classes de jobs portant chacune sa propre chaîne de connexion, ce sont cinquante endroits à oublier quand tu migres tes queues, et j'ai vu exactement ça produire un incident un vendredi, avec la moitié des jobs partis vers l'ancien cluster.
La fonctionnalité dormante de cette version, à mon avis, c'est Cache::touch(). Prolonger le TTL d'une clé impliquait jusqu'ici de lire la valeur et de la réécrire, deux allers-retours réseau plus la sérialisation, tout ça pour bouger un timestamp. Maintenant Cache::touch('user_session:123', 3600) envoie un simple EXPIRE à Redis, frappe Memcached avec son TOUCH natif, et exécute un banal UPDATE sur le driver base de données. Si tu as déjà construit un rate limiter à fenêtre glissante ou maintenu au chaud une métrique de dashboard très sollicitée, tu sais à quel point ce motif revient souvent. C'est une petite API qui fait une seule chose et se calque proprement sur ce que chaque store sait réellement faire. Encore, s'il te plaît.
Les nouveautés plus clinquantes sont réelles aussi, je doute juste qu'elles remodèlent ton diff quotidien autant que la question de la config. Le Laravel AI SDK passe en stable en même temps que la release, donc avec PostgreSQL et pgvector tu obtiens whereVectorSimilarTo() directement dans le query builder, avec la génération d'embeddings branchée sur OpenAI, Anthropic ou Ollama. La connexion par passkey via WebAuthn arrive dans Fortify et les starter kits, et comme la clé privée ne quitte jamais l'appareil de l'utilisateur, le credential stuffing contre ton endpoint de login cesse d'être une menace qui vaut le temps de l'attaquant. Ajoute le driver database de Reverb pour scaler les websockets sur MySQL ou PostgreSQL sans machine Redis, Http::pool() qui passe par défaut à une concurrence de 2 au lieu de ramper en série, et les teams de retour dans les starter kits avec un routage isolé par onglet, pour que changer d'équipe dans un onglet du navigateur n'en corrompe pas un autre.
Une remarque au passage sur les attributs, parce qu'on peut facilement rater le chemin parcouru par PHP ici. Les développeurs Go entassent des métadonnées dans des struct tags depuis dix ans, des chaînes brutes que le compilateur ignore joyeusement jusqu'au runtime. Les attributs PHP sont de vraies classes avec arguments nommés, typés, autocomplétés, refactorables. Que Laravel s'y appuie à travers tout le framework est moins une fonctionnalité de Laravel que l'écosystème qui encaisse enfin un chèque signé par le langage dès PHP 8.0. Ça a pris du temps, mais la syntaxe qu'on obtient est plus agréable que ce sur quoi plusieurs langages soi-disant plus modernes se sont rabattus.
Voilà donc ma ligne : les providers pour tout ce qu'une décision ops peut changer, les attributs pour tout ce qui définit l'objet du domaine lui-même. Mais je connais des équipes qui rejetteront ce découpage en bloc et se standardiseront sur un seul style juste pour garder des revues simples, et je ne peux pas leur donner tort. Et toi, tu te places où ? Tu routes tes jobs de façon centralisée, tu les décores avec #[WithQueue], ou tu écris une règle Pint pour interdire celui des deux qui a perdu le débat à ton standup ? Raconte-moi ça en commentaire, surtout si tu as déjà essayé de mélanger les deux dans une même base de code.




Commentaires
Pas encore de commentaire — écris le premier.
Lance la discussion
Pas de compte ni de mot de passe — saisis simplement ton adresse e-mail et nous t’envoyons un lien de connexion à usage unique. Première visite ? Tout se met en place automatiquement.
Ton évaluation sera appliquée automatiquement après ta connexion.
Vérifie ta boîte mail
Nous avons envoyé un lien de connexion à …. Ouvre-le sur cet appareil — cet onglet te connectera automatiquement.
Rien reçu ? Vérifiez le dossier spam — et marquez le message « Non spam » pour qu'il arrive directement la prochaine fois.