Making ExcelBook::save() atomic is easy to describe. Write the workbook to a temporary file, then rename it into place. A save that dies halfway leaves the original file untouched. The obvious way to build that staged file is to ask LibXL for the finished archive as one buffer and write the buffer out. It works. It also costs 67.7 MB of peak RSS on a 3.3 MB workbook, and the PHP-side copy counts…
Parse Malcolm X with almost any name splitter and you get a suffix. X looks like a roman numeral, roman numerals are suffixes ( John III , Henry VIII ), so X becomes the suffix and the surname disappears. That's the kind of bug you only find once you already have a working parser, because it isn't a missing rule. It's two correct rules wanting the same token. Last month I wrote about the casing…
ExcelBook::save() to a file:// path used to truncate your existing file before it finished writing the new one. If the write was short or got interrupted, you were left with neither the old file nor a complete new one. php_excel 2.4.0 fixes that: the write goes to a temp file and renames into place, so a failed save leaves your original intact. That fix doesn't make a good changelog headline. It's…
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…
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…
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…
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…
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…
I've reached for igbinary on nearly every PHP project I've shipped in the last decade. It's smaller and faster than PHP's native serialize() , it's stable, and it has been the obvious default for so long that reaching for it stopped being a decision. So phpser started as curiosity, not a complaint. igbinary is good. Could a serializer built specifically for cache workloads do better? I wanted two…
Couple of weeks ago I shipped fastchart 0.2.0 and wrote it up here . One extension, 19 chart types, server-side rendering through ext/gd . The idea was right, but execution not quite there. After the launch I spent a few days actually looking at the output side by side with what plutovg can do on the same primitives. The libgd-rendered charts were fine for what libgd is, which is a 1990s 2D…
(new FastChart\StockChart()) ->setSize(1200, 600) ->setTitle('AAPL last 90 days') ->setTheme(FastChart\Chart::THEME_DARK) ->setOhlcv($ohlcvRows) ->setMovingAverages([20, 50, 200]) ->setVolumePane(true) ->setCandleStyle(FastChart\Chart::STYLE_HOLLOW) ->renderToFile('/tmp/aapl.png'); That's a server-side OHLCV candlestick chart with three moving averages, a volume pane, and a hollow candle style.…
The launch post for php_clickhouse 0.6.0 covered the framing: native binary protocol, soft fork of the stalled SeasClick, modern ClickHouse types, 30-40% faster than HTTP at high throughput. That post landed April 25, 2026. Today (May 1, 2026) the current tag is 0.8.1, and I'm calling the extension stable. The six days in between were a focused quality cycle, not a feature sprint. Three buckets:…
Anyone who's tried AI-assisted trading research has hit the same wall. The agent has no native access to your charts. You end up copy-pasting symbols, indicator values, screenshots, and Pine Script back and forth between TradingView and Claude or Cursor. The tools that try to fix this fall into two camps: route market data through a third-party API (added latency, added cost, their interpretation…
In 2005 I wrote a PHP binding for libstatgrab and pushed it to PECL. The extension took CPU, memory, disk I/O, network, process, and user statistics from a cross-platform C library and exposed them to PHP as plain functions. I moved on to other things, libstatgrab kept evolving, PHP went through three major versions, and the binding sat untouched. By 2020 you could not build it against PHP 7…
I run a few projects that move a lot of data through ClickHouse. Telemetry pipelines, ad-hoc analytics, log ingest. The two pure-PHP options today are smi2/phpClickHouse (HTTP) and lizhichao/one-ck (binary TCP). HTTP gets you a 30-40% slowdown on hot loops; one-ck shipped its last release in 2020 and isn't keeping up with the column types ClickHouse keeps adding. The reference native binary client…
Several of my projects do heavy markdown parsing. Comment rendering, documentation pipelines, content management. The volume keeps growing, and I've been hitting the point where pure-PHP parsers (Parsedown, league/commonmark, cebe/markdown, michelf) just can't keep up. They're solid libraries, but parsing thousands of documents per request or chewing through 200 KB files in interpreted PHP is slow…
PHP processes more Excel files than any language except maybe Python. Payroll exports, inventory imports, financial reports, data migrations. If your business runs on spreadsheets (and it does), your PHP app touches them constantly. The standard approach is PhpSpreadsheet: a pure-PHP library that parses XML, builds an in-memory object graph, and promptly devours your server's RAM. It works fine…
Every AI coding agent ships with the same problem: it knows syntax but not discipline. It can write a React component or debug a segfault, but it won't ask "did I verify this actually works?" before declaring victory. It won't split a 400-line diff into reviewable chunks. It won't check if the fix it's about to apply matches the root cause it claims to have found. I've spent the past six months…
In the PHP community, "persistent connections" are often treated like a dark art; powerful, but prone to blowing up in your face. We've been told they cause "Too many connections" errors, stale data, and dangling transactions. The truth? In high-traffic environments, persistent connections are your best friend. If you understand how PHP internals and networking flows actually work, they are the…