Why Go, for a PHP dev
You already know how to build things. This course isn't going to teach you what a loop is. (If you've ever written $response['data']['data'][0]['data'] and shipped it anyway, you're among friends.) It's going to take the PHP instincts you've built up over the years and show you where they carry straight over to Go, where they need adjusting, and where they'll actively trip you up.
Let's start with the biggest one, because it changes how you think about everything else.
Your PHP app doesn't really exist between requests
Here's what happens when a request hits a typical PHP app. nginx hands it to PHP-FPM, a worker picks it up, your code boots (autoloader, container, config, routes), handles the request, sends a response, and then throws everything away. The next request starts from a clean slate.
That's the shared-nothing model, and it's quietly brilliant. PHP is the goldfish of runtimes, and we mean that as a compliment. A memory leak only lasts one request. A global variable can't bleed into someone else's request. If something goes badly wrong, the worker dies and FPM starts another one. You've probably never had to think about any of this, and that's the point. (Your memory_limit = -1 is safe with us.)
A Go app is a program that keeps running
A Go web app is a single compiled program. You start it, it boots once, opens its database connections once, and then sits there handling requests for days or weeks, many of them at the same time.
flowchart TB
accTitle: Request lifecycle, PHP-FPM compared with Go
accDescr: With PHP-FPM, every request boots the app, handles the request, then throws everything away. With Go, the program boots once and every request goes through the same running process, which keeps shared state such as the database pool and caches between requests.
subgraph php ["PHP-FPM: on every request"]
direction LR
R1([Request]) --> B1[Boot app] --> H1[Handle it] --> D1[Throw it all away]
end
subgraph go ["Go: boot once, serve forever"]
direction LR
Q([Requests 1, 2, 3…]) --> Hd[Handler] <--> St[(Shared state: DB pool, caches)]
S([Start binary]) --> B2[Boot app once] --> St
end
php ~~~ go
style php stroke:#4F5394,stroke-width:2px
style go stroke:#00728F,stroke-width:2px
So a variable declared outside your handler isn't reset between requests. It's just... still there, like that one .env value nobody remembers setting. Check the Interchange tab (the side-by-side PHP⇄Go view you'll get in every lesson): the same visit counter gives you 1 every time in PHP, and 1, 2, 3… in Go.
| PHP-FPM, 09:00:00 | Boots app. Serves one request. Forgets everything. |
|---|---|
| PHP-FPM, 09:00:01 | Boots app. Serves one request. Forgets everything. |
| PHP-FPM, 09:00:02 | You get the idea. |
| Go, 09:00:00 | Boots app. |
| Go, 3 weeks later | Still running. Remembers everything. Including that cache you forgot to clear. |
Mind the gap
Shared state is Go's superpower and its sharpest edge. Anything you put in a package-level variable is shared by every request, at the same time, for as long as the process runs. That's great for a connection pool or a cache, and a disaster for "the current user". Units 6 and 8 cover how to do this safely.
What you get for that trade
- One file to deploy.
go buildproduces a single executable with no runtime to install, novendor/to upload and no FPM pool to tune. Copy it to a server and run it. - Concurrency built in. Handling thousands of requests, or fanning a job out across 50 workers, is a language feature (goroutines and channels), not a queue package and a supervisor config.
- Mistakes caught before deploy. It's compiled and statically typed, so a typo in a variable name is a build error, not a 500 in production.
- A small language. Go has 25 keywords. There's usually one obvious way to do something, and
gofmtends the style arguments. - A serious standard library. HTTP servers, JSON, testing and crypto are all in the box.
Where PHP is still the better choice
This isn't a "PHP is dead" course. (The name's a pun, honest.) If you're building a server-rendered app with auth, queues, mail, an admin panel and a dozen integrations, Laravel or Symfony will get you there faster than Go will. Go has no Eloquent, no Artisan and a lot less magic, and its error handling is famously wordy. You'll type if err != nil so often your fingers will do it in your sleep.
Where Go earns its place is next to your PHP app: the queue worker that needs real concurrency, the API that needs to be fast and boring, the CLI tool your team runs everywhere. That's where this course is aimed.
Laravel corner
If you've used Laravel Octane (Swoole, RoadRunner or FrankenPHP), you've already met this model. Octane boots your app once and keeps it in memory, which is exactly why its docs warn you about state leaking between requests. Go works like that all the time, except the language and tooling were designed around it from day one.
Recap
- PHP-FPM is shared-nothing: every request boots, runs and is thrown away.
- A Go program boots once and serves every request from the same process, so state persists and is shared.
- Go buys you single-binary deploys, built-in concurrency and compile-time safety. PHP still wins on framework-heavy web apps.