Skip to main content
The PHP attribute that yells at you for ignoring a return value: #[\NoDiscard] in 8.5
php

The PHP attribute that yells at you for ignoring a return value: #[\NoDiscard] in 8.5

PHP 8.5's #[\NoDiscard] makes the engine warn you when you call a function and throw away its result — the classic immutable-API footgun ($url->withScheme('https') that quietly did nothing). Why it's the rare attribute that improves your code by nagging you, where it fits in Drupal (Url, cache metadata, fluent withX() setters), the (void)-cast escape hatch, and why it only helps if your CI fails on warnings.

2026-09-07 / 03 min
Craft is becoming a Laravel app — a Drupal dev watches a CMS change engines mid-flight
craft cms

Craft is becoming a Laravel app — a Drupal dev watches a CMS change engines mid-flight

Craft 6 (alpha since May 2026) is a ground-up port from Yii onto Laravel, and can embed in an existing Laravel app. I lived Drupal's Symfony 'get off the island' in Drupal 8, so I have a haunted perspective: the framework swap is the right long-term bet and a short-term ecosystem earthquake. The questions that decide it aren't about Laravel — they're about the plugins.

2026-09-02 / 04 min
Async PHP grew up in 2026 — does a Drupal developer need to care?
php

Async PHP grew up in 2026 — does a Drupal developer need to care?

Fibers are mature, AMPHP and ReactPHP share one event loop via Revolt, and the concurrency jokes are finally wrong. So how much must a Drupal dev learn? Almost none directly — Drupal's synchronous DB blocks the whole model. The one real win (parallel outbound HTTP in a queue worker) Guzzle already gives you, no Fibers required.

2026-08-24 / 04 min
Stop new \DateTime(): treat time as a dependency you inject
drupal

Stop new \DateTime(): treat time as a dependency you inject

Every time() and new \DateTime() buried in your logic is a hidden dependency on the one thing you can't pause — and it's why your time-sensitive tests are flaky. Inject Drupal's TimeInterface (already there) or Symfony's Clock (freeze and advance instantly in tests). Where Drupal's built-in falls short, and the discipline that makes 'what happens at midnight?' a test you can actually run.

2026-08-17 / 04 min
The phar wrapper that wouldn't die: parse_url() ate PhpSpreadsheet's patch
php

The phar wrapper that wouldn't die: parse_url() ate PhpSpreadsheet's patch

CVE-2026-45034 (CVSS 9.2) bypasses an earlier PhpSpreadsheet fix because one extra slash makes parse_url() return false, walking past the guard and re-enabling phar deserialization. The real villain isn't the library — it's using parse_url() as a security boundary, a recurring PHP footgun the advisory itself warns against.

2026-08-13 / 04 min
One emoji, quadratic time: the Markdown bug that DoSes your site without a payload
php

One emoji, quadratic time: the Markdown bug that DoSes your site without a payload

CVE-2026-71488 in league/commonmark — the Markdown parser behind Laravel, Drupal, Statamic and more — turns a single non-ASCII character into O(n²) parsing. No RCE, no leak, just one long line with an emoji pinning a CPU. Why algorithmic-complexity DoS is the vuln class nobody threat-models, and why you should benchmark parsers with adversarial input.

2026-08-13 / 04 min
Why turning on JIT won't speed up your Drupal site (and the math that proves it)
php

Why turning on JIT won't speed up your Drupal site (and the math that proves it)

PHP's own JIT authors admitted it barely helps real apps like WordPress — ~3.5%. Here's why: a Drupal page is I/O-bound, and Amdahl's law caps what JIT can ever do to ~11% even if it made the CPU work infinitely fast. What actually speeds a site up instead (OPcache, preloading, a real cache backend), and the CPU-bound cases where JIT genuinely earns its keep.

2026-08-03 / 04 min
hook_ is dying (slowly) and I started rewriting my .module files anyway
drupal

hook_ is dying (slowly) and I started rewriting my .module files anyway

Attribute hooks have been stable since Drupal 11.1, so I converted this blog's SEO module from a procedural .module file to a #[Hook] class. The catch nobody mentions: procedural hooks aren't actually deprecated yet and won't be removed before Drupal 13, around 2028. What's worth doing now, what isn't, and the LegacyHook trap that quietly fires your hook twice.

2026-07-24 / 05 min
FrankenPHP + Drupal: Great Server, but Skip Worker Mode
php

FrankenPHP + Drupal: Great Server, but Skip Worker Mode

Field notes on running Drupal 10/11 on FrankenPHP in classic mode today, why worker mode is still off-limits for Drupal, and how it sits behind my Traefik/Coolify setup.

2026-07-11 / 04 min
Subscribe to PHP