React is such a good idea that we will spend the rest of the decade continuing to explore its implications and applications.
I haven’t taken a serious look at PHP in over a decade—and that’s on me. Feels bad, given the current hype and traction. Especially because that’s where my journey with coding all started. I’m the ambitious, starry-eyed dreamer that left my hometown.php in the dust for the big city lights and never looked back.
But there’s been a palpable shift in the air. You can sense it. People seem… excited about PHP.
What happened? Well. Laravel happened (and has been happening).
I’ve literally never touched Laravel. That changes today, here, now, in this blog post, raw, unwrapped before your very eyes. Will I become a fan? Will you? Unknown. Let’s see what we uncover.
But first… we have to address the obvious.
How PHP soured thousands of developers
I’ve met so, so many developers who earned their wings by writing a procedural, top-to-bottom home.php and hucking it up to DreamHost via FTP. It was PHP’s learning curve—or better yet, lack of a learning curve—that made it so dang easy to get started feeling like a magical internet hax0r:
However, it was this same swiss army knife approach that ultimately handed it a bad rap. This sort of no-guardrails code drilled the idea that PHP was never going to be a viable choice for scaling apps of the future into the heads of thousands of devs who, just like me, have never checked back in.1 Poor design decisions, regrettable function names, global variables… oh my.
It’s not that there weren’t any conventions or frameworks. It’s just… to me, even those weren’t so hot (CodeIgniter? Symfony? Kohana? W…Wo…WordPress? shudders).
The truth is, I only learned PHP (and honestly, to write code at all) because I had no other option. I never even wanted to be a programmer. I yearned for a personal website with more functionality and pizazz than your run-of-the-mill index.html but, back in 2007, the only collateral you’d find in my college pockets were suspiciously-dirt-cheap Lionshead bottle caps with rebus puzzles printed on the underside. I had no cash to pay a “real” developer, so… down the rabbit hole I went.
And in that hole I stayed. In that deep, dark hole. Where I also befriended jQuery, Subversion, and Bootstrap. And lots of lost laundry socks.
NodeJS and the decade of JavaScript
I’m fast-forwarding a bit for brevity, but it wasn’t too much later that a chap named Ryan Dahl introduced a way to execute JavaScript code outside a web browser.
What a moment that was. You mean to tell me that I can write JavaScript everywhere? That my whole stack would forever be at peace, hugging, shaking hands, laughing over a fine dinner, seamlessly handing off front-end interactivity to backend logic in a blissful state of being?
The minds of developers everywhere activated all at once, racing with possibility. We braced for impact and endured a furious flurry. Ember. Express. Backbone. Koa. Meteor. Knockout. Knockback. Rivets. AngularJS. The… other Angular.
Oh, gosh. The wars had begun. And I’d cried more tears and curled up in bed longer than ever. Was this the actual bottom of the dark hole? Would I ever want to code again? How do we recover from this?2
Almost on cue, I heard about React from a guy named Wes. Fatigued, with cold sweats, I bought his course, begrudgingly subscribing to learn yet another JS tool.
Unexpectedly, the clouds parted. I could tell: at least for me, the storm was over.
It’s okay, Dave. Open your eyes. You can climb out of that hole. It’s all gonna be okay.
I wasn’t the only one who felt that way. There were frameworks to be built. We were entering the next era.
A little project named Laravel
All the while, some kid named Taylor Otwell had been happily chipping away at a more advanced alternative to CodeIgniter. He published the first Laravel beta release all the way back in June of 2011. How’d I miss that? Where was I? Even more, where was he? I don’t know Taylor, but how he managed to escape unscathed from the Great Unrest™ of the JavaScript ecosystem completely blows my mind.3
My understanding of Laravel is even more cursory. But still, even as an uninformed outsider, I am vaguely aware that one of Laravel’s top selling points is the first-class support for what feels like everything that you’d ever possibly want to implement in a web application.
Need to manage Stripe subscriptions? Cashier can help with that. Want feature flags? Sure, there’s Pennant. There’s even a supported package for social authentication called Socialite.
These aren’t community contributions, mind you. These are supported by the same folks that built the core Laravel framework. Okay, that’s pretty sweet. That's what sticking to the same tech for 13+ years will do for ya. +1 internet point to Laravel. +1 internet point to… PHP? What year is it?
Here’s what makes Laravel so great
Just kidding, I don’t actually know the answer to that yet. We’re going in cold. Let’s build something live. Now.
I visit the Laravel website, click the creamy orange Get Started button as fast as humanly possible, and jump straight towards the Installation docs.
I see me! I’m on macOS. Gimme Laravel Herd, whatever that is. Immediate download, install, open. Didn’t check for package validity or anything. Don’t tell our security team.
Oh nice. No CLI here. I’m great at clicking buttons.
Bam! A Laravel project initiated without typing a single keystroke. I haven’t really had to use my brain at all yet. I don’t know about you, but that’s a good day.
I open up the scaffolded code and give it a look-see.
Some minimal clicking around gives me the lay of the land. Routes are defined in… well, /routes. The default route loads up a view called welcome. I’ll be honest, I wasn’t expecting to look in the /resources directory for a view, but I suppose it’s not too unusual.
There we go, some HTML. I’m ready to take this app by the horns. cracks knuckles
Wait a sec.
I write blog posts these days, not production code (we’ll leave that up to the rest of the experts here at Mux).
Not to worry. That’s what AI IDEs like Cursor are for. Let’s fake it til we make it.
I know nothing about Laravel. Zero. Can you please remove all content and edit this page to show a demo video using Mux Player?You can find out how to do that with some example code on the Mux Documentation.@https://docs.mux.com/guides/play-your-videos
I copy-pasta Cursor’s AI-generated response into the welcome.blade.php
Holy moly, it actually worked. There’s my video. Right there in Mux Player. It plays back flawlessly. It looks good. It’s correctly centered within a div. How? How?
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Mux Player Demo</title>
<!-- Mux Player Script -->
<script src="https://cdn.jsdelivr.net/npm/@mux/mux-player"></script>
</head>
<body>
<div style="display: flex; justify-content: center; align-items: center; height: 100vh;">
<mux-player
playback-id="DS00Spx1CV902MCtPj5WknGlR102V5HFkDe"
metadata-video-title="Mux Demo Video"
metadata-viewer-user-id="user-123"
stream-type="on-demand"
style="width: 80%; max-width: 800px;"
></mux-player>
</div>
</body>
</html>
That’s not gonna cut it though. I need some dynamic routing. This new Laravel app is that start of something huge. It'll need to load up thousands of UGC videos, each having their own Playback ID. It’s the future. The next big thing. I rewrite my next prompt:
I love your can-do attitude, Cursor. Make me look good.
Here’s what it’s suggesting we do:
First, we should create a new view file called video.blade.php in the resources/views directory
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Mux Video Player</title>
<!-- Mux Player Script -->
<script src="https://cdn.jsdelivr.net/npm/@mux/mux-player"></script>
</head>
<body>
<div style="display: flex; justify-content: center; align-items: center; height: 100vh;">
<mux-player
playback-id="{{ $playbackId }}" ​
metadata-video-title="Mux Video"
metadata-viewer-user-id="user-123"
stream-type="on-demand"
style="width: 80%; max-width: 800px;"
></mux-player>
</div>
</body>
</html>
Okay. Looks basically the same, except we have a Mustache-like handlebar dollar sign variable in place of where the playback ID once was. Dollar sign, I’ve missed you!
Next, we create a simple controller at app/Http/Controllers/VideoController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class VideoController extends Controller
{
public function show($playbackId)
{
return view('video', ['playbackId' => $playbackId]);
}
}
This part took me back to my aimless Chicago afternoons spent noodling in Rails. I reminisce, dancing fondly through my historic abuse of var_dump and binding.pry. It’s all coming back to me now.
That was then. Laravel is now.
Finally, we're to create a new route in routes/web.php
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\VideoController; ​
Route::get('/', function () {
return view('welcome');
});
Route::get('/videos/{playbackId}', [VideoController::class, 'show']); ​
Two lines of code. What do we think? Is it gonna work? I move the playback ID up into the URL, visit http://noideawhatimdoing.test/videos/DS00Spx1CV902MCtPj5WknGlR102V5HFkDe, cross my fingers and toes, and hit refresh.
Boom! LFG Laravel! A dynamic video page, built in just a few minutes.
So it’s looking like the Route definition allocated the playbackId variable to whatever appeared in the URL path at that location and handed it off to the controller. Then, the controller took the baton and propagated it down to the view. MVC never felt so right.
I probably should double-check another playback ID, just to be safe. I change the URL.
Sure enough, my dynamic video playback app powered by Mux is ready for the masses.
What is this feeling?
I have to say… that was easy. Too easy. Nice separation of concerns. Valid code generated by the AI underlords. Big, bright, beautiful orange buttons.
I’m starting to feel a bit funny inside. What have I been doing all this time? I click around the directory structure a bit more.
Does this thing come with a database too? And Auth? Mail? Queue management? Sessions? Testing? How is this possible? How does it come with everything? Is fast-as-heck video transcoding, battle-tested delivery at scale, and quality of playback experience monitoring up next? Are we as a company doomed? Who are you, really, Taylor Otwell, sir???? And how did you get that Lambo??
Okay. One more improvement. Just one more and we’ll call this little experiment finished.
I want this video playback page to be the best that anyone has ever seen. Beautifully designed. Expertly crafted. We don't need new tooling, or extra JavaScript, or excessive mentions of "use client" — nope, not here. This is Laravel, baby. I'm a believer.Whip it up. Do your thang. Make this page shine with some incredible CSS. And don't forget to use Laravel's signature creamy orange color: #f9322cYou might even wanna give Laravel a warm shout out in big bold text at the top of the page.
Now that’s a video player.
PHP is dead. Long live PHP!
Am I a convert? A newly-minted PHP Web Artisan? You bet your bottom $dollar I am. Depending on how critical you are of my AI coding approach, you might argue that I've still literally never touched a Laravel application. But I'll tell ya what: Laravel makes PHP fun again. I am here for it. Maybe you should be, too.