I think some orgs just need to take the jump and plan a rewrite, add tests (easier with Go) and just do this if they are a PHP shop, I would say it's worth it.
Instead of blending Rust/PHP or Go together and having an unmaintainable mess of a codebase.
I understand this for a large codebase where rewriting is not feasible.
But if that wasn't the case, a C# APIs achieves both speed of development and execution in my experience. You'll rarely need to reach for C++ or Rust.
PHP is great but the language still doesn't allow things like typed arrays. It will happily accept string in a array of dates, for example.
While completely true, you are using static analyzer anyway which won’t let you do this.
The generics support will likely come in the near future, there has been momentum in it again: https://thephp.foundation/blog/2025/08/05/compile-generics/
Go made this worth it and it also was easy to hand over to another experienced developer.
Go is a pretty verbose language, whereas for me PHP is somewhere in the middle of the pack in terms of verbosity (Haskell would be on the terse side, enterprise Java and Go on the verbose end, particularly due to the constant error-checking after every function call).
PHP is really nice if you dig into it, it includes so many great functions and functionality built in for creating web stuff.
It also has a number of issues,. but to quikly put something together PHP take the win in my limited opnion.
https://github.com/el7cosmos/pasir
Which uses the following Zend API bindings for Rust:
https://github.com/davidcole1340/ext-php-rs
There's also all sorts of interesting experiments, like ngx-php, which basically embeds PHP via Zend API inside an nginx binary: https://github.com/rryqszq4/ngx-php
And workerman, which has a hybrid backend of asio libraries, so you can get pretty fast runtimes: https://github.com/walkor/workerman
https://www.php.net/manual/en/book.ev.php
PHP’s initial appeal was you could do scripting on the server side, “turn off PHP with a ?>” spit out normal html, and “turn back on PHP with a <?php”.
For a beginner programmer, it was simple, easy to understand, and had an include so your designs were’t nested table hairball messes of garbage. (but your CSS was definitely garbage).
Today, it’s so easy to run JavaScript, I can build a basic jsx site in under an hour, just like I can with PHP and includes. With Bun, I can quickly write a data access layer as well and wire up crud APIs w/ JWT auth. A weekend project in both.
I do get why JS appeals to people, but switching from PHP to JS feels a little winning an internet argument — you might feel smarter for doing so but in reality all you’ve done is sunk time into something that doesn’t make you any better off.
Unfortunately I can't think of anything constructive to say about this nonsense.
> Today, it’s so easy to run JavaScript, I can build a basic jsx site in under an hour, just like I can with PHP and includes.
You assume people agree that it's preferable to work in JavaScript.
It should be more like: what pixels is the user about to see? What data is need to set the the pixels? What data is likely needed next and optimistically pre-fetch - something like that.
If you combine Go + Templ for instance, your "if err" are mostly on the DB calls. What you needed to check in PHP anyway.
Yes, the if err != nil is extreme frustration when your doing for instance, type conversion. But if your already doing this with reflection in your DB calls (by casting to the correct types in your struct), that saves a ton.
Same with getting external data, casting it directly to structs and if something is wrong, its a single "if err".
And if your just doing PHP style programming in Go, well, _, ignoring errors like PHP does and you can panic/recover to make Go act as badly as PHP, to save on the "if err". ;-)
But as PHP have released newer versions I'm convinced our migration away from PHP (which is just finishing) is probably a step backwards _now_ that PHP is awesome.
Everyone still thinks it is like 5.x days, it really isn't.
Yeah theres a bunch of oddities that rear their head from time to time.
I've had one peculiar JSON de-serialize bug lately that really threw me for a while. I normally do the json_decode() with the second arg set true, which yields an assoc arr. This doesn't tell the whole story though. IF the key is numeric when decoding, PHP will make its key an int! and not a string like the rest. I'm guessing it does the equivalent of an is_numeric() check or something.
This yields an array with keys which could be ints and strings :/
Still for all its warts though it is a fantastically Frankenstein of a language!
For PHP on the other hand - even when I started writing PHP3 - so certainly not the very beginnings, it's clearly just cobbling together whatever works from unrelated half-understood parts and so there's no coherent centre to it, when I last worked on some PHP earlier this year it still felt like bailing wire and string.
Equally, PHP3 is worlds apart from modern PHP.
Your point is a little like saying “motorbikes are easy to maintain because they’re based on the penny-farthing”. Times have changed and your references are literally decades out-of-date.
It always seems to be a challenge to upgrade dependencies for these projects. Its usually because (in building the thing) one can't fully follow the "prescribed" way of doing things with the god framework, because each project has to deal with a niche infrastructure environment and/or business context that requires some hack or additional dependency. Then when you need to, say, upgrade a language version, you can't follow the god framework's guide for doing this (if there even is a decent one) because it will break your workaround. So you end up with this hodgepodge which never gets updated until it reaches a critical point where it cannot continue to run on your infrastructure, and it forces a big migration project.
Using a selection of libraries to build up the elements of a web service, and creating your own high-level abstractions for utilizing them, does require an additional time investment, but it leaves you in more control to do upgrades piece by piece, and to pivot the way things work when it is needed.
I feel like the Go ecosystem follows the latter approach more than most, and it was bit of a mindset shift for me at first, but I've grown to appreciate it.
The niche I think PHP had back in the day has largely been supplanted by Python.
Maybe it’s better now, but after moving on from it to basically anything else after a 25 year career, I don’t miss it.
One of the reasons I like Perl is because of its high committment to backwards compatibility.
I like PHP because it's so easy to set up an installation of my app, but the breaking changes have bit me hard in the past, so I try to minimize its use.
Together, it's a great combo.
I get to forget about HTML and Javascript, CSS, most of the complication of the browser and web, and just write an application in my favorite language which will run fast and deliver GL accelerated graphics to it's users.
I am really happy with WASM / WebGL for being abstractions which allows for this.
I don't really agree. I think the goal should be to reduce complexity where possible, but not if you're inevitably painting yourself into a corner.
If you want the simplest and most scalable way forward, write static pages and avoid server-side rendering.
At this point it's diverged from PHP to the point that it's basically a different language, is (IIRC) actually slower than PHP 8, and the HHVM doesn't even support PHP any more.
As such, it's not a huge surprise that relatively few people outside of Meta give it much attention.
I also moved on from PHP several years ago, and don't miss it. That doesn't mean I don't recognise that there are still perfectly legitimate reasons to choose it.
If you're making a simple app then web frameworks can feel downright magical (like the original "Build a blog in 15 minutes with Rails" demo [1]), but for anything that gets even remotely complicated, I find that they generally just get in the way.
I personally have grown to prefer the "mid-level" HTTP setups, like Express with Node.js or Vert.x with Java.
[1]
It's inevitable that you will need to host the pages somewhere else like a CDN to lower latency, integrate with other backends, and the biggest one is allowing the frontend devs to have complete control of the HTML so that stylesheets and javascript don't randomly break for reasons out of their control. They should be able to develop everything locally with mocks instead of your server and use whatever build tools and frameworks they want. There are also SEO and accessibility concerns with the page structure. The backend devs should not be making decisions about any of that. Sometimes the client may want quick turnaround on simple but very specific changes to the pages. None of that process should depend on backend teams who don't care and will drag ass about it because they will have to refactor their junky code that hasn't been touched in years.
Getting rid of dependencies and having good boundaries in the code that align with the way dev teams are organized is always a good thing. I'm not sure why anyone would go for SSR unless they haven't done web dev in a while or are working on a legacy project. Even if this starts out as a hobby project, you need to keep things clean for future maintainers.
The cognitive load is null. You’re just having trouble breaking apart your learned behavior. Returning a component of jsx is just the same as writing an include for PHP.
Browser -> Client-Side Server Pages -> Business Logic APIs -> Backend Systems.
And meta/hack is probably the other huge mainstay of PHP outside of what the person you responded to said. And hack with HHVM was supposed to be the panacea for PHP
Just saying.
What people used to use PHP for tasks, has largely been replaced by Python.
Not only that, but now we have these "frankenstein" solutions with all the interop problems on top of PHP.
Just shows that as a species humans really can't learn.
The initial equality operator was a mistake, but that was rectified over a decade ago with `===`. Not having a proper int type sucks and holds the language back in a number of ways, but otherwise the language is wonderfully regular.
And anyone who complains about the ecosystem has obviously never tried python, which after a decade of attempts, is now almost on par with JS of a decade ago!
Flask prescribes so little that every project is a snow flake. Which of the N available options will you pick to handle auth/templating/cookies/email/whatever. Real decision fatigue when trying to enable core functionality. Extra special is that many of these libraries are single author creations, so maintenance and security are a mixed bag.
Django - every project roughly looks the same. You get so much out of the box that you must have special requirements if you must supplement with libraries. Since so many bits are first party, you have greater confidence that code is being maintained/checked for security problems.
I really think there's a big opportunity for somebody to create the astral.sh for PHP.
With a proper package manager, PHP can do way more than what it presently can.
It’s the best of both worlds - the new app gets to see all of the traffic, but doesn’t need to implement 100% of the routes. Any added to the new app can just take precedence over the old one, carving out the path-space that gets reverse proxied.
It seems like doing FFI for this is overly complex; I’d rather take the small perf hit of doing another request to a different process.
Cool that you’re creating an actual desktop-style gl app with it.
Another minor annoyance is that 'cargo bloat' and similar tools don't yet have backends for wasm, so I need to fix up the native build to make use of that sort of analysis, which I'd like, because I serve the whole application from microcontroller flash where I only have 4 - 16mb to hold application and firmware, including the http server and network stack.
Please consider joining the Discord: https://discord.com/invite/cCHRjpkPhQ
I'm the only one in there at the moment. Bring friends! lol
I learned how to build for the web by looking at webpages and seeing how they worked. What you're describing is the switch from circuit boards of discrete components to everything in a single microscopic IC under a blob of epoxy.
And solutions that try to fix this (custom templating engines, runtimes that run the whole thing inside a continuous PHP process) are simply putting lipstick on a pig.
The solution is to use a language that wasn't originally called "Personal HomePage"
Like you, a part of me years for SGML and The Semantic Web, and where it makes sense in Alumina I am using RESTish APIs.
But I do not pine for Javascript. Language or frameworks. 20 years has been enough. And I do not believe that some of the 4mb minified obfuscated js downloads from a CDN I've seen are in any way more accessible than a WASM binary of similar size. At least there is advanced tooling for the WASM representation. Folks who want you to read their code will still make it easy, and folks who don't won't.
To your point about learning, WASM makes some really incredible systems like https://lovr.org/ available in the browser, which I would have loved to have as a kid, but which also aren't javascript. It's related to Turing completeness somehow, once you let a little software into your structured document, it all wants in. Or maybe it's "if you give a mouse a cookie"?
I understand what you're saying about discoverability. But the developer in me really likes having a relatively simple binary interpreter to target for network-delivered cross-platform binary applications. My hope is that offering such a juicy target to the folks who want to develop applications (including myself) gets them out of all the semantic document features, allowing both sets of code to get simpler and more focused. Because I think they're two different, both entirely valid, tasks folks use the web for.
Ever want to type `$model->foo instead of $model->getFoo()` but then have `$model->foo` magically call `$model->getFooAttribute()`, but fall back to `$model->getAttribute('foo')` if that method doesn't exist? Then that magically calls some casting methods, and possibly even fetches infinite records from a remote store? It is so artisan, bro. I can tell you more if you got five minutes.
You usually build the modules yourself in the Dockerfile, for example for the "pgsql" module:
RUN apt-get update && apt-get install -y libpq-dev && docker-php-ext-install pdo_pgsql && apt-get remove -y libpq-dev && rm -rf /var/lib/apt/lists/*
And for http, you just put the following in the Caddyfile: http://:80 {
# rest of the Caddyfile directives
}
Step 2: (There is no step 2.)
Can you give any specific examples?
I'd like to see which of these are open source. And whether or not they're funded for maintenance.
Saying “at least x isn’t as bad as y” doesn’t further a discussion, it only acknowledges denial about just how bad the problems are with x.
This is particularly true when we weren’t even discussing y (in our case, Python) in the first place.
The fact this happens to lead to more organized and testable code masks the wastefulness in the original goal of such an effort. It simply trades back-side efforts that may or may not ever be required for additional front-side effort with the result of making things easier later if it happens to be needed. I’m not saying it is completely a bad thing, more that it isn’t de-facto a good thing either.
I guess, like with all things, the important part is finding the right balance for the situation.
This matches my experience, literally took months to migrate an older Spring project to something with fewer CVEs and bugs. Created some new bugs and issues along the way, including one where compiling it on Windows would produce a .jar that runs fine, whereas compiling it on Linux changed something in how the Spring beans are initialized, leading to it failing to even start (the settings for allowing lazy initialization changed nothing).
> Using a selection of libraries to build up the elements of a web service, and creating your own high-level abstractions for utilizing them, does require an additional time investment, but it leaves you in more control to do upgrades piece by piece, and to pivot the way things work when it is needed.
Yes and no. If you only wire things up, then sure. But depending on how much code your devs have to write (and depending on the devs), you might actually end up with a bespoke mess if you have to dig into writing various base mechanisms (think transaction handling, scheduled tasks, task pools for parallel execution, key/value stores and caching, validations, auditing and metrics, file uploads and downloads etc.) - one that will have less documentation than something like Spring Boot, you won't be able to ask anyone how to solve issues in it, alongside sometimes just having architectures that neither scale nor work properly, because it isn't something battle tested over literal decades.
> I feel like the Go ecosystem follows the latter approach more than most, and it was bit of a mindset shift for me at first, but I've grown to appreciate it.
I still agree with this, to me it feels like the correct approach is indeed to give you most of the tools you might need for the technical bits and make you (or other devs) only write a bit of glue to wire everything up, to order how data moves through your system (resources, services, validators, repositories etc.) according to whatever business rules you might have. Things really go south when you miss out on that detail.
In the Java land, I think Dropwizard is a good example of that: it uses a bunch of mostly idiomatic libraries that are well tested, without being quite as rigid as Spring (and Spring Boot), letting you set things up as you please and also not getting in the way too much: https://www.dropwizard.io/en/stable/getting-started.html
In Go, I really like that a lot of the stuff is already present in the standard library.
Twig and Blade are both fine templating engines with their own quirks and features but they’re also battle tested and have proven their use over the past decade+. If someone wants to use a dedicated templating language for abstracting away chunks of HTML, it’s low on my list of complaints.
vim projects/example.cs
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
dotnet run projects/example.csNot the same as PHP I know, but it's close enough for me.
PHP:
- vim projects/webhook.php
C#: - vim projects/webhook.cs
- Assign a port number
- Reconfigure Nginx/Caddy to serve that port number
- Reconfigure systemd to dotnet run projects/webhook.cs on startup
For instance, PHP allows for even function calls like this:
$language = "German";
$functionName = $language."_send_email";
$functionName("Mike", "mike_1@gmail.", "Text ...");
This sort of flexibility has its own problems and it is only possible because of the very lax type system of PHP but it is also extremely powerful when it comes to developing reusable frameworks.
Not having the equivalent of hibernate level ORMs is not a disadvantage for me personally, just because I don't like ORMs - Asking chatgpt to spit out some SQL and mapping code for me and being able to tweak the actual SQL over time is preferable (but again that is just my preference).
I don't really agree with the idea that Go has an underdeveloped type system, I think its contraints lend itself to productivity in other ways. Of the various languages I've worked with, Go programs I expand have the highest chance of working the first time I run them, because the compiler and language server A) give meaningful indications of mismatched usages and B) older Go projects have a very good chance of just working, without me having to worry about getting them going with my IDE again. B is a product of the fact that they have been very conservative with the language.
But I would say a 20k line PHP app is pretty small… we probably have 20 different 1k+ files in our app. They’re not pretty but they’re still fast enough and they work so I’m not gonna try and rewrite them just for giggles.
That said, when working on this legacy behemoth, it’s not uncommon we find a way to delete a few hundred lines because there are so many old features that aren’t needed by the business anymore so we can remove that cognitive load from codebase. Maybe that had a similar experience and the rewrite was just a good time to get buy in from the business to admit that the features weren’t important anymore. We run an e-commerce site so there are lots of little marketing experiments cluttering the app and it’s a constant churn to remove old ones and add new ones for people to tweak and test with feature flags. Removing dead code is just a part of the job.
In the past it got away with it because of PHP magic. PHP let's you do pretty much whatever, at least in the past.
Typescript exists, but if I'm compiling something I'm using a real language or framework like dotnet. There's no reason for me to use typescript and node and install 100 packages when I can just install dotnet.
We can "lipstick pig" a lot of those problems by using typescript or whatever, but now we're compiling JS and the output isn't even fast. At that point use a competent compiled language like C# or Rust.
While strongly typed languages are great. I like to be able to get things done. This is why I don’t C++ anymore. This is also why I don’t dotnet anymore. Too much BS with the type system and correctness and the Microsoft way or lack of support or rug pull. They lost me when they killed XNA.
Typescript is actually good, except for the fact that it’s a transpiler to JavaScript. That part sucks.
I want a C++, with Types, with memory safety, with garbage collection, with pointers, with a dev experience like dotnet, but we don’t have those things.
The difference is TS has to be compiled, PHP doesn't. If we have to compile stuff we might as well use a more safe language like C#.
Also no, Node is not fast. I don't know why people think Node/JS is fast. JS has very poor performance characteristics and it can't be fixed because it's a factor of the language design - although, PHP has similar problems.
Chromium is very optimized, for specific scenarios. Its still a dynamically typed, garbage collected language - and optimizing a for loop in a play pretend medium blog doesn't change that.
amqp,apcu,ast,bcmath,brotli,bz2,calendar,ctype,curl,dba,dom,exif,fileinfo,filter,ftp,gd,gmp,gettext,iconv,igbinary,imagick,intl,ldap,lz4,mbregex,mbstring,memcache,memcached,mysqli,mysqlnd,opcache,openssl,password-argon2,parallel,pcntl,pdo,pdo_mysql,pdo_pgsql,pdo_sqlite,pdo_sqlsrv,pgsql,phar,posix,protobuf,readline,redis,session,shmop,simplexml,soap,sockets,sodium,sqlite3,ssh2,sysvmsg,sysvsem,sysvshm,tidy,tokenizer,xlswriter,xml,xmlreader,xmlwriter,xz,zip,zlib,yaml,zstd
https://github.com/php/frankenphp/blob/main/build-static.sh#...