First Rust Patch
Saturday, 06 September 2025As 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.