Joe Hoyle

PHP-Deno: Learning Rust the Hard Way

Image showing Rust, PHP, Deno and V8 logos smashed together.

For several years I've been interested in the edge-computing “v8 isolates everywhere” approach to building web applications and the like. From a software perspective, I think the idea is enticing: lightweight JavaScript that is secure, simple and fast. Easy to deploy (with things like Deno Deploy), cheap (serverless) and portable (largely.)

JavaScript and the ecosystem continues to evolve and mature at a quick pace. I'm a big fan of Deno, mostly because it vastly simplifies writing JavaScript (and has first class support for TypeScript). Dependency management is much simpler, and it's aligned with ECMA script web APIs now, and into the future.

I've also been experimenting with Ryan McCue on a way to bring v8 isolates to WordPress enabling secure, sandboxed extensibility to WordPress; as an alternative to the “insecure-by-default” PHP WordPress plugins. This was done using the php-v8js extension, which provides PHP bindings to the V8 JavaScript engine. Unfortunately, that project is largely abandoned, which also lead to me re-implementing it in Rust (a story for another day.)

Deno is a more widely supported V8 isolate platform, open source and some support for embedding into other applications. Rather than providing a V8-wrapper to PHP, I thought I'd have a go at implementing PHP bindings for Deno, to allow embedding the Deno runtime in PHP applications. It's also written in Rust, which I've been interested in trying out for a few years.

Why Rust

Throughout my career as a computer programmer, I've trended towards wanting more correctness in writing programs. This has led me from JavaScript to TypeScript, to adopting and contributing to tools like Psalm (a PHP static analyser) and trying to learn as much about “types in computer programming” as my non-mathematical brain can take in. As many will know, PHP, WordPress and JavaScript are about as far away as one can get from these concepts.

Rust is a nice "reset" on programming for someone who's so used to dynamically typed, runtime driven programming. When you actually want a solid type system and want the compiler to just refuse to compile things not correct, having that feels like a godsend. When you don't appreciate those things, it is largely seen as an obstacle rather than an aid. I'm now fully in the camp of strong type systems and compiler errors being hugely valuable.

It does mean confronting your lack of understanding 5 times a minute when my Rust programs don't compile, whereby writing the same thing in PHP would at-least run! It's been interesting to observe just how much one is reduced to a novice in light of a new programming language such as Rust. It also reminds me of how I was able to learn programming in the first-place though: tons and tons of trial and error, failing, retrying and persevering. If I've learned anything in 18 years of programming (and primarily debugging) it's “never give up”. For whatever reason I have the propensity to just keep going until I solve what I'm working on when programming, be it late into the night, or back at it the next day for another round of misunderstanding, failing and feeling utterly useless.

So, why is building PHP-Deno "learning the hard way"? Mostly because it's mixing together several projects, in different languages.

It requires an understanding of how the V8 engine works (which is written in C++) which is not well documented. For what documentation exists, it's written for people way smarter than I (ones writing JavaScript engines for one thing!) V8 is embedded into Deno Core, which is written in Rust. Deno Core has a nice wrapper for V8, however most Deno functionality that we know and love is part of Deno CLI, which is written as a CLI program — not what an embedded API can use. So, Deno internals knowledge is pretty important. Then, there's knowledge of Rust - PHP bridging, which essentially requires FFI calls to the PHP C internals; so PHP internals (written in C) knowledge is essential. Ultimately, writing a Rust program to map data types and function proxying between JavaScript and PHP involved a lot of moving parts.

It has been mostly possible, though! One step at a time, grasping Rust concepts one-by-one, I have managed to produce something that compiles and for what I've been able to test so far, does work. My Rust knowledge is still very basic. I don't understand `dyn`, futures, raw pointers, lifetimes and many other things to such a degree that I can “just write it”; but I am enjoying it. I'm starting to see the light at the end of the tunnel to feel, dare I say… productive.

You can follow along with PHP-Deno on my Github repository and you can check out examples of what kind of things you can do with PHP-Deno in the examples directory.

Follow me on twitter to get future updates@joe_hoyle