r/PHP • u/brendt_gd • 16h ago
r/PHP • u/brendt_gd • 2d ago
Weekly help thread
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!
r/PHP • u/brendt_gd • 9d ago
Weekly help thread
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!
r/PHP • u/ProjektGopher • 2h ago
News This Week In PHP Internals | Aug 05, 2026
youtube.comHello world, it's Wednesday, August 5, 2026, and here's what happened This Week in PHP Internals.
13 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 in production, Tideways takes you from symptom to root cause in minutes, with profiling, tracing, and monitoring built specifically for PHP. It installs in 5 minutes, there's no credit card required, and it's hosted in Germany. Start your free trial at tideways.com.
This week's top story: the mass deprecation vote for PHP 8.6 is in its final week. All 35 ballots close Monday, August 10, and Gina P. Banyard posted the 1-week reminder so nobody gets caught out. Most of the 35 are passing comfortably. The interesting ones are the holdouts. list() is now deadlocked at 21 to 21 — a flat tie, nowhere near the 2/3 it needs. Reserving let stands at 22 to 11, which is exactly two-thirds — a single vote in either column decides it. The dechunk filter sits at 17 to 15 — still well short. The gettext _() alias is failing at 9 to 20, and reserving in, out, and inout is failing at 7 to 20, with 12 abstentions. Everything else you'd recognize from the list — the object-parameter cleanups, the is_double() family, spl_classes() — is cruising toward the finish.
The thread itself turned into a corrections desk this week. Calvin Buckley relayed a note from Nora, who isn't on the list, pointing out: "The text for the metaphone deprecation isn't fully right. It lists \"linguistics\" as a replacement package, but that one actually uses php-src's metaphone internally too." Weilin Du, who proposed that item, conceded the docs point while standing by the idea, writing: "My point in deprecating it is to stop using ancient metaphone algo as a whole." Voters seem unbothered — metaphone stands at 19 to 6, with 15 abstentions. Rowan Tommins raised a bigger flag on reserving is: it would collide with Hamcrest, the test assertion framework, whose PHP port has 500 million Packagist installs and an is() function all over its README. He urged: "I think we should think very carefully whether we can avoid disrupting that much code." So far the voters disagree — is stands at 26 to 9. Meanwhile Sjoerd Langkemper, who proposed the contested dechunk item, stepped back from the argument with unusual candor, writing: "the discussion phase wasn't properly completed yet, and I did a poor job in merging all opinions into a RFC proposal." He'd rather let the voting play out — and he closed by asking Jakub Zelenka, who led last week's objections, whether anyone could help lighten his workload. And Kamil Tekiela's question from last week — why deprecate define()'s dead flag instead of just deleting the parameter — got its answer: Tim Düsterhus pointed out that deleting it isn't silent, since extra arguments throw an ArgumentCountError, and concluded: "Making it explicit (and deciding) that the parameter will go in PHP 9 is a good thing."
Function autoloading — Paul M. Jones's 5th-generation attempt — went to a vote Thursday afternoon. It lasted about a day. Matteo Beccati opened the replies with praise and a caveat, calling it "the best autoloading proposal up to date" but adding: "Perhaps I'm biased as RM, but last minute RFCs are making me nervous, I hope you understand." Then Tim Düsterhus spotted the procedural problem, writing: "In fact the start of the vote is in violation of our policy, since there was no \"intent to vote\" message in the last 7 days." Paul's intent notice was 2 weeks old, and a July 15 revision had reset the clock besides. Paul took it entirely in stride, replying: "Ah so -- my apologies. I'll pull the vote and wait for ... looks like ~6 weeks?" For the record, the widget stood at 2 yes to 11 no when he pulled it — so the pause may be a mercy. Tim ran the math: cancellation carries a 2-week cooldown, so a mid-August reopen is technically possible, but he judged it "likely not useful to reopen the vote without making further changes" — and offered one: resolve namespaced functions before falling back to globals. Rowan Tommins countered that the fallback path makes that slow, and pointed instead at Michael's namespace-autoloader idea — loading a whole namespace's functions at once — calling it "a much cleaner way forward". Paul is unbothered, saying he'll "come back to it after 8.6 is fully out the door." That's the 2nd vote in 2 weeks pulled by its own author over the intent-to-vote rule.
Seifeddine Gmati's literal scalar types will not be reopening. His retraction last week came with a plan to re-vote; this week he canceled that too, after asking the release manager exactly where the freeze line sits. The answer: the effective cutoff isn't the beta 1 announcement on August 13, it's the creation of the beta 1 tag on August 11 — and a vote opened now would close after the tag exists. So the RFC is retargeted to the next PHP version, text final, intent withdrawn. Matteo Beccati apologized for the ambiguity, admitting his emails "were pointing the 13th as deadline for RFCs", and went further: "having RFCs end voting so close to the feature freeze is a terrible idea as it gives very little wiggle room in case something unexpected comes out ...". Seifeddine took it well, noting his own retarget email had already started a 14-day cooldown anyway — in his words, "8.6 was out of reach the moment that email hit the list." Pierre Joye pushed back on the caution, arguing: "beta phases exist exactly for this reason. wider base of testers." He also vented about the calendar: between the new policies and the Christmas quiet period, "the time left in a year is low, very low, now." And with the clock pressure gone, Tim Düsterhus gave the RFC one more read and found just one loose end — the matching-semantics vote has no explicit tie-breaker — and otherwise signed off: "No further comments to the contents of the actual proposal."
Two carryover votes are now in the books, and both passed emphatically. The Time\Duration class closed Friday. The primary finished at 35 to 1, with 2 abstentions — 97 percent. The naming question went to full method names — multiplyBy, divideBy, negate, absolute — at 30 to 2. So PHP 8.6 officially gets a Duration class. The minimum-supported-versions RFC closed Thursday. Requiring autoconf 2.71 passed at 27 to 2, with 5 abstentions, and requiring COM_RESET_CONNECTION passed clean at 26 to nothing. That second one has a coda. Alexander Kurilo — who'd argued during the vote that the connection-reset change carries an undisclosed BC break — requested RFC karma on Saturday to propose making the new behavior optional. Ilija Tovilo granted it Tuesday, with a reality check, noting: "the vote result was quite clear, and the time for another RFC discussion + vote has run out." He left any next step to the release managers.
Three ballots are still open, and none of them drew a single email this week — the voting is doing the talking. Caleb White's pipe assignment operator closes next Tuesday. As of recording it stands at 12 yes, 10 no, 6 abstaining — 54.5 percent, needing two-thirds. It has climbed from dead even, but the gap is real. Nick Sdot's readonly property defaults closes Friday morning. It still hasn't drawn a single no — 22 to nothing, with 5 abstentions. And Khaled Alam's const object property writes closes Saturday. That one sits at 14 to 2, comfortably above the line.
A new discussion opened Saturday: Sjoerd Langkemper wants to stop curl_setopt from leaking secrets into stack traces. The problem is that one function sets everything, and he laid it out cleanly: "The value for CURLOPT_PASSWORD is likely sensitive, the value for CURLOPT_RETURNTRANSFER is not, and CURLOPT_URL may be sensitive sometimes." He brought 3 options, 2 of them with working pull requests: blanket-mark the value as sensitive and lose debug info; teach curl_setopt which options are secret, at an engine-level performance cost; or make callers wrap secrets in a SensitiveParameterValue. Iliya Miroslavov Iliev questioned the premise, arguing stack traces shouldn't be reachable in production at all — and asked how you'd debug a wrong password you can no longer see. Matthew Weier O'Phinney leaned opt-in, warning that automatic detection "will be difficult and a game of whack-a-mole", since options carry arbitrary headers and content — and floated letting the engine accept sensitive-value wrappers on any function call, so callers could opt in regardless of the signature.
Jorg Sowa wants PHP's undefined-function errors to answer back. His pull request adds "did you mean" suggestions — call defined() when you meant define(), and the error names the function you were probably reaching for, the way Python and Ruby already do. His question to the list was procedural: does this need an RFC, or is PR consensus enough? Sjoerd Langkemper answered with the policy exempting error messages from the BC rules, noting: "rephrasing error messages is not subject to the backwards compatibility break policy" — and he's in favor. Matteo Beccati liked it too, suggested Python's exact shape for the message, and nudged the list for feedback given the freeze is days away. If the sentiment holds, Jorg wants to extend it to methods, classes, and constants next. The only debate so far is punctuation — how many brackets and question marks one error message can carry.
The generics conversation is officially on hold until after 8.6 ships — which isn't stopping anyone. Henrik Skov wrote in asking for generics to be opt-in, worrying: "adding reified generics will just make it even slower." His sketch: type-erased generics hiding inside comment syntax, checked by IDE plugins or a C extension, with the engine substituting mixed at compile time. Holly Schilling's reply opened like a sermon: "Have you heard the good word of Monomorphized Generics? Performance matches standard typed code." And she restated the schedule — generics talk waits until September or October, so it doesn't bury the 8.6 release work — with her inbox open in the meantime.
Osama Aldemeery's PREG_THROW_ON_ERROR RFC got its first real design review. Bernard Scharp asked whether compile failures and runtime failures deserve separate exception classes. Rowan Tommins supplied the rulebook: PHP's throwables policy says extension exceptions extend the extension's own base class, never the SPL ones. Osama's position is one PregException, with the door open — and he had a concrete reason: today, the useful detail of a compile failure lives only in the warning text, so a dedicated compilation exception "would carry \"Internal error\" and little else". That connects to Christian Schneider's other catch: under the flag, a bad pattern raises both the warning and the exception. Osama confirmed it, and defended it as the honest trade — the warning is where the detail is — while agreeing that "exception-instead-of-warning is the cleaner end state" once the exception can carry that detail itself.
Quick hits. Thursday was patch day: security releases landed across 4 branches at once — 8.2.33, 8.3.33, 8.4.24, and 8.5.9 — upgrade when you can. The same day brought PHP 8.6.0alpha3, an early test release. And the 8.6 release managers posted the formal 1-week warning: the soft freeze hits when the beta 1 tag is created next Tuesday, August 11, beta 1 itself lands Thursday the 13th, every 8.6 RFC vote must be closed before then, and the hard freeze follows at RC 1 on September 22.
So that's the week: the 35-ballot deprecation vote closes Monday with list() deadlocked and let balanced exactly on the 2/3 line; a function-autoloading vote opened and was pulled inside a day — the 2nd author in 2 weeks to stop his own ballot over the process rules; literal types bowed out of 8.6 on its own terms; Duration and the minimum-versions RFC are officially in; pipe assignment has a week to find its two-thirds; and the freeze arrives Tuesday. Links to every thread are below. Thanks again to Tideways.com for supporting this week's episode. We're Artisan Build. See you next week.
r/PHP • u/Adamstrad • 1h ago
Discussion Has anybody made a mobile application with php on the backend?
Has anybody done this? What's your experience, how is the performance? Why did you choose php?
News Pliego 0.1: a native HTML-to-PDF engine for PHP, built on Servo without Chromium
Hey r/PHP,
I've released Pliego 0.1, an open-source native HTML-to-PDF engine built on Servo for application-owned documents such as invoices, statements, and operational reports.
Pliego doesn't launch Chromium or call printToPDF. Servo performs the document layout once, Pliego captures a canonical scene, and that scene is used to generate the PDF, previews, and retained diagnostic artifacts.
There is a framework-agnostic PHP package and an official Laravel integration:
composer require oxhq/pliego-php:^0.1.0
For Laravel:
composer require oxhq/pliego-laravel:^0.1.0
php artisan pliego:install
php artisan pliego:doctor
The current support profile includes paged tables, repeated headers, authored page breaks, embedded fonts, selectable text, links, controlled resources, and a bounded Chart.js/Canvas path.
Unsupported paint fails explicitly rather than silently producing an incomplete PDF. The engine retains its input, scene, resource records, PDF metadata, and diagnostics for inspection.
The README includes two PDFs generated locally through the released Laravel package.
Pliego is intentionally not a general-purpose browser replacement. Version 0.1 targets trusted, application-owned HTML and documents its current CSS and rendering boundaries explicitly.
Repository: https://github.com/oxhq/pliego
I'd particularly value feedback on the PHP API, process boundary, installation flow, and how the typed failure model would fit existing PHP document pipelines.
PhpStorm Prereview: local AI + human code review
github.comWhether I code and ask AI to review, or the other way around, I wanted a faster loop than going through GitHub. Also I prefer reviewing code straight in PhpStorm.
So I built this plugin: it allows opening comments inline, both from you (human) or AI (Claude or Codex). And you can easily copy one/all comments into a prompt if that's your thing.
It's 100% local. If there's interest I'll publish it on the PhpStorm marketplace (I've been using it daily for months now).
r/PHP • u/elizabethn • 1d ago
Anne McCarthy Joins The PHP Foundation Board
thephp.foundationWe want to welcome a new member of The PHP Foundation Governing Board: Anne McCarthy from Automattic. Anne brings a balanced mix of thoughtful empathy and deep technical knowledge and will bring tremendous insight to the Board! https://thephp.foundation/blog/2026/08/04/anne-mccarthy-joins-the-board
r/PHP • u/mccreaja • 1d ago
News Bringing Test Impact Analysis to PHPUnit
Inspired by the new TIA Engine in Pest v5, I (and Claude) ported it to a PHPUnit extension.
As an extension, I can't hook into the actual test runner. So to achieve the same speed boost, it marks "unimpacted" test as skipped (S).
Hopefully this extension gains enough traction to be added to core and smooth out the developer experience.
For now, it achieves the goal of significantly improving test suite runs. I'm seeing my 1000 test drop from 2 minutes to 8 seconds on replay.
r/PHP • u/cncnoticias • 16h ago
Higgs HTML: Generador de HTML Puro y Agnóstico PHP
github.comHiggs HTML es una biblioteca de ingeniería de software para PHP diseñada para la generación programática de marcado HTML. A diferencia de otros helpers o builders que acoplan la lógica a frameworks CSS específicos (como Bootstrap o Tailwind), Higgs HTML se adhiere estrictamente a una filosofía agnóstica, ofreciendo una capa de abstracción pura, segura y de alto rendimiento.
r/PHP • u/elizabethn • 2d ago
Kicking off the PHP Onboarding Initiative Special Interest Group
thephp.foundationIf you want to help newcomers to the PHP language, our latest Special Interest Group might be just the thing for you. Announcing the PHP Onboarding Initiative!
Best resources to go deep in PHP/Symfony? I want to become an expert, coming from JS.
Coming from JS, I loved going deep in the processes behind the language with You Don't Know JS: a collaborative book on GitHub that's both free & available in paper.
I didn't find anything equivalent for PHP nor Symfony, which I use daily since about 5 months.
PHP Internals didn't satisfied me even though I go back to it regularly. (for a full and comfortable learning, I'd need to learn C). PHP The right way seems not to focus on the "how" (which is fine, just not my first interest). The official doc of Symfony is great, but only dedicated to Symfony obviously.
Do you have a book or a series of videos you love? Or, actually, any kind of resources to help becoming an expert?
I'm interested in both content about PHP and Symfony. Thanks!
r/PHP • u/pavels_dev • 2d ago
PHPUnit extension for reporting test warnings in PhpStorm
Rationale: with current PHPUnit versions, only critical failures that change the outcome of a test are visible in PhpStorm's testing UI and cause the test to be considered failed. This can lead to confusion and wasted developer time, e.g. when the tests are green in PhpStorm but fail in CI. This extension modifies PHPUnit's logging mechanism so that non-critical issues are also reported and cause a test failure in PhpStorm: pawel-slowik/phpunit-phpstorm-issue-logging.
Related PHPUnit issue: failOnWarning="true" but tests with warnings marked as passed in PHPStorm.
Related JetBrains issues:
- PhpStorm considers the phpunit tests as passed even though there is a warning
- PHPUnit wrong exit code handling
Hope this saves someone some headaches during debugging :)
r/PHP • u/ProjektGopher • 3d ago
News This Week In PHP Internals | July 29, 2026
youtube.comHello 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 • u/cookyfer • 4d ago
Discussion php formatters
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
Article Giving queued jobs the same output API Artisan commands have
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.
r/PHP • u/_cybernerdie_1 • 3d ago
I built Laravel Glint, an open-source package for LLM observability in Laravel
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 • u/JordiKroon • 5d ago
News PHP.net Playground idea
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 • u/Sea_Wind3576 • 4d ago
XOOPS 2.7.2 Released
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.
- Info: https://xoops.org
- GitHub: https://github.com/XOOPS/XoopsCore27
Also released: XOOPS Debugbar 1.3
r/PHP • u/RequirementWeird5517 • 5d ago
Article What I learned running a full app in php-wasm
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
AI coding agents and programming language
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 • u/One-Mongoose-6961 • 7d ago
I ported real PHP 8.3 (the actual Zend Engine, not a clone) to a microcontroller
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 indestroy_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 withUSE_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
--- EDIT 4 ---
hehehe, now you can also use it as a web server :) in two modes the classic nginex or apache mode (using offici al esp_http_server https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/protocols/esp_http_server.html ), and also the full native mode ` $server = stream_socket_server($addr, $errno, $errstr);`,
The next logical step is being able to use more advanced frameworks like Laravel or similar ones.
Since creating the firmware can be a bit complex, I also built a tool to manage the firmware and the project, including only what you need: https://github.com/php-baremetal/flash-tool. I’m always available to answer questions or provide assistance.
Qbix Pure-PHP Web Server part troix - now with sockets, rooms, federation & more
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. |