HomeRésuméOpen SourceWorkBlog

First Rust Patch

Saturday, 06 September 2025

As part of preparing for my Longhorn PHP talk about what is new in PHP 8.5, I have been going through various PHP tools and checking to what extent they support the new features. When the support is lacking, I have sometimes tried to add it myself; this led me to making my first patch in Rust.

Most of the common tools for analyzing PHP code (e.g. PHPStan and PHP Codesniffer) are written in PHP. However, I recently came across a new tool currently in development, mago, that is written in Rust. I have approximately zero experience with Rust - I've seen some Rust code before, but I don't recall having written any myself. Until now.

My last RFC for PHP 8.5 was adding support for #[\Deprecated] on traits. After I merged the implementation yesterday, I started working on patches for the various tools to add support for the new feature. I hadn't contributed to mago before, but I saw that mago already had support for reporting a trait as deprecated when it had a @deprecated comment, so I figured that it would be pretty simple to try and add warnings when the attribute is found.

The logic to warn about using deprecated traits was already there. And, I was able to look at an existing case (processing of the #[\NoDiscard] attribute) to figure out how to examine attributes. The entirety of my Rust code was the addition of:

if class_like_metadata.attributes.iter().any(|attr| attr.name.eq_ignore_ascii_case("Deprecated")) {
	class_like_metadata.flags |= MetadataFlags::DEPRECATED;
}

to the scan_class_like function in the codex crate.

I like learning, and I especially like learning new programming languages. Rust has been on my list for a while now, and this experience showed me that it has some features that PHP lacks. For example, the condition above, if implemented in PHP, would look something like

if (array_any($class_like_metadata->attributes, static fn ($attr) => strtolower($attr->name) === 'deprecated')) {
	$class_like_metadata->flags |= MetadataFlags::DEPRECATED;
}

PHP does not support methods on primitives types, and requires more boilerplate for its inline anonymous functions. (The "scalar_objects" extension adds support for methods on primitive types, but has a disclaimer that it is intended to be just a proof of concept.) I can definitely see the appeal of Rust, even if I don't fully understand the code that I wrote. I probably shouldn't have skipped past the "Hello, World!" step.