Skip to content

Laravel 13 and the Attributes-First Revolution: Modernizing the Framework

Published: Duration: 6:52
0:00 0:00

Transcript

Host: Hey everyone, welcome back to Allur, your go-to space for everything happening in the worlds of PHP, Laravel, Go, and mobile dev. I’m your host, Alex Chan, and today... wow, do we have a big one. Host: Joining me today is Marcus Thorne. Marcus is a senior staff engineer who has been building enterprise-level Laravel applications since the version 4 days, and he’s a huge advocate for static analysis and clean architecture. Marcus, it is so great to have you here on Allur. Guest: Thanks, Alex! It’s great to be here. Yeah, "Attributes-First"... it’s definitely the topic of the hour in my Slack channels right now. People are either cheering or scratching their heads, so I’m excited to dig into it with you. Host: (Laughs) I bet! So, let’s start with the big "why." Laravel 13 is making a pretty bold move by requiring PHP 8.3 as the bare minimum. That’s a significant jump. Why do you think the core team is being so aggressive with the versioning this time? Guest: It’s actually a really smart move, even if it feels a bit "bleeding edge" for some. By locking in PHP 8.3+, the Laravel core team can finally stop writing "poly-fill" style logic to support older versions. But specifically for the Attributes-First vision, they need the latest improvements in how PHP handles reflection and metadata parsing. If you’re going to move all your model configuration into attributes, the framework has to be able to read those attributes extremely fast at scale. PHP 8.3 gives them the performance runway to make that happen without slowing down the request lifecycle. It’s basically about trimming the fat. Host: That makes total sense. So, let’s talk about the actual "look and feel" of the code. We’ve all seen the classic User model with those huge arrays at the top of the class. What does the "Attributes-First" approach actually look like in practice? Guest: Oh, it’s a total shift. Think about your current `User` model. You probably have a `protected $casts` array at the top, and then way down in the file, you have the actual logic. In Laravel 13, the configuration lives *with* the data. So, right above your `public string $email` property, you’ll just have `#`. Above your `password` property, you have `#`. Host: Interesting! So, instead of scanning back and forth between the top of the file and the property list, it’s all right there? Guest: Exactly. It’s like the "Data Mapper" pattern you see in things like Doctrine or even some Java frameworks, but it keeps that "Active Record" ease of use that we love about Eloquent. The big "aha moment" for me, though, isn't just the aesthetics—it’s the static analysis. Host: Tell me more about that. I know you’re a big PHPStan fan. How does this change the game for tools like that? Guest: It’s huge! Currently, tools like PHPStan or Larastan have to do a lot of "guessing." They see a `$casts` array and try to infer that a certain column is a Carbon instance. But with attributes, the metadata is literally attached to a typed property. Your IDE knows *exactly* what that field is without any magic. It makes your code so much more robust. You get near-perfect autocompletion and type safety right out of the box. Honestly, it makes the "legacy" way of doing things feel a bit... um, disconnected? Host: I can see that. But I have to play devil's advocate for a second. I’ve seen some developers on Twitter—X, I guess—complaining about "visual noise." They’re saying that having `#`, `#`, and `#` all stacked on top of a single property makes the class look cluttered. What’s your take on that "noise" argument? Guest: (Chuckles) Yeah, I’ve seen those threads. Look, I get it. If you’re used to a very "clean" looking class with just properties, seeing those tags can feel a bit busy at first. But I’d argue that what people call "noise" is actually "explicit clarity." In the old way, the behavior of a property was hidden inside a protected array that could be fifty lines away. Now, the behavior is explicit. I’d rather have a slightly "busier" file where I can see exactly what’s happening at a glance than a "cleaner" file where the logic is hidden in a series of disconnected arrays. Host: That’s a fair point. It’s about where you want your complexity to live, right? Guest: Exactly. And it’s not just models, Alex. That’s the thing people are missing. This is spreading to the whole framework. Host: Oh! Right, the Queue system! I saw a snippet of that. How is that changing? Guest: It’s the same philosophy. Instead of defining a `public $tries = 5;` property inside your Job class, or creating a `retryUntil()` method, you just put `#` at the very top of the class definition. It standardizes everything. Whether you’re configuring a Route, a Model, or a Job, the answer to "how do I configure this?" is now always: "Check the attributes." Host: I love that consistency. It feels like the framework is finally speaking one cohesive language across all its different parts. But, okay, let’s talk practically. March 17th is coming up fast. If I’m a lead dev with a massive Laravel 11 or 12 app, should I be panicking? How do we even begin to approach this migration? Guest: No need to panic! (Laughs). Laravel is historically very good about deprecation cycles. They aren't going to just break every app on day one. But, the "Attributes-First" way *is* the future. My advice? Start by auditing your environment. You’re going to need PHP 8.3. If you’re still on 8.1 or 8.2, that’s your first hurdle. Get your CI/CD pipelines updated now. Host: And what about the actual refactoring of the models? Guest: Start small. You don’t have to rewrite 200 models in one afternoon. Start with your new features. If you’re building a new module in February or March, try using the attribute syntax there. Get a feel for the declarative flow. It’s actually quite addictive once you get used to it. You’ll find yourself looking at your old models and thinking, "Ugh, I have to go scroll up to the `$casts` array again?" Host: (Laughs) It’s like once you see it, you can’t unsee it. I actually had that moment looking at a Job class yesterday, thinking how much cleaner it would be if the retry logic was just a simple attribute at the top. Guest: It really is. And for the community, it’s pushing us toward the broader PHP standards. We’re moving away from DocBlock annotations—which are basically just comments that we’ve forced to be functional—and moving toward actual language-level features. It’s a win for the entire PHP ecosystem, not just Laravel. Host: Such a good point. It feels like PHP is finally growing up and shaking off that "it’s just a scripting language" reputation. Guest: Absolutely. We’re writing sophisticated, type-safe, modern software now. Laravel 13 is just the framework catching up to what the language is now capable of. Host: Well, Marcus, this has been incredibly enlightening. I’m actually really excited for March 17th now. It feels like a "defining moment" for the framework. Guest: It definitely is. It’s the "modernization" release we’ve been waiting for. Host: Well, thank you so much for joining us on Allur today and sharing your insights. Where can people find you if they want to follow your work or see your thoughts on Laravel 13? Guest: You can find me on GitHub at mthorne-dev or over on X/Twitter at @MarcusCodes. I’ll definitely be posting some "before and after" refactoring examples as we get closer to the launch! Host: Awesome. We’ll make sure to link those in the show notes.