A while back a proposal landed on the PHP internals list: deprecate metaphone(). My first reaction was the reflex of someone who has spent years as a PHP release master. Leave the old string functions alone, people depend on them, deprecation churn is its own tax. I was ready to argue against it.
Then I read the reasoning and went looking at what phonetic name matching is actually supposed to do in 2026. I changed my mind. metaphone() should go. What surprised me was not that the function is dated. It was how far the field had moved while PHP core stood still, and how weak the replacement path the RFC points at really is. So I built the replacement I wish it had recommended.
metaphone() is the oldest, least accurate version of an idea that kept evolving
The RFC is right, and here is the short version of why. The metaphone() in core is the original 1990 algorithm: English-only, single-key, tuned for one accent of one language. It was superseded twice. First by Double Metaphone (Lawrence Philips, 2...
Here is a bug in a name-parsing library I use at work:
// theiconic/name-parser
$name = $parser->parse('Jane Doe DDS');
$name->getLastname(); // "Dds"
$name->getMiddlename(); // "Doe"
The dental credential is now her last name. The real surname got shoved into the middle-name field. Every row with a trailing credential and no comma had some version of this, and in a list of clinicians that is most of them.
The library is theiconic/name-parser, a small, genuinely useful PHP package that splits a full-name string into salutation, first name, initials, last name, suffix, and nickname. I use it at work. It does the boring parts well. But the upstream repo went quiet around 2020, and bugs like the one above never got fixed.
So I forked it. Today I'm releasing iliaal/nameparser, a maintained fork that fixes the credential handling, adds a confidence signal for the cases it genuinely can't decide, and targets PHP 8.3+. Most of the fix is unglamorous boundary work. One part of it rests on a single ide...
Update, June 21 2026. This post went up at 0.2.1. Since then 0.3.0 and 0.4.0 have shipped, and one claim below is already out of date: result streaming, which I describe as the next thing on the list, now exists. Set PDO::DUCKDB_ATTR_UNBUFFERED and a large SELECT streams row by row instead of buffering. Also new since publication: DuckDB config options on the DSN or through PDO::DUCKDB_ATTR_CONFIG, real per-column types from getColumnMeta(), an appender that accepts PHP arrays for nested columns like LIST, STRUCT, and MAP, GEOMETRY decoding, and duckdbTableNames() / duckdbLastProfile() for query introspection. The walkthrough below is otherwise current. Full list in the changelog.
DuckDB is the closest thing the analytics world has to SQLite. It runs in-process, needs no server, reads and writes a single file, and chews through columnar aggregate queries that would make a row-store sweat. PHP has shipped PDO_SQLite in core for twenty years. Until now it had no equivalent for Du...
Most libraries raise their minimum PHP version over time. Drop 8.1, require 8.2, then 8.3, because every release you can assume lets you delete a pile of compatibility shims. This round I went the other way. php_excel, fastchart, and fastjson now build on PHP 8.1, phpser dropped to 8.2, and all four had required 8.3 a release ago. php_clickhouse already runs on everything from 7.4 up, so it sat this one out.
The reason is mundane but worth stating: for a native extension, the minimum PHP version is a packaging decision, not a language-feature decision. None of these extensions needed an 8.3-only engine API. The floor was set high because that was the version I built and tested against first, and lowering it just meant wiring the older versions into CI and fixing whatever broke. A shop pinned to 8.1 on a long-term-support distro gets the same speedups as one on 8.5. That's the whole point of shipping a C extension instead of a Composer package.
Here is what else landed since the last set of releases.
php...
I generate a lot of UUIDs. Primary keys, cache keys, event IDs, request-trace IDs. Probably too many, if I'm honest about it. On a busy request path the same function gets called dozens of times before the response is even assembled, and across a fleet that adds up to a number of UUIDs per second I would rather not write down.
For years that cost was invisible to me, the way a single random_bytes() call is invisible until you make a few billion of them. Then it showed up in a profile, sitting higher than it had any right to, and I started paying attention to where the time actually went. It went to two places: pulling fresh entropy from the kernel once per UUID, and formatting 16 raw bytes into the 36-character canonical string. Both are cheap. Neither is free. Multiply by "too many" and you get a real slice of CPU spent doing nothing but minting identifiers.
So I wrote fast_uuid, a PHP extension that does UUID generation in pure C. This post is about why the two existing options each left a gap, what...
- «
- 1
- …
- »