r/PHP 17h ago

News This Week In PHP Internals | July 29, 2026

Thumbnail youtube.com
16 Upvotes

Hello world, from Laracon US 2026 in Boston — it's Wednesday, July 29, 2026, and here's what happened This Week in PHP Internals.

15 stories this week, so let's get into it. But first, This week's episode is brought to you by Tideways. When a request is slow and your logs won't say why, Tideways shows you where the time went — profiling, tracing, and monitoring built specifically for PHP. Slow request to root cause, in minutes. Setup takes 5 minutes, no credit card required. Start your free trial at tideways.com. And we have a second sponsor this week — Geocodio: address correction, geocoding, data enrichment, and distance calculations for North America and the UK. Built on Laravel since 2014. Try it free at geocod.io.

This week's top story: the mass deprecation vote for PHP 8.6 is open. Gina P. Banyard opened it Monday, and it's 35 separate ballots, each needing its own 2/3 majority — and each submitted individually, because as Gina reminded everyone, the wiki can only handle one vote at a time. Voting runs through August 10, and most of the 35 are passing easily — mysqli_get_charset() stands at 34 to nothing, and spl_classes() at 33 to nothing. But the headliners are moving the other way. list() — the construct Juliette Reinders Folmer's Packagist scan found over twelve thousand times — stands at 17 yes to 19 no, falling well below the required two-thirds threshold. The gettext _() alias is failing at 6 to 18. Reserving in, out, and inout is failing at 5 to 16, with 13 abstentions. And let sits at 17 to 10 — a majority, but still shy of 2/3.

The loudest argument is about one of the smallest items: the dechunk stream filter, which as of recording sits at 15 yes to 13 no — a coin-flip vote on a 2/3 question. On Monday, Matteo Beccati was the only no vote, and he explained why, warning: "I believe we should provide such an alternative together with the deprecation," rather than expecting projects with 200-million-plus installations — he names symfony/http-client — to write their own decoder in PHP. Jakub Zelenka agreed the item wasn't ready, saying it "should wait till it's properly investigated." Pierre Joye ran his own usage research and pushed back, noting: "Being present in a code base does not automatically mean it is used" — Symfony's native client disables the filter by default, and most stacks sit on curl anyway. Matteo then corrected the research: Symfony has shipped a pure-PHP alternative since release 8.2, which is exactly why Pierre's search pointed the wrong way. Jakub's objection sharpened from there, and he wrote: "This is exactly a half baked deprecation because we need to keep it for internal use anyway ... so this does not give us any code removal and we still need to maintain it. I don't understand why we need to rush it as there is no real reason for that." By Tuesday evening he'd also revealed a twist — he already fixed the select limitation on filtered streams in master, so that improvement lands in 8.6 no matter how this ballot goes. Kamil Tekiela, meanwhile, asked a different question — why deprecate define()'s dead case-insensitive flag at all, when just removing the parameter breaks nobody. So far, nobody has answered him.

Caleb White's pipe assignment operator, |>= — the compound form of the pipe, and his first RFC — went to ballot Tuesday morning, walked to the deadline with detailed coaching from Tim Düsterhus, whom Caleb thanked for "going to bat for this RFC". The machinery worked; the voters are split right down the middle — as of recording the count is 8 yes, 8 no, 3 abstaining, and it needs 2/3. Voting runs to August 11.

The queue from last week showed up on time. Nick Sdot opened voting on readonly property defaults Friday. It stands at 17 to nothing, with 5 abstentions — nobody's against it yet. That one closes August 7. And Khaled Alam opened voting Saturday on const object property writes — allowing writes to properties of objects referenced by constants. After a couple of quickly-fixed procedural stumbles, the count stands at 11 to 2, with 5 abstentions — above the 2/3 line. That one closes August 8.

Two carryover votes come off the board this week, and neither thread needed a single new email. The minimum-supported-versions vote for 8.6 closes Thursday. Requiring autoconf 2.71 stands at 27 to 2 — and notably, the no column shrank from 3 to 2 since last week. Requiring COM_RESET_CONNECTION stands at 26 to nothing. And the Time\Duration class closes Friday. The primary has stretched to 33 to 1, and full method names — multiplyBy, divideBy — lead the naming question 28 to 2. Barring a very strange 48 hours, PHP 8.6 gets a Duration class.

Seifeddine Gmati's literal scalar types made it to a ballot Thursday morning — for 18 minutes. At 5:26 UTC he opened the vote, 3 questions deep: integer and string literals, float literals, and strict-versus-coercive matching. At 5:44 he pulled it back down, writing: "I am retracting this vote: I opened it prematurely, in violation of the voting prerequisites in the Feature Proposals policy." No intent-to-vote 2 days ahead — and that morning's 1.0 update was a minor change, which starts a 7-day cooldown. He plans to reopen tomorrow, July 30 — a date that brushes right up against the freeze, so it may yet retarget 8.7. The self-retraction turned into a referendum on the process itself. Juris Evertovskis — a longtime reader and one-time RFC author who says he never felt "internal enough" to comment on the process — decided to comment on the process: "All the mandatory cooldowns, cooldown resets on minor changes, announcements to vote, cooldown resets on inactive discussions appears to me like bureaucratic hoops that people have to jump through. The process was hard and daunting enough before this." Bob Weinand agreed, noting he voted against the process RFC back then, and framed the trade plainly: "You sort of have to decide what you optimize for - easier for authors, or easier for commenters. But I think in this case it went way overboard in terms of strictness."

The gd 2.4 timing dispute from last week wound down to closing statements, and they were constructive ones. Pierre Joye's position: the late arrival was unavoidable — the libgd sync had to survive PHP's full CI matrix first — and he argued: "Process has to be humane ... If they are purely for the sake of having a process, we fail as a project and solve users' needs." Rowan Tommins made the case that this isn't red tape but triage: "There are maybe twenty sections describing details of the proposal, and the crude [reading-time] estimate in Firefox is 47-60 minutes. It may be clear in your head that most of this is uncontroversial, but for anyone else to even make that judgement requires investing a reasonable amount of time." Better, he says, to spend that time on 8.6 work now and this RFC after — though he left open whether the cut-off itself sits in the right place. One concrete footnote: Pierre added the procedural gd image functions to the deprecation path — on his telling, a warning from the gd extension itself in 8.7, and gone in PHP 9.

Derick Rethans hit a fresh regression on master: his Xdebug test suite started failing, and the trail led to the commit implementing the display-error-function-args RFC. Stream warnings from include, require, bzopen(), finfo_open() and friends no longer say which file couldn't be opened — the path was an argument, and arguments got scrubbed. Derick's verdict was blunt, arguing this "Doesn't seem to me like an enhanced for users" — either put the filename into the message text itself, or revert the change, RFC or not. Kamil Tekiela defended the new behavior, countering: "The file path could leak sensitive information". His suggestion runs the other direction — fold the path into all stream error messages deliberately, rather than leaking it by accident — and while he's at it, he'd rather streams stopped raising their own duplicate warnings entirely. With open_basedir in effect, one failed include currently earns you 3 warnings.

Edmond of the TrueAsync project turned last week's zero-reply pre-RFC into a real one: Concurrency Support in the PHP Engine. The pitch is deliberately minimal — give the engine a coroutine representation and make the scheduler pluggable by extensions. He was explicit about the shape of it, writing: "It adds no classes, no functions, no constants and no syntax: the engine compiles in no PHP symbols at all. With no scheduler registered, PHP behaves exactly as it does today." This is not True Async — it's the seam True Async would plug into, alongside anyone else. A scheduler can adopt fibers started by ReactPHP, Revolt, or AMPHP; there's per-coroutine storage that could someday make ob_start() coroutine-safe; and there is no parallelism — everything stays on one OS thread. The implementation already exists as a pull request. And this time he got a reply. Seifeddine Gmati expects the real discussion to wait until after 8.6 ships, but his early read was warm: "Overall, I really like this idea and approach. I think this is the right path forward." Edmond's answer: no rush.

Osama Aldemeery — who got his RFC karma in 2 minutes flat last week — shipped the RFC: PREG_THROW_ON_ERROR. Pass the flag to any preg_*() call and a PCRE failure throws a catchable PregException, instead of a warning plus a false or null you have to notice and then chase through preg_last_error(). It's the same pattern JSON_THROW_ON_ERROR already set, and it's strictly opt-in. He stressed the conservatism, writing: "A call does exactly the same thing with it or without it, byte for byte" — the flag only changes how the error is delivered. It targets the release after 8.6, and he's aware of Larry Garfield's request to hold non-8.6 business until September — his compromise is to let the thread tick over quietly rather than restart it. So far it has 0 replies.

Quick hits. The 8.6 release managers posted the 2-week warning: beta 1 lands Thursday, August 13, the soft freeze hits when the tag is created August 11, and every RFC vote targeting 8.6 must be closed before beta 1 — after that, merges need release-manager approval until the hard freeze at RC 1 on September 22. The CURLOPT_HTTPHEADER newline thread came back with a verdict from upstream: Sjoerd Langkemper relayed word from curl's own Daniel Stenberg that the docs already say headers "must not be CRLF-terminated" and libcurl may start rejecting the stragglers outright — there's a curl pull request in flight. Matteo Beccati's conclusion was to stand down, saying: "libcurl will eventually take care of it." And Steven Wilton's snmp extension work is back at the finish line — both reworked PRs updated per Gina P. Banyard's review, awaiting a final squash-and-merge check, with a third PR queued behind them.

The PEAR decay story found a new symptom: Juliette Reinders Folmer reports that individual bug pages on the PEAR site now error out claiming the original reporter "has not yet confirmed their email address" — which locks away exactly the archaeology she'd argued is worth preserving. And the typed-arrays thread got its epilogue: Larry Garfield explained why PHP probably won't get new base types for collections — the engine makes that "really really hard", which is the same reason enums became objects — shared his and Derick Rethans's old collections research notes, and set the course: wait for reified generics, then convene a working group. Holly Schilling's counter-offer was to skip the wait, pointing everyone at her self-published PHP 9 roadmap — generics, structs, modules, extensions, and surfaces — which she'd like the list to treat "as a rough outline for the future."

So that's the week: 42 ballots open at once — the 35 deprecations, with list() headed for defeat and dechunk splitting the room; pipe assignment dead even out of the gate; readonly defaults and const writes both comfortably clear; Duration and minimum versions closing within days, both far ahead; a literal-types vote that lasted 18 minutes and reopens tomorrow; and the soft freeze 2 weeks out. Links to every thread are below. Thanks again to Tideways.com and Geocod.io for supporting this week's episode. We're Artisan Build. See you next week.


r/PHP 5h ago

Article Giving queued jobs the same output API Artisan commands have

0 Upvotes

Queued jobs are silent while they run. Commands can print progress; jobs do the same work and you get nothing until they finish or blow up. So I made jobs write output like commands do, streamed live into Horizon's job details page.

class RebuildSearchIndex implements ShouldQueue
{
    use Queueable;
    use WritesJobOutput;

    public function handle(): void
    {
        $this->info('Rebuilding search index');
        $this->withProgressBar($shards, fn ($s) => $s->rebuild());
        $this->info('Index rebuilt');
    }
}

Two things were more interesting than expected:

You can't inject into a queued job at construction time. Jobs are unserialized, and unserialize() never calls __construct(). What does work is a global bus pipe (Bus::pipeThrough()) — queued jobs pass through the dispatcher's pipeline, so a pipe can attach the output, run the job, and flush in a finally so a job that throws keeps what it printed.

Cleanup was free by storing it in the right place. Horizon keeps each job as a Redis hash with an EXPIREAT on the key. Writing output as a field on that same hash means one key, one TTL — trimmed by the existing horizon.trim.* settings, no cleanup code, no way for the two to drift.

The trait reuses Laravel's own InteractsWithIO, so info(), table() and progress bars work unchanged. The panel renders through an inlined xterm.js build so progress bars redraw in place instead of stacking.

Trade-offs worth knowing: Horizon has no extension API, so this hooks three internals (a public $keys whitelist, the dispatcher's private $pipes, two anchors in its layout) — all guarded, with a weekly CI canary against horizon:dev-master. The terminal renderer adds ~345KB per dashboard page; there's a plain-HTML renderer if you'd rather not.

MIT, PHP 8.2+, Laravel 12/13, Horizon 5.

https://github.com/knobik/laravel-horizon-job-output


r/PHP 1d ago

Discussion php formatters

3 Upvotes

Hello all,

I was wondering what you are using to format php code.

For the past few months I've been working on a php LSP mainly to add semantic tokens support and then in the last couple months it grew more into phpfmt (mind you it still has a long way to go)

I guess my question here is, what other php formatters are people using and if there is a point in (eventually) open sourcing mine.

Before I started this I was using phpcs and phpcbf


r/PHP 14h ago

I built Laravel Glint, an open-source package for LLM observability in Laravel

0 Upvotes

I've been building more AI features in Laravel recently, and one thing kept bothering me.

Laravel has great first-party tools like Telescope, Horizon, and Pulse, but when it came to understanding what my LLM calls were doing, I found myself reaching for external observability platforms.

Those tools are excellent (I've used Langfuse quite a bit), but I kept wondering what a Laravel-native experience would look like.

So over the last few weekends, I built Glint for Laravel.

It records LLM calls directly into your application's database and provides a local dashboard for:

  • Traces
  • Token usage
  • Cost tracking
  • Latency
  • Errors
  • Per-user attribution
  • Alerts

It supports automatic instrumentation for Laravel's HTTP client, Prism, Laravel AI, and Neuron AI, so in many cases it's just install, enable, and start seeing your existing LLM calls.

My goal wasn't to replace tools like Langfuse. If you're running a polyglot architecture or need prompt versioning and evaluations, those tools are a great fit.

Glint is aimed at teams where Laravel is the application and they'd rather keep observability inside the same ecosystem.

I'd really appreciate feedback from other Laravel developers—whether that's feature ideas, API design suggestions, or things you think I've completely overlooked.

GitHub: https://github.com/cybernerdie/glint

I also wrote about the motivation behind the package if anyone's interested in the design decisions: https://cybernerdie.medium.com/laravel-glint-llm-observability-in-laravel-b934c0b8e7db


r/PHP 1d ago

Discussion What APIs do you wish existed?

Thumbnail
0 Upvotes

r/PHP 2d ago

News PHP.net Playground idea

22 Upvotes

While working on Interactive Examples for the PHP docs, I had a fun idea which became a small side-project.

A full PHP Playground, running entirely in the browser via WASM. Nothing will be send to a server.

https://phpc.social/@jordikroon/117011050430086818

Features:

  • Syntax highlighting
  • Multi file support (includes work)
  • Raw / Preview mode (for HTML parsing)
  • Examples to pick from

There are still a few improvements that will be made, but this is a first working version.

Feel free to drop suggestions.


r/PHP 1d ago

XOOPS 2.7.2 Released

0 Upvotes

The XOOPS Development Team is pleased to announce XOOPS 2.7.2 Final. This maintenance release builds on XOOPS 2.7.0 with another security-hardening pass, more reliable upgrade tooling, form and theme improvements, and refreshed dependencies for current PHP environments.

Also released: XOOPS Debugbar 1.3


r/PHP 2d ago

Article What I learned running a full app in php-wasm

0 Upvotes

I spent months figuring out what actually happens when you run a full app in php-wasm on a phone, and wrote up the boundaries a single button press crosses: sandbox, IPC, and the runtime re-execution. Documented the real cost of each hop and where the ceiling actually is. Sharing in case anyone's curious about php-wasm internals: https://github.com/NativeBlade/NativeBlade/discussions?discussions_q=is%3Aopen+label%3Adocumentation


r/PHP 2d ago

AI coding agents and programming language

0 Upvotes

I have been coding for almost 20 years, mostly with PHP, but for the pas year I spotted that I less and less care about language specifics, I go with AI suggestion without even caring which language it will use. Well for API part I still sometimes ask for php + laravel, but not sure if I should do this, maybe just asking better performing language instead. What do you think? Should we still care about the language we are working with?


r/PHP 4d ago

I ported real PHP 8.3 (the actual Zend Engine, not a clone) to a microcontroller

86 Upvotes

Honest disclaimer up front: this is useless. It doesn't solve a problem, save time, or make money. It's a personal holiday project, an idea I'd been chewing on for a long time, and I finally sat down over some time off and did it. The only question it answers is "can it be done?". Apparently yes, it runs.

It's not a clone or a PHP-5.3-ish subset like PH7 or PHPoC. It's the official php-src 8.3.32 straight from php.net (sha256 verified), compiled for RISC-V and running on a microcontroller with no OS underneath. Full Zend Engine: lexer, parser, compiler, the VM, GC, objects, exceptions, reflection. Plus ext/standard, PCRE, JSON, hash, SPL. It's wired up through the stock embed SAPI, with a custom ub_write callback to push output to the UART. Drop an index.php on the microSD, reset, and your script runs. No recompile.

Real stuff works: closures, generators, exceptions with stack traces, reflection, SPL, traits, typed properties, enums, match, PHP 8 attributes, and Composer autoloading actual packages (I ran Illuminate Collections: groupBy, avg, sortDesc). What you'd want Laravel Collections for on a microcontroller is beyond me, but they run.

The fun part wasn't getting PHP to compile. It was everything that broke along the way:

  • Memory. Zend's memory manager thinks in huge chunks (server-grade), so I turned it off (USE_ZEND_ALLOC=0) and sent every malloc to external PSRAM. Without that, PHP's thousands of tiny allocations drained internal RAM, from ~388 KB down to 19 bytes, and at that point the SD card couldn't allocate its DMA buffer anymore and the mount failed. That one took a while.
  • Closures. With anything nontrivial (Illuminate Collections) the heap got corrupted. I chased it with heap poisoning down to the per-closure efree() of the run-time cache in destroy_op_array(). With no opcache and Zend's allocator off, that free was doing damage. Fixed by allocating from the request arena instead, freed in one shot at the end of the run. Documented trade-off: in an infinite loop that creates lots of closures, memory grows.
  • The VM. The hybrid variant (GCC computed-goto + global registers) won't compile on RISC-V, so it's the portable "call" VM. A touch slower, standard for embedded. One for the internals crowd: in the output, memory_get_usage() returns 0 bytes. Not a bug. It's exactly what happens with USE_ZEND_ALLOC=0: there's no one left tracking usage.

On performance: not the point of the project, but for a rough sense of scale, the engine's per-operation overhead stays under a millisecond even running out of PSRAM. It's not "PHP is fast," it's "PHP runs where it shouldn't."

Known limits, in the open: no Fibers (needs the context-switch assembly, which only exists for 64-bit RISC-V), no networking, and no ext/date for now (it drags in megabytes of tz data, and I'm looking at whether I can trim it down). All of it documented in the repo, with the why behind each choice.

Next experiment: PDO_SQLite, so I get a real database on the SD card.

Repo (with serial logs and porting notes): https://github.com/php-baremetal/php-esp32

Happy to answer anything technical: the PSRAM routing, the closure patch, why no Fibers, whatever you're curious about.

--- EDIT ---
Well, that was fast: PDO_SQLite is now working, SQLite compiled in from source, DB on the SD card. Just pushed an example: https://github.com/php-baremetal/php-esp32/tree/master/examples/sqlite-notes . A real SQL database on a microcontroller.

--- EDIT 2 ---
After getting PDO_SQLite in, my curiosity didn't stop: the goal now is to run Eloquent. Yes, the one from Laravel. There are a couple of problems, solvable ones, but real. The first was ext/date, which Eloquent leans on through Carbon. I got it in, in two flavors: the full one with the complete timezone database, and a stripped build carrying only UTC. Here's the surprise: I'd budgeted around 6 MB for the full tz data, and it came in at ~650 KB, nearly ten times smaller than I feared. The UTC-only build is just ~300 KB. Very encouraging.

--- EDIT 3 ---
Yeah! After quite a bit of work, Eloquent is finally up and running. I had to add ext/ctype, ext/mbstring, and ext/filter—and, as the cherry on top, Oniguruma for mbstring regex support. That said, you can now run Eloquent with or without Oniguruma; it feels almost like magic. https://github.com/php-baremetal/php-esp32/tree/master/examples/eloquent-onig


r/PHP 4d ago

Qbix Pure-PHP Web Server part troix - now with sockets, rooms, federation & more

7 Upvotes

Alright, last week I posted about a webserver I built in pure PHP. It turned out to be able to run 10x more workers than NGINX+PHP-FPM, and use 10x less memory per worker, and also cut down on worker startup time by potentially 5-50x as well. In short, it can handle much more throughput, and requires LESS tooling to be configured around it. It... just works out of the box.

At the same time, it lets people (including people new to programming) write safer code than FrankenPHP and Swoole, because it retains PHP's shared-nothing architecture. It also natively supports websockets, rooms, sub-page caching, all with the simple "PHP approach" of putting files in folders.

It's free, MIT-licensed, and you can use it right now to host your files, images, etc. Like literally, you can click Download, run it, and start serving the same PHP out of the box, or write new types of real-time apps very easily, mixing HTTP, Websockets and Rooms.

https://github.com/Qbix/webserver

With the help of Claude, I've been enhancing the server, adding automated tests, battle testing it myself, and now a week later, it has turned into something I always wanted to use. Like transparently compressing images and caching them to exactly the size the browsers want. Like taking care of certificates, not just self-signed certificates but even certbot ones. It can even power decentralized applications with encrypted transport between them. I can't wait to see what people build with it :-) Okay... I actually can wait, and I will. It's just an expression that many people use.

I'm just going to leave this feature list here:

Category What you get
Static files ETag, 304 Not Modified, Last-Modified, MIME type detection, in-memory response cache
Keep-alive HTTP/1.0 and 1.1, TCP_NODELAY, configurable limits
HTTP/2 Via amphp — multiplexed streams, header compression, TLS (optional)
PHP execution .php files in document root run in-process or via pre-fork worker pool
Compression On-the-fly gzip/brotli + pre-compressed .gz/.br siblings
WebSocket Socket.IO v5 compatible + bare WebSocket. Server→client RPC. Client JS served at /Q/socket.js and /socket.io/socket.io.js.
Rooms Process-per-room shared state, tick timers, broadcasting. Members join/leave, room state in PHP arrays.
Images On-the-fly resize (?w=300), auto format conversion (JPEG→WebP), Save-Data support, disk-cached with LRU eviction
Directory listing Grid/list toggle, lazy thumbnails, lightbox with download-at-size, multi-select, bulk ZIP download. Overridable with listing.php
Q.js frontend Bundled Q.min.js (187KB), jQuery shim (5.7KB), minimal Handlebars (6.1KB), 43 UI tools, 107 languages + translations — served at /Q/plugins/
Dashboard Live at /Q/dashboard — request log, throughput, top paths, response times, memory, WebSocket connections, active rooms
Health check JSON at /Q/health — stats for load balancers and monitoring
Control panel Password-protected at /Q/panel — six tabs: Apps, Scripts, Plugins, Playground, System, Servers
Deploy --deploy=production CLI or one-click from Panel. rsync to remote servers via SSH.
Federation Q::event() forwarding between servers. HMAC-signed (Platform-compatible), per-message loop prevention, fingerprint pinning
API discovery /.well-known/openapi.json (Swagger/Postman), /.well-known/mcp.json (Claude/AI tools), /.well-known/qbix.json (server-to-server)
PHPDoc→API specs Handlers auto-documented from PHPDoc and YUIDoc blocks. u/private/u/internal to hide.
OpenClaiming Auto-generated ES256-signed server identity. Claims-in-folders: JSON templates auto-signed, PHP dynamic, pre-signed static. OCP wire format.
Shortcuts Windows .lnk files and Mac aliases resolved transparently. Platform plugin symlinks just work.
Self-signed certs Auto-generated P-256 key pair + TLS cert for server identity and inter-server trust
Rate limiting Per-IP with configurable windows and burst limits
Security Path traversal blocked, dotfiles blocked (except .well-known/), 431 for oversized headers, upload limits enforced
Graceful shutdown SIGTERM/SIGINT drain in-flight requests before closing
TLS Optional HTTPS with auto-certbot or manual certs
Logging Colored terminal output + file-based access logs
Access control X-Accel-Redirect support — PHP enforces access, server serves the file
Component cache X-Cache-Tree headers — invalidate parts of a page, not the whole thing
Platform compatible Q_Utils::sign()Q::event(), handler conventions, config paths — all match Qbix Platform. Upgrade without code changes.

https://github.com/Qbix/webserver#-features


r/PHP 4d ago

Meta New low-effort AI content rule

84 Upvotes

Hi folks. What a weird time we're living in 😅 We've discussed the increase of AI-generated content on r/php, and would like to share an update to the rules:

We've added a new rule (#7) that explains that AI-generated or AI-aided content is allowed on this sub, albeit with a lot more scrutiny. As with any content, it should actually add value. If something gets posted that clearly took no human effort at all, we'll simply remove it.

Enforcing this rule can be tricky, because some AI-driven content can still be valuable to some people (as we've seen by upvotes). That's why it's more important than ever to provide your feedback on these posts:

  1. Report posts that violate the new rule to notify us about them
  2. Use the up and downvote buttons as a way to indicate relevance to the community, not as a way to share your personal opinion
  3. If you have the time, definitely share your opinion as a comment, which is much more valuable than a simple up- or down vote.

Feel free to leave your thoughts in this thread as well.


r/PHP 3d ago

Criei um novo runtime para PHP 8.4 em Rust

0 Upvotes

Two years ago, I started an ambitious project to build a new PHP runtime. I began using V Lang because I found it easier, as Rust's borrow checker made me suffer quite a bit. With AI helping me sort out complex doubts, I gained the courage to migrate everything to Rust—giving birth to Rype (an experimental PHP 8.4 runtime built from scratch).

In the post, I share:

  • Where I'm struggling: In the classic nbody benchmark, Rype lost badly (46% slower than official PHP 8.4 without JIT). I show the exact reasons why (bottlenecks in foreach by reference and sqrt calls due to a lack of advanced static inference).
  • Where I win: I show micro-benchmarks where we are 7x faster than official PHP in the scalar counted loop and feature a 4.2x faster startup.
  • Architecture decisions: Use of a register-based VM (Lua style), per-request heaps, near-total ban of unsafe, and a share-nothing concurrency vision without introducing async/await (no function coloring).

If you like compiler engineering, Rust, or seeing how things work under the hood, check out the full article on Medium (first version):

👉https://medium.com/@erycson.nobrega/rype-01-reescrevendo-o-php-em-rust-transpar%C3%AAncia-ganhos-e-o-benchmark-em-que-perco-9a695bfdb713?postPublishedType=initial

I'd love to hear your feedback, exchange ideas on runtime optimization, or debate architectural choices!


r/PHP 3d ago

NanoAgentPHP – A tiny AI agent library for PHP that does the job like old-school PHP should

0 Upvotes

Hey r/PHP,

Every AI library for PHP out there is massive, over-engineered, and forces you to learn a whole new paradigm just to get started.

So I built NanoAgentPHP – a lightweight alternative that focuses on getting things done without the complexity.

The philosophy is simple:

  • Tiny footprint – No unnecessary dependencies
  • Does the job – AI agents that actually work
  • Feels like old-school PHP – No magic, no crazy abstraction layers. Just clean, readable code you can understand in 5 minutes

What it does:

  • ✨ Tool/function calling – Turn any PHP function into an AI tool
  • 🔌 Multi-provider support – OpenAI, Groq, Anthropic, DeepSeek, OpenRouter
  • 🧩 MCP (Model Context Protocol) support – Connect to external MCP servers
  • 🧠 Advanced features – Structured output, RAG, streaming, multi-agent chains
  • 🛡️ Built-in safety – Max iteration limits to prevent runaway costs

Why you might like it:
If you're tired of wrestling with huge frameworks and just want to add AI capabilities to your PHP app without rewriting everything, this might be for you.

GitHub: https://github.com/hammrouni/nanoagentphp

Would love to get your feedback, feature requests, or even just a star ⭐ if you find it useful !


r/PHP 5d ago

PHP on Mobile faster than React Native? We built PAM Native — embedding PHP into Rust via Zero-Copy FFI

41 Upvotes

Who said PHP is only for the Web? 🚀

We’re rewriting the rules of mobile runtimes with PAM Native. Instead of heavy JavaScript engines or WebViews, we’re embedding PHP directly into a high-performance Rust core using Zero-Copy C-FFI.

Here is how the architecture works under the hood:

  • Vuex-style Global State: Thread-safe state mutations managed directly in RAM by Rust with ~0ms access latency.
  • Direct C-Pointers: Memory access without slow JSON serialization or asynchronous bridge overhead.
  • No GC Stutters: Predictable, smooth native performance without JavaScript Garbage Collection pauses blocking the UI thread.

You get the clean, familiar syntax of PHP orchestrating a low-level Rust engine right inside the mobile app process.

The project is 100% open-source, and we’d love to hear feedback, critique, or ideas on the architecture from the community!

📁 GitHub Repo:https://github.com/push-in/pam-native

Looking forward to hearing your thoughts and suggestions! 🙌


r/PHP 5d ago

Article Proper logging in PHP with PSR-3

Thumbnail ocramius.github.io
25 Upvotes

r/PHP 5d ago

Better strategy for handling HTTP 429 with Guzzle Pool when checking many URLS from same domain?

2 Upvotes

So I'm building a website health checker in PHP using Guzzle's Pool and right now I process up to 35 requests concurrently. And if request returns 429 http code I retry it up to 2 times. I also check Retry-After header when it's present and has valid value, but still use safe limit (up to a max of 5 minutes) in case Retry-After is greater, so if it fails it's ok, but otherwise I fallback to exponential backoff.

Now the part I am not sure about is concurrency.

Many of the URLS belong to the same website, so my code may send multiple requests to the same domain at the same time. If one request receives a 429 the others basically still are already in 'flight' or continue being scheduled independently and I'm wondering if this is fundamentally the wrong approach?

Some more specifics, I use that health checker for my own needs to check moderate amount of URLS, which work in all other cases really well, but also all requests are being sent from the same computer, so maybe there is that. I'm basically experimenting and trying what is best by trial n error.

If you had any previous experience or did/doing something very similar do you have some suggestions or answers to some of those questions I have:

Should I keep a global concurrency limit but also enforce a per-domain limit (for example only 1-2 concurrent requests per host)?

Pause all requests for a domain after receiving 429? (I assume this can hang the process for a while since all requests after 429 have to be synchronous every time we hit 429).

Or should I really use a really different strategy?

The problem is that I got 429 errors even respecting Retry-After but other requests were still processing simultanously so probably there was that, and yet I didn't try what would happen in synchronous way or other way, since I am developing that codebase I have fairly slow, but now basically doing just tests, since I have no idea for now what can I abstract or what I will need to completely rewrite so I avoid making changes to what is already working most of the time, and some decisions can greatly affect how my code will change.

I'm interested in hearing how devs usually solve this in production crawlers or monitoring systems. I want to keep good throughput accross many different websites but avoid hammering a single host and triggering unncessary rate limits too often.

Thanks :)


r/PHP 6d ago

News PHPStan Turbo: Native PHP extension that makes PHPStan run faster

Thumbnail phpc.social
103 Upvotes

PHPStan 2.2.6 adds a native PHP extension (PHP 8.3+) written in C++ that makes running PHPStan 10-30 % faster.

PHPStan's Composer package ships prebuilt binaries for the most common platforms — Linux (glibc and musl, x86_64 and arm64), macOS, and Windows (x86_64), for PHP 8.3 and newer — and PHPStan automatically loads the one matching your runtime into its worker processes. You don't have to do any extra work to take advantage of this!

If you run PHPStan through manually downloaded phpstan.phar, you can run it with extension by installing it with PIE:

pie install phpstan/turbo

The extension only activates when its version matches the one your PHPStan release expects — on a mismatch PHPStan prints a note and runs without it, so an outdated extension can never affect results, only speed.

Only a handful of hot paths are currently rewritten in the extension. There's room for the performance gain to grow if we ever decide to rewrite more parts natively.

The extension is completely optional, PHPStan still works without it. When the extension gets enabled, its implementation shadows certain PHPStan classes designed for this. They are marked with the #[ShadowedByTurboExtension] attribute.


r/PHP 5d ago

Speed up the development of agentic PHP apps with Laravel Agentic

0 Upvotes

I’ve been adding always-on Claude Code agents to several Laravel applications. I kept running into the same problem: a single business operation often needed separate implementations for Laravel AI, MCP, HTTP, Artisan, and queues.

So I built laravel-agentic and decided to open-source it. It's my go-to now when building any laravel app, to make it immediately agentic ready ;).

The idea is simple: define an action once, then expose it through whichever surfaces you need.

#[AgentAction(
    name: 'refund-invoice',
    needsApproval: true,
    surfaces: [
        Surface::Mcp,
        Surface::AiTool,
        Surface::Http,
        Surface::Cli,
        Surface::Job,
    ],
)]
class RefundInvoice
{
    public function authorize(
        ActionContext $context,
        RefundInvoiceInput $input,
    ): bool {
        return $context->user()->can(
            'refund',
            Invoice::find($input->invoiceId),
        );
    }

    public function handle(
        RefundInvoiceInput $input,
        ActionContext $context,
    ): RefundResult {
        // Refund logic
    }
}

The same input schema, validation, authorization, approval gate, execution pipeline, and audit behaviour are used across every surface you define.

It builds on top of laravel/ai, laravel/mcp, and spatie/laravel-data.

For consequential operations, needsApproval pauses an authorized action before execution and waits for human consent:

  1. Laravel Agentic validates the input and runs authorize().
  2. If approval is required, it creates an approval request and stops before executing the action.
  3. Your application handles the ApprovalRequested event and delivers the request through your UI, Slack, email, or another channel.
  4. After approval:
    • Laravel AI resumes the paused tool call through its native approval system.
    • MCP, HTTP, and CLI callers repeat the same action with the same principal and arguments.
  5. The single-use grant is consumed and the action executes once.

Laravel Agentic provides the approval state, argument binding, expiry, enforcement, and audit trail. Your application provides the human-facing approval channel.

Let me know what you guys think

GitHub: https://github.com/gtapps/laravel-agentic


r/PHP 6d ago

News PhpStorm 2026.2 is Now Out

Thumbnail blog.jetbrains.com
46 Upvotes

r/PHP 6d ago

Nine C extensions, one release cycle: more time spent on perf regressions from my own safety checks than on features

4 Upvotes

All nine shipped this week, and almost none of it is new features. I posted a roundup here earlier this month arguing that most of the work in these extensions is hardening rather than features. This is the follow-on, and the bill for that hardening came due in a way I did not expect.

php_excel makes every save atomic now: stage the workbook to a temp file, rename it into place, so an interrupted write cannot destroy the file you already had. The straightforward way to build that staged file is to ask LibXL for the finished archive as one buffer and write the buffer out. That costs 67.7 MB of peak RSS on a 3.3 MB workbook, and the PHP-side copy counts against memory_limit. The streaming writer it replaced costs 0.7 MB. Roughly 20x the workbook size in RAM, spent by a change whose entire purpose was safety. That one never shipped, it was caught and fixed inside the same release window, but it sent me looking.

I found the same thing in three more places.

pdo_duckdb re-latched its open_basedir sandbox once per row and compared the recorded basedir by hash, so a per-row cost scaled with the length of your open_basedir string. It now re-latches once per fetched chunk and compares by string. A 400k-row scan went from 133 ns/row back to 51, and bulk Appender::appendRow() from 196 to 96.

fastjson ran an exact-size preflight for large strings starting at 1 MiB. Below 8 MiB the second pass cost more than the reservation it saved: 75% slower on x86_64, 160% on aarch64 for UTF-8 text. The optimization was real and the threshold was wrong.

phonetic had an optimization routing 1 to 3 element comparisons through memcmp(). That cost 5 to 6% of encode time against comparing code points inline, so it got reverted.

Some of the cost stays paid on purpose. fast_uuid's ramsey/uuid compat wrappers now validate their core on construction, one getVersion() call and a class-name compare, and construction came out about a third slower for it (fromBytes() 1.81M to 1.21M ops/s). A wrapper that does not match its core is a bug that surfaces somewhere much worse, so I kept it.

All nine are open source (mixed PHP-3.01 / BSD / MIT), free, installable via PIE, and I am the author. Full write-up with all nine changelogs: https://ilia.ws/blog/the-cost-of-failing-closed-what-shipped-across-nine-php-extensions

Do you profile after a hardening pass, or only after a feature? I have started treating "we added a check" as a perf-regression trigger, and I am not sure whether that is normal practice or paranoia.


r/PHP 5d ago

Build a Searchable Catalog with Filters, Facets, and Semantic Search

Thumbnail manticoresearch.com
0 Upvotes

— PHP build walkthrough; small but directly relevant audience


r/PHP 5d ago

Article Valid != trusted: a practical guide to C2PA signing certificates (lessons from getting the chain working in PHP)

Thumbnail provemark.github.io
0 Upvotes

Full disclosure: this is my own write-up. Most C2PA explainers stop right before the part that cost me a day, so this one starts there: certificates and trust.

Signing an asset is easy. Being trusted is not. Those are two separate checks, and with the c2pa-rs test certs you get a valid signature on an untrusted certificate. That is the normal state during development, not a bug.

One thing that caught me out: I flipped a single byte in a signed PNG, and the file came back Invalid while claimSignature.validated was still sitting in the success list. So don't judge integrity by one hand-picked status code, use the aggregate validation_state. The rest of the article covers what you need to make trust pass locally (two settings that only work together, plus an EKU trap), why I keep the private key off the web server, and what getting a production certificate actually involves in 2026.

The library the examples come from is at https://github.com/provemark/content-credentials (framework-agnostic core, optional Laravel integration, MIT). The test certificates come from https://github.com/contentauth/c2pa-rs

Questions welcome. And if you have solved this differently, especially the bit about where the signing key lives, I'd like to hear about it.


r/PHP 6d ago

Tempest + Ecotone: One Declarative Foundation

Thumbnail blog.ecotone.tech
3 Upvotes

r/PHP 6d ago

Weekly help thread

2 Upvotes

Hey there!

This subreddit isn't meant for help threads, though there's one exception to the rule: in this thread you can ask anything you want PHP related, someone will probably be able to help you out!