DEV Community

Cover image for 🐘 TypeScript for PHP? Yes, that's possible. And it's not what you think
Kevin 心学
Kevin 心学

Posted on

🐘 TypeScript for PHP? Yes, that's possible. And it's not what you think

It is time to bring opposites together, to stir up these stagnant waters, and to restore an industry that is dynamic from within, with multiple connections that were previously impossible or unimaginable.


In the previous parts of this series, we explored how PureScript acts as a quiet rewrite of the Web, offering a territory of mathematical precision above JavaScript, and how its universal polymorphism allows it to target wildly different runtimes like Node.js, Erlang's BEAM, Chez Scheme, etc.

But hey, what about the elephant in the room? Yes, what is running the majority of the web, today, in the shadow. You know. The eternal one, the veteran, the one whose death everyone talks about, but who never truly dies.

Totoro in the shadows

PHP.

While the modern JavaScript ecosystem (among others) races toward edge computing and containerized microservices, around 70% of the web is still powered by PHP. From legacy WordPress sites to affordable shared hosting (cPanel, OVH, GoDaddy, basic LAMP stacks), a massive portion of the internet lives in environments where escaping the PHP runtime is either financially unviable, technically impossible, or simply unnecessary.

And yet...

For a long time, the PHP ecosystem has been left without a true, strictly typed functional and safe alternative, like TypeScript for Javascript. Even though recent PHP versions introduced fantastic features (short closures, match expressions, Fibers), the frustration that comes with its historical limitations and dynamic typing remains very real for some of its users.

Very well!

This is why I built phpurs: a brand new compiler backend that transpiles PureScript directly to modern PHP 8.4+ syntax.

phpurs

It is no longer a proof of concept. It is passing the official PureScript test suite, and it is ready for production.

Here is how we bring the elegance of purely functional programming to the big web, while keeping deployment as simple as a legacy FTP upload, or anything alike.


The easy deployment paradox

In modern DevOps, deploying an app often means configuring Docker containers, CI/CD pipelines, Kubernetes, or serverless edge functions. It is powerful, but it is expensive and sometimes... a bit too complex for the real need. Let's be clear: I have nothing against it, I use it every day. But it's not always necessary. A website can run just fine on a very low cost server, possibly a shared one, without needing such an arsenal of tools.

For many freelancers and agencies, the reality is different indeed: clients often have a simple, small and cheap shared hosting plan. They want a robust application, but they don't want to pay for a managed AWS infrastructure.

Small Totoro

So... phpurs bridges this gap. It allows you to write your entire business logic, API, and background processes in 100% pure, strictly typed PureScript. And you get all the guarantees of ADTs, pattern matching, the Aff monad, HKTs... and so much more...

Then, you compile it, and you get plain .php files. No overhead. The compiler has pruned what the runtime won't need, and optimized everything (e.g. Tail-Call Optimization, Dead-Code Elimination, Uncurrying...).

You just drag and drop these files via FTP to your client's cheap HostGator, OVH server, or whatever... and it works. No container, no daemon, no reverse proxy. Just native execution.

One of the biggest strengths of PHP is its portability. We leverage it.


Architecture: standing on the shoulders of giants

In fact, phpurs doesn't reinvent the entiiiire wheel. It stands on the incredible work of the PureScript community (e.g. Arista's purescript-backend-optimizer).

On the shoulders

The compilation pipeline is beautifully decoupled:

  1. At first, purs compiles your code to corefn.json.
  2. The backend-optimizer reads this CoreFn and performs aggressive dead code elimination (DCE), inlining, uncurrying, etc.
  3. At the end, phpurs takes this highly optimized intermediary AST and prints it as modern PHP syntax. And of course, it will add additional and sophisticated optimizations for PHP's sake.

Concurrency: Aff meets PHP Fibers

One of the biggest historical flaws of PHP was its synchronous, blocking nature. How do you implement PureScript's asynchronous Aff monad in such an environment?

Well, PHP 8.1 introduced Fibers, and the Revolt event loop followed.

Support for Aff has been natively added to phpurs. The behavior of the event loop in the compiled PHP code perfectly mirrors its Node.js counterpart: asynchronous operations are handled transparently without blocking the OS thread. The main process will automatically wait for all pending Aff tasks to complete before exiting, for example.

You can seamlessly run your code with a JS runtime, or a PHP one. You can even switch from one to another, when you're coding.

There is no need for complex daemonized C or Go extensions like Swoole or FrankenPHP. By relying exclusively on native PHP Fibers and asynchronous libraries (like Amphp), phpurs ensures that your concurrent PureScript code can run natively anywhere PHP runs. It just works, and handles multiple requests, like a good ol' Express server in Node.


What about performance?

It would be a legitimate question. For example, PHP is often criticized for its raw execution speed compared to V8 (Node.js).

In raw micro-benchmarks, PHP 8 is indeed about 2 to 3 times slower than V8 for heavy computational tasks. However, in the vast majority of real-world web applications, the main bottleneck is I/O (database, network, filesystem).

Running Totoro

The difference in performance is entirely negligible in practice. You lose almost nothing in speed, but you gain the ability to deploy your code on any server in the world for pennies.

I recently battle-tested phpurs against the test suite of a real-world project (still a WIP, but the code is mature). The results are clear: in practice, it is only x1.15 slower. Of course, the value of this factor will depend on your very specific project(s). But remember: PHP is not the preferred backend for performance, it is for portability.


The next frontier

I am already using it in production for several client projects with strictly PHP-only environments, and the runtime stability is rock solid (and super fast). 🟢

Pure dev pleasure, with pragmatic client constraints. Getting the best of both worlds is a very, very pleasant feeling.

Happy Totoro

Community contributions are highly welcome! If you want to help add missing PHP FFIs to core and major PureScript libraries, your PRs are more than welcome.

Let's bring the elegance of PureScript to the 70% of the web that still runs on PHP! 🐘

Cheers 👋

Top comments (0)