r/symfony 3d ago

Weekly Ask Anything Thread

1 Upvotes

Feel free to ask any questions you think may not warrant a post. Asking for help here is also fine.


r/symfony 6h ago

News This Week In PHP Internals | July 22, 2026

Thumbnail
youtu.be
2 Upvotes

While PHP Internals is technically not Symfony related, it does directly affect every single one of us.


Hello world, it's Wednesday, July 22, 2026, and here's what happened This Week in PHP Internals.

20 stories this week, so let's get into it. But first, This week's episode is brought to you by Tideways. Slow requests, and no clear reason why? Tideways helps you understand exactly where your PHP application spends its time — profiling, tracing, and monitoring to find and fix bottlenecks faster. And your profiling data stays hosted in Germany — GDPR-friendly by default. Learn more at tideways.com.

This week's top story: the season's first ballots are open — 2 sets of them — and the early counts are lopsided. Tim Düsterhus opened voting on the Time\Duration class on Friday with 2 ballots: a primary, needing a 2/3 majority, and a secondary choosing between full and abbreviated method names. As of recording, the primary stands at 23 to 1, and full names lead 18 to 1 — so multiplyBy and divideBy, not mul and divBy. Voting closes July 31. And remember Pierre Joye, who last week was leaning no over fromSeconds() and its capped nanoseconds argument? This week he closed the loop and voted yes, writing: "We were like ships passing in the night for some of my disagreements. The RFC wiki page did not show the additional constructor for other units, which hence the inconsistency I pointed out for the extra [nanoseconds] argument in fromSecond. They are here, and reduce this down to a lower level of bad APIs, more a pragmatic compromise conciliating different (if not numerous) use cases. Anything can be perfect, or shipped. Choose one." It turns out the per-unit constructors that resolved his objection had been in the RFC all along. His ballot almost didn't register, though — each vote on the wiki is a separate form, and Tim had to point out that you submit each one individually. The count now includes him.

Before the ballots opened, the Duration thread picked up a subplot about PHP 9. Holly Schilling — who wrote the class-extensions RFCs we covered last week — announced she's drafting a Value Structs proposal for after the 8.6 window, and argued that Duration would make a better struct than a class, with both ideally landing together in PHP 9. Ilija Tovilo replied by linking his own existing structs-v2 draft and asking whether she was aware of it. She was — she'd read it before drafting her own, and diverged from it on purpose, keeping mutating and non-mutating functionality separate. Tim saw no reason to wait on any of this, saying a draft-stage idea "will take an unknown duration to land - if it ever happens" — his pun, not mine — and that improvements to the standard library shouldn't queue behind it.

The week's other live vote came from Eric Norris, who opened balloting Thursday on minimum supported versions for PHP 8.6 — also with 2 questions, each needing a 2/3 vote. Requiring autoconf 2.71 for builds from git stands at 20 to 3 with 4 abstentions. Requiring COM_RESET_CONNECTION — which sets a floor of MySQL 5.7.3 or MariaDB 10.2.4, so persistent connections actually get reset — stands at 21 to nothing with 3 abstentions. Alexander Kurilo arrived after the discussion phase to ask for an opt-in instead, warning that on older databases persistent connections will silently turn non-persistent. Eric noted: "MySQL 5.7.3 is at least a decade old; it was released on December 3rd, 2013." After walking through every opt-out design he could think of, he concluded the right move is to make the correct behavior the default. The 3 no votes on autoconf include Jakub Zelenka, who's worried about building on Red Hat Enterprise Linux 8 and 9 — Tim offered to delay that particular merge to early 8.7. Both votes close July 30.

Saturday night, Pierre Joye opened the RFC that grew out of the libgd sync we covered last week: gd 2.4*. It's big — 3 pillars. First, syncing the bundled gd extension with upstream libgd: new codecs like QOI, JPEG XL, and UltraHDR, animated GIF and WebP support, multi-page TIFF, and real metadata handling. Second, an additive object-oriented Gd\ API — codecs with fromFile() and toStream(), immutable image info, streaming readers and writers. Third, a brand-new *2D vector canvas built on FreeType's rasterizer, with gradients and the full Cairo compositing set. He says the implementation is nearly done, including a security audit. He declared discussion open for 14 days, until August 1 — and that one sentence is where the trouble started.

Because August 1 plus a 14-day vote lands after the deadline. Release manager Matteo Beccati was gentle about it, writing: "As much as I like this RFC, I'm afraid it came in a little too late." Jakub Zelenka explained that nobody — release managers included — has the authority to grant an exception; that would take a change to the policy itself. And Rowan Tommins did the arithmetic: with alpha 1 out July 2, the cutoff for an RFC's final state was July 14, which is 4 days before this thread even opened. Pierre's frustration has a specific shape. The implementation was finished weeks ago — what delayed everything was that his pull request sat waiting on an approval that had been assigned to an automated bot reviewer, so no human was ever going to sign off, and he eventually merged it himself. He also argues the stakes are real, because PHP 9 is the one chance to change old defaults, and missing this window locks the current design in for years. The thread got tense over tone along the way — Pierre felt brushed off by a terse reply, and Rowan apologized outright, then made the counter-case that a fixed cutoff applied to everyone is fairer than debating each RFC's merits one at a time. All of this landed the same day Larry Garfield asked the list, in a separate thread, to hold new business until September 1 so reviewers can focus on 8.6's finish line. So gd 2.4 is alive and under discussion — just aimed at the next release, whatever its number turns out to be.

Caleb White's pipe assignment operator, |>=, had a crowded week. Larry Garfield opened it unable to find a compelling use case, and by Monday had moved to a no — pushed there, he says, by a competing proposal. That competing proposal is Vadim Dvorovenko's left-to-right assignment RFC, published Sunday, which claims the same |>= token with opposite semantics. Vadim objects on principle, arguing: "Attempting to transform such an operator from an immutable, functional construct into a mutable, imperative one steers the language in the wrong direction and undoes previous efforts." Caleb declined to merge the proposals, noting that F#, Elixir, OCaml, and Hack all kept ordinary assignment alongside their pipes. Larry also claimed none of the pipe proposals could make 8.6, and Tim Düsterhus corrected him, asserting: "This is false" — the last major change was July 13, so voting could open July 27 and close August 10, before the freeze. Meanwhile Bob Weinand asked whether the desugaring double-fires property hooks. Caleb came back with tests showing |>= behaves exactly like ??=, and updated the RFC's single-evaluation section to match. Vadim's own RFC, as of recording, has 0 replies.

Paul M. Jones's strict-namespace RFC — the piece he carved out of function autoloading last Tuesday night — spent its first full week in one long argument about a single word. Rowan Tommins objected first, writing that strict "implies some extra check that namespaces are [correct] in some way, which isn't really what this is about." Ilija Tovilo went deeper, arguing: "the value-add of this declaration is very small if the plan isn't ever to deprecate/remove the old behavior." Tim Düsterhus is in favor — with a rename to global_fallback=0. By Friday Paul had 4 candidate names on the table and a diagnosis: the pushback is the name, not the feature. Theodore Brown pointed out he'd floated the same directive in 2019; Paul added it to the prior art with an apology. And Benjamin Außenhofer suggested splitting the ballot — vote the concept, then vote the name. Rowan warned against it, writing: "a split vote leaves voters who actively dislike a particular name with an awkward choice: vote Yes, and risk the [bad] name being chosen; or vote No, even though you would support the feature under a different name." The rest of the autoloading corner kept moving too: Paul updated function autoloading mark 5 to lean on the new RFC and wants its vote open in about 2 weeks, and Michael Morris's improved-autoloading draft drew warm-but-firm feedback from Larry Garfield and Rowan Tommins — both like the namespace-setup-file idea, neither wants it crammed into the class autoloader's callback.

Nicolas Grekas didn't let Ilija Tovilo's "sadly not in favor" be the last word on serializable closures. His rebuttal: caching one attribute isn't the point — the point is skipping the entire metadata pipeline that frameworks re-run on every request, and that's the measured slow path. On the security design, he refused to loosen it, writing: "Name-based closure unserialization would ship a universal, app-independent gadget in the engine ... I won't commit to an RFC that turns every serialized payload into that kind of gadget, and I don't think we should, either." Then Saturday brought version 0.3, and a surgical cut — the reflection API is gone, the serialize() support stays. His reasoning: "serialize() is the one feature that most/all cache systems are built on, so that's the place that needs the improvement." Fresh reviews welcome.

Wendell Adriel came back to the list Thursday proposing typed array declarationsarray<int, string> as real syntax, with 3 escalating enforcement levels. The review was fast and unsparing. Lazare Inepologlou flagged that you can't soundly subtype a mutable array without splitting reads from writes, and Wendell shipped a revised draft the next day. Rob Landers warned the whole thing overlaps the reified generics work, on hold until after the freeze, which is late August at the earliest. Rowan Tommins noted that level 1 — syntax without enforcement — rhymes with the bound-erased generics RFC the list just declined. Michał Marcin Brzuchalski even found a runtime hole, where functions like parse_str() that build results directly into a typed property can dodge the check. By Monday, Wendell put the RFC on hold himself. Larry Garfield's verdict was the sharpest, calling this "the already-dangerously-overloaded array mega-type" and asking for real typed list, set, and dictionary objects instead — which Wendell promptly volunteered to help build.

The frozen deprecations list for PHP 8.6 got its evidence file. Juliette Reinders Folmer scanned the Packagist Top 4-thousand — nearly four hundred fifty thousand files — and posted counts for every proposal. The headline being: list() appears over twelve thousand times, and Juliette wrote plainly: "Having said that, I'm definitely not in favour of deprecating list()." Compare spl_object_hash() at 625, is_integer() at 303, and a long tail of single and double digits — several proposals scored a clean 0. Kamil Tekiela discovered his mysqli proposal had missed the procedural mysqli_stmt_init(), patched the text, and worried aloud: "I hope this change is not going to reset the counter." Tim Düsterhus was quick to correct the record downward — one scary-looking count, on _ as a constant, collapses to 0 once false positives come out. And Monday, right on schedule, Gina P. Banyard confirmed the timetable, writing: "I intend to open the vote next Monday (the 27th of July) for 2 weeks so that the vote is finished on time for 8.6." Every deprecation gets voted in isolation — bring a lunch.

Quick hits. Go Kudo returned with a rebuilt cache proposal — a bundled user_cache extension, fully decoupled from OPcache this time; Larry Garfield likes it, flagged the lock story around remember(), and gently redirected it to 8.7 — adding: "Or 9, if that's what we call it." Holly Schilling's 4x fix for non-public asymmetric setters got its answer: no RFC needed — Tim confirmed a pure performance improvement just needs PR review, and Ilia Alshanetsky called it "definitely a strong candidate for PHP 8.6 inclusion." fennic pitched engine-native PSR-4 autoloading with spl_autoload_psr4_register(); Alex Rock wants classmap support before it can replace Composer's bootstrap, and Heinz Wiesinger pointed to his existing PECL extension doing much the same. Edmond of the TrueAsync project published a pre-RFC for an async scheduler engine interface — coroutine-aware core, no scheduler in core itself. His philosophical problem is that the RFC has no user-visible changes at all, and so far it has 0 replies. And Osama Aldemeery asked for RFC karma to formalize PREG_THROW_ON_ERROR — Ilija Tovilo granted it 2 minutes later.

Liam Hammett's markup expressions thread sprouted an alternative: Edmond proposed making the parser extensible instead, so JSX-like syntaxes could ship as extensions — Morgan liked that better than blessing one syntax, and within a day Edmond had a working DSL-hooks prototype, announcing: "Your wish has been granted. 🙂" Máté Kocsis and Ignace Nyamagana Butera kept refining query parameters — the open question is whether parsing limits belong on builder methods too, with Ignace arguing PHP shouldn't police what's really a business constraint. Prateek Bhujel's terminal-helpers extension hit 0.6.0 — it's now installable via PIE, and its output methods now write to standard PHP streams like STDOUT and STDERR instead of only its own built-in targets. The ballot queue grew by 2: Nick Sdot posted intent to vote on readonly property defaults for on or around July 23, and Khaled Alam's const-object-property-write opens Saturday the 25th — both aiming ahead of the freeze. Ben Ramsey amended the Working Groups RFC with a new section setting expectations for charter-RFC discussion. And release week: PHP 8.6.0alpha2, 8.5.9RC1, and 8.4.24RC1 all shipped — with alpha 3 and both GA releases converging on July 30 — while the release managers posted the countdown that framed half of this episode: soft feature freeze August 11, beta 1 August 13, every 8.6 vote closed before then.

So that's the week: 2 ballot boxes open and both lopsided — Duration cruising at 23 to 1, minimum versions right behind it; gd 2.4 arriving 4 days after the door closed and pointing at the next release instead; a pipe operator with 2 authors claiming 1 token; typed arrays proposed, revised, and shelved inside 5 days; and the deprecations list armed with its evidence file, ballots opening Monday — with readonly defaults and const-property-write queued right behind. 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/symfony 16h ago

Files touch() storage implementation for Symfony Lock component

Thumbnail github.com
2 Upvotes

r/symfony 19h ago

SymfonyCon Warsaw 2026: 10 easy steps towards a more inclusive workplace

Thumbnail
symfony.com
3 Upvotes

r/symfony 4d ago

A Week of Symfony #1020 (July 13–19, 2026)

Thumbnail
symfony.com
6 Upvotes

r/symfony 5d ago

Un profiler comme PHP-SPX

1 Upvotes

Bonjour à tous 👋

J'ai récemment voulu essayer le développement d'un projet complet / complexe avec Claude Code et Fable 5. Pour répondre a mes problématiques sur des projets legacy j'ai donc développé https://github.com/quentinRogeret34/php-pulse un profiler comme celui intégré dans Symfony ou comme PHP-SPX

Je vous le partage si ça peut également vous aider dans certains de vos projet legacy


r/symfony 7d ago

News This Week In PHP Internals | July 15, 2026

Thumbnail
youtube.com
4 Upvotes

While PHP Internals is not technically directly related to Symfony, internals does affect us all.


Hello world, it's Wednesday, July 15, 2026, and here's what happened This Week in PHP Internals.

This week's episode is brought to you by Tideways. Something in production is slow — and you can't see where. Tideways takes PHP developers from slow request to root cause in minutes, with profiling, tracing, and monitoring built specifically for PHP. 5-minute install, no credit card. Start your free trial at tideways.com.

This week's top story is a brand-new keyword knocking on the door: extension. One week after Larry Garfield floated Kotlin-style extension functions at the scalar-methods RFC, Holly Schilling arrived with working prototypes of Swift-style class extensions — born, she says, out of a Discord conversation — and it became the biggest thread of the week at 26 messages. The idea: add methods to a class you don't own — extension \DateTimeImmutable gives every date an isWeekend() — and, in a later phase, put methods on scalars, so "hello" gets a length(). She published 3 draft RFCs as gists, implementation included. Michael Morris asked the obvious first question, writing: "Looking at Swift's extension syntax I fail to see anything it adds not covered by the above." — the above being inheritance and traits. Holly drew the line clean: "An extension is essentially the reverse of a trait." With a trait, the author of the class decides; with an extension, the user of the class decides.

Then came the twist. 2 days in, Holly sat down to defend her own scalar-methods implementation — and couldn't. She wrote: "Typing this email this morning gave me real hesitation. If I can’t support my own implementation, no one else should either. I immediately set out to build a better version that I could put my full weight behind." The better version came from an unexpected place: C# 14, whose new extension syntax puts the receiver right in the declaration — extension string $str — no autoboxing, no downcast headaches. She rewrote all 3 drafts and the implementation around it in a day. Not everything got absorbed so gracefully: when Alex Rock proposed an explicit extend ... with ... wiring statement, Holly apologized in advance for the bluntness, then answered: "I reject this functionality." — extensions stay file-scoped, and they never override a real method. And Pierre Joye flagged a process problem: proposals keep citing Discord conversations as their origin, while he reads only internals and GitHub — and found no reference to a php.net Discord anywhere he searched.

Gina P. Banyard's Deprecations for PHP 8.6 — the annual bundle that spent June on fire — reached its quiet milestone: the list is locked. Gina declared the RFC "frozen", with only minor amendments still allowed, and put dates on everything: "I will initiate a call to vote next week on Monday (the 20th) for the following Monday (the 27th) so that the vote is done by the 10th of August." Because items were still being added in the final week, the policy's 2-week discussion clock is what sets that gap — and the timing is deliberate, so accepted proposals can land in 8.6.0 beta 1. The week's lightest subplot: Garrett W. wants the deprecation notices themselves copy-edited — those commas are comma splices, and he'd use semicolons. Tim Düsterhus explained the house style comes from PHP error messages, and added: "The deprecation messages can still change during PR review (or even later), there is explicitly no BC guarantees for those."

Paul M. Jones's function autoloading — attempt number 5 — got smaller this week, on purpose. The declare(strict_namespace=1) directive he added last week drew a structural objection from Tim Düsterhus, who argued: "I believe the strict_namespace=1 directive is a sufficiently unrelated concern - with enormous bikeshedding potential on its own, but also sufficient usefulness on its own - such that I feel it should be its own RFC that is a prerequisite to this one. It should not be piggy-backed onto function autoloading." Paul didn't fight it. He replied: "I'm good with that. I'll prepare a separate RFC and remove that from the function-autoloading one." — and by Tuesday night it existed: strict-namespace is now its own RFC on the wiki, and mark 5 will reference it instead of carrying it. Tim also showed his cards: he built the inverse directive as an experiment a year ago, and he's firmly on team fully-qualify-everything.

Tim Düsterhus and Derick Rethans' Time\Duration class is days from the ballot box — and it picked up its first declared no. Pierre Joye spent the week pressing on fromSeconds() and its capped nanoseconds argument, and landed here: "I like that RFC, but it adds confusions and limitations from what is supposed to be a simple first step. As it stands now, despite the fact that I would love to see it, I tend towards a no." Tim's defense reached for the stopwatch — it's natural, he argued, to say Usain Bolt broke the 100 m world record with "9 seconds 58 hundreths" — exactly the fixed-point form fromSeconds() uses. Pierre countered: "It is just as common in the real world to have duration information in one unit only and decimal. F.e. 234.54ms. or 3.4 hours, etc." Neither moved — and per Tim, that's fine: "All discussions have been resolved (some of them with an “agree to disagree”), so we plan to open voting at the end of this or early next week." The 14-day cooldown runs out Friday evening, European time.

A first-time author had a very good week. Caleb White got RFC karma from Ilija Tovilo, and his first proposal — the pipe assignment operator, |>= — went through review polish at speed. The idea: $x |>= trim(...) pipes $x through and puts the result back, just like every other modify-assign operator. Tim Düsterhus liked the shape, saying: "Conceptionally I like the idea of having an “in-place modification operator” for function calls and the semantics of the operator seem to be consistent with the existing “modify-assign” operators we have, particularly also with regard to operand order. Nice idea!" Tim also caught a precedence claim that was almost right — assignment operators are not the lowest; the infamous or die() pattern depends on it — and Caleb fixed the RFC the same day, both times. The list's real energy went to naming. Ben Ramsey offered: "I like to think of |> as the volcano operator, while |>= is the erupting volcano operator."

Then last night — hours before we hit record — Liam Hammett published Native Markup Expressions: JSX-style markup as first-class PHP expressions. Write a <button> tag straight into an expression, and it compiles to new \Markup\Element(...) — escaped by default, with capitalized tags becoming components. Liam headed off the obvious reading, writing: "Despite appearances, this is not a template language grafted onto the engine - the syntax is pure compile-time sugar." First reviewer Garrett W. questioned that capitalization heuristic — PSR-4 isn't binding, and lowercase class names are legal. Liam pushed back: "Fallback resolution turns typos into silent bugs. With the capitalisation rule, <Layuot /> fails loudly with a class-not-found error. With fallback resolution, it silently renders as a literal <Layuot> element and you find out in the browser, if you find out at all." This is the ambitious RFC Liam requested wiki karma for on July 10 — Ilija Tovilo granted it Monday: "RFC karma was granted. Good luck!"

Marc Henderkes wants to end PHP's double life. His pre-RFC: make ZTS — the thread-safe build — the default, deprecate the rest, and drop NTS entirely in PHP 9. He summed it up himself: "Tl;dr: nobody wants to maintain two builds and even having a necessary split is making things hard." Distros package only NTS, FrankenPHP needs ZTS, and php-src carries roughly 420 ZTS ifdefs. The performance tax is dissolving too — his numbers: "Worst case performance cost of ZTS in php 8.5 was ~5%, will be ~1.5% in php 8.6, likely ~0.5% after my last open PRs." To be clear, he is not proposing to deprecate FPM — a single-threaded ZTS run keeps everything NTS does today. 2 of the named blockers — the arm64 macOS JIT and the fuzzer SAPI — were fixed within 2 days of the thread opening; the third, NewRelic's missing ZTS support, isn't Marc's to fix. Benjamin Eberlei backed the initiative, Calvin Buckley volunteered his own PHP distribution as a test subject, and Marc has requested wiki karma to write the full RFC.

Nicolas Grekas's serializable closures spent the week absorbing a deep review from Tim Düsterhus — and then ran into a wall. Tim was candid: "While reading the RFC initially and now the updated version, I got the feeling that it was “overfitted” to solve the specific use case and deployment scenario that you consider a “best practice”, which I feel results in “weird” behavior when one leaves that happy path." Still, the 2 converged on real changes: Nicolas adopted Tim's tagged-union serialization format, and — after an off-list suggestion from Arnaud — replaced the fragile line-number check with a compile-time hash of the closure body, so a shifted use import can't silently break payloads. Then Tuesday night, Ilija Tovilo weighed in against — questioning whether attributes need caching at all, and finding the format and implementation too complex. He closed with: "Overall, I'm sadly not in favor of this RFC."

No ballot box was open this week — instead, the queue got dates. Eric Norris's minimum supported versions opens voting tomorrow, July 16 — the earliest the policy allows. Duration clears its cooldown Friday evening and opens late this week or early next. The deprecations list calls its vote Monday the 20th, with ballots open the 27th. And Khaled Alam's const-object-property-write RFC is cleared to open July 25 — no later than the 28th to make 8.6. All of it backs into the release managers' reminder from Monday. Matteo Beccati wrote: "Any RFC intended for inclusion in PHP 8.6 must have its discussion concluded and its voting closed before August 13." Soft feature freeze: August 11. Beta 1: August 13.

Quick hits, round 1. Máté Kocsis revived his query parameters RFC with a simplification: he's cutting the array API down to 2 — maybe 3 — methods, fromArray() and toArray() with withArray() on the bubble, plus an options class with security limits on parsing; League-of-URI maintainer Ignace Nyamagana Butera answered with naming notes and an enum for null handling. Nick Sdot's readonly-property defaults — zero replies when we covered it last week — got its replies: Tim Düsterhus found an unserialization wrinkle, Nick fixed it the same day, Larry Garfield is skeptical, and Tim plans to abstain. Holly Schilling — the same Holly Schilling from our top story — found that non-public asymmetric setters run roughly 4x slower than public ones, posted a fix, and then a formal RFC for it — with Ilija Tovilo reviewing the PR, she's giving the list a few days to weigh in on 8.6 versus waiting; Marc Henderkes and Calvin Buckley both questioned whether an internal change needs an RFC at all. And Osama Aldemeery's PREG_THROW_ON_ERROR settled its naming on Tim's advice: an unnamespaced PregException.

Round 2. Sjoerd Langkemper showed that newlines in CURLOPT_HTTPHEADER values inject extra headers — even over HTTP/2 — and opened a fix; upstream curl is adding its own check, and curl's own Daniel Stenberg confirmed CRLF is disallowed. Xavier Leune bumped his curl socket-callbacks PR — pitching it as the missing tool against SSRF to localhost — and is still waiting on a reply. The bundled-GD sync to libgd 2.4 drew its first pushback: Giovanni Giacobbi says the upstream code is too young and 8.6 too far along, while Pierre Joye, Jakub Zelenka, and Ilia Alshanetsky want it landed before beta 1 — Jakub's condition being that the security-review findings get addressed first — and Kamil Tekiela says wait for the next version. And the DTLS experiment in the openssl extension became a real draft PR; Jakub Zelenka confirmed the direction and is already sketching the generalization it needs.

So that's the week: a brand-new extension keyword that rewrote itself mid-thread; a frozen deprecations list with ballots set for the 27th; function autoloading shedding a prerequisite RFC; a Duration vote opening within days, carrying its first declared no; and a JSX-flavored surprise landing the night before we filmed. Nothing was voted on this week — and the ballot queue starts moving tomorrow. 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/symfony 8d ago

Symfony UX 3.3.0 released

Thumbnail
symfony.com
15 Upvotes

r/symfony 8d ago

Symfony You start with cities for one country... then one day you need the whole world.

11 Upvotes

I've been bitten by this more than once.

On one project, I needed an API for city lookup and address autocomplete.

It usually starts with a simple table containing cities for a single country.

Then requirements evolve:

* support international cities;
* handle ISO country codes;
* import data from different providers.

Or even worse, someone decides users should be able to maintain the city database manually.

So instead of writing the same component again, I cleaned it up and open-sourced it.

Features:

* City search
* Address autocomplete powered by OpenStreetMap (Photon)
* Deployable with Docker or Podman in a few commands
* Designed to be easily extended if another data source needs to be plugged in

Tech stack:

* Symfony / API Platform / PostgreSQL
* Hexagonal Architecture
* 100% unit test coverage on the domain layer
* Behat scenarios used both as executable documentation and API tests

I don't think this project is going to change the world.

But if it helps someone avoid a questionable data model, or rewriting the same component for the tenth time, then it's already worth it.

Repository: https://github.com/thlaure/world-cities-api

I'm genuinely interested in feedback, especially from people who have had to solve the same problem in production.


r/symfony 8d ago

SymfonyCon Warsaw 2026: The first 4 speakers are live! 🔥

Thumbnail
symfony.com
2 Upvotes

r/symfony 8d ago

New SymfonyCasts Course: Upgrading to Symfony 8

Thumbnail
symfony.com
14 Upvotes

r/symfony 10d ago

Weekly Ask Anything Thread

2 Upvotes

Feel free to ask any questions you think may not warrant a post. Asking for help here is also fine.


r/symfony 11d ago

A Week of Symfony #1019 (July 6–12, 2026)

Thumbnail
symfony.com
9 Upvotes

r/symfony 13d ago

I built a Symfony bundle to manage & send dynamic email templates stored in a database (with Twig & expected variables validation) - Callisto Mailer

11 Upvotes

Hey r/symfony!

I wanted to share a Symfony bundle I've been working on to solve a problem I keep running into: having to redeploy application code just to fix a typo or modify the layout of a transactional email template.

It's called Callisto Mailer (fully open-source under MIT).

Here's the GitHub repo: https://github.com/callisto01/Callisto-mailer And the documentation: https://callisto01.github.io/Callisto-mailer/

Why not just use static Twig templates? Static Twig templates are great, but non-technical managers or marketing teams often want to tweak email copy or add discount codes.

Callisto Mailer lets you store templates in a database using Doctrine (perfect to expose via EasyAdmin) and renders them dynamically on-the-fly using Twig.

Quick Example:

// Inject DatabaseMailerService
$mailerService->send(
    code: 'welcome_email',
    recipient: '[email protected]',
    context: ['user' => ['firstName' => 'Lucas']],
    locale: 'en'
);

I'd love to know what you think! Does this solve a pain point in your daily projects, or do you handle database-driven emails differently? Feedback and PR contributions are welcome!


r/symfony 14d ago

News This Week In PHP Internals | July 8, 2026

Thumbnail
youtube.com
1 Upvotes

While PHP Internals is not technically directly related to Symfony, internals does affect us all.


Hello world, it's Wednesday, July 8, 2026, and here's what happened This Week in PHP Internals.

This week's episode is brought to you by Ballast. Your team ships constantly — but how much of that work actually lasts? Ballast reads your git history and computes a deterministic durability score: does shipped code hold up, or churn and get redone? Ballast is in early access now at ballast.now.

This week's top story is still Gina P. Banyard's Deprecations for PHP 8.6 — the annual bundle where every removal gets its own ballot — and this week it caught fire twice. First fire: the long-array question. With Seifeddine Gmati's list() deprecation already on the table, Tim Düsterhus floated a draft that turns array() into a real cast function — and Michael Morris erupted at where that road leads. He asked, "Are you crazy?" — deprecating array() would, by his math, touch 3 quarters of WordPress core and nearly every plugin. Seif's counter was all receipts: the rewrite is one ast-grep command, array(...) and [...] compile to byte-identical opcodes — and, for the record, "The proposal is to deprecate list(), not array()." Then Juliette Reinders Folmer — who maintains the WordPress Coding Standards — corrected everyone: WordPress still supports PHP 7.4, and short arrays were blocked there for years by a handful of core committers, not the community.

It got personal — Morris told Seif to step out of his ivory tower; Seif kept answering with engineering. He wrote: "I've written a compiler that migrated a multi-million-line codebase from one language to another, automatically, overnight. Swapping one AST node for another that is literally equivalent to the compiler is not a feat of engineering courage." To Morris's credit, when told he was turning it personal, he replied: "I am, and I apologize." — and the thread cooled.

Then Monday it reignited — over evidence. Gina regrouped the list, folded in new items sent to her directly, and set the clock: "If none are added or amended, I will initiate a call to vote next week." Rowan Tommins counted 35 proposals and only 8 with any discussion of who'd be affected, and threatened to cast 27 blanket no votes. Gina drew her line: "You are free to do as you please." — she won't produce metrics for the sake of metrics without an agreed method. Rowan held firm: "I do not think we should be removing features without thinking about who will be affected. I'm honestly shocked that that's a controversial opinion". Juliette, once again the bridge, renewed her offer to generate real impact data with PHPCompatibility — feasible, she says, for about 25 of the 36 items. One item is on its way out: the by-reference-return-modifier deprecation — Bob Weinand recommended a complete retraction, and its proposer had already offered one. The RFC freezes July 13 — expect the call to vote next week, though with the mandatory 14-day cooldown after Gina's latest changes, actual ballots open July 21 at the earliest.

Tim Düsterhus and Derick Rethans' Time\Duration class — the stopwatch value object aimed at 8.6 — got called done this week: "we would consider the RFC to be complete". The final decisions: add and sub won an informal PHP Foundation Slack poll unanimously; the past-tense method suffixes are gone; divideInto() got pushed to future scope; and the ban on negative constructor arguments stays, on Derick's call. One naming question goes to the voters as a secondary vote: full names like multiplyBy and absolute, or abbreviations like mul and abs — with the abbreviations needing a 2-thirds supermajority.

But one fight would not close: fromSeconds(). It takes seconds plus a nanoseconds argument, capped at 999 million 999 thousand 999 — overflow is rejected, not carried. Marc B. objected: "It makes it simple to reason about for you as implementing it - it forces the burden to the one using the API." Pierre Joye brought prior art: Java and Rust both carry the overflow instead of rejecting it, and JavaScript's Temporal doesn't impose the cap either. Tim's defense: an injective constructor means one value, one spelling — a form asking for seconds should reject out-of-range input the same way June 31 should be rejected, not silently become July 1. Neither side budged — and with the RFC complete, that question rides along to the vote.

Function autoloading now has 2 competing designs, and they met in the same inbox on the same day. Paul M. Jones updated his mark-5 RFC — that's attempt number 5 — adding a declare(strict_namespace=1) directive to kill the global-fallback edge case, plus research across the top 1000 Packagist packages: exactly 2 packages and 8 call sites would misbehave. Meanwhile, Michael Morris — fresh off the deprecations thread — had floated an idea on July 2, saying: "An idea that popped into my head an hour ago, that I don't have another PHP Dev to talk to about, what if you could register a function that is called by PHP the first time it sees a namespace declared?" Five days later that spitball was a formal draft: autoloader callbacks that take 2 arguments — the class and the namespace — firing the first time the engine meets a namespace. And within hours of Paul's update, Morris was in Paul's thread advertising his rival.

The reason the spitball grew legs is Rowan Tommins. His endorsement became the backbone of Morris's draft — he wrote: "This really nicely side-steps the global-vs-namespace sequence problem that function autoloading always runs into: by the time the engine reaches an unqualified name, the namespace loader has already run for the current namespace, and defined any functions it wants." Not everyone's sold. Aleksander Machniak flagged that passing null to existing string-typed autoloaders is itself a BC break, and Alex Rock argued the draft bundles 2 different proposals and called it overkill. Morris's reply had some edge: "And you've misread the proposal entirely."

The busiest brand-new thread: Matheus Martins revived typed closures — write Closure(int): bool as a parameter type, and a mismatched callback fails at the boundary with a clean TypeError instead of exploding deep inside your filter(). The reception was warm — Matthew Weier O'Phinney would find it "very useful", and Larry Garfield is in favor, to nobody's surprise. Rob Landers suggested waiting for generics; Seif pointed out that would need variadic generics, which have never appeared in any proposal — waiting for generics means waiting indefinitely. Larry was blunter: "Generics syntax is the wrong format to use for this, full stop." The real villain is the lexer: inside Closure(int), that (int) is a cast token. Osama Aldemeery, who's been down this exact tunnel, put it memorably: "So the natural spelling is, unfortunately, the engine-hostile one."

Where it landed: inline signatures first, named type-aliases later, and neither blocks the other. Larry pre-empted the objection everyone could see coming — if someone gets fussy about long signatures, the answer should be "that's nice, go work on aliases then and don't block this RFC". By Monday he'd added just one ask: invokable objects should fit through the same door, not get squeezed through closures.

Rob Landers' primary constructors — the constructor hoisted onto the class line — spent June fighting over whether it may carry a body. This week that fight hit its endgame, in a single day of posts. Rowan Tommins came off the fence — with a body bolted on, he'd be a definite no. Rob, the author, declined to relitigate: "All I can say is that I reject it for future scope, repeatedly." Nick Sdot stood down under protest, warning: "We don't need more half finished, half not working, confusing features in PHP." And then, quietly, the week's one unreserved fan — a reader who wrote that extending third-party classes and calling the parent constructor by hand "always felt dirty". The thread's been silent since July 1.

Michal Kral's scalar object methods(3)->pow(2), dispatched at compile time — came back for round 2, and the room steered it somewhere new. Michal gave real ground: he'd restrict or drop the file-order-dependent form, and lean on typed locals for safety. Seif stayed unmoved, arguing: "Seeing $s->trim() where $s is a string, I should know it works. A construct where identical AST dispatches or doesn't depending on file position, a redundant cast, or whether a declaration sits above or below the call is not something people can reason about." Then Larry Garfield reframed the whole conversation: a small curated set of methods, he said, "is bikeshed bait, and needlessly limiting" — and counter-pitched Kotlin-style extension functions on any type, from a design he drafted with Sara Golemon. Michal's response? Genuinely interested. They're talking off-list once Larry's back from vacation.

To the scoreboard — one ballot closed, one never opened. Jordi Kroon's third-party extension documentation RFC is in: 26 to 1, with 1 abstention. The secondaries settled too: the docs land on a php.net subpath rather than a new subdomain, 15 to 8, and the old user notes get dropped in the move, 21 to 4. Meanwhile the grapheme_mask vote that was announced for July 3? As far as we can tell, it never opened — the RFC page still says draft, and the feedback stayed kind but firm. Yuya Hamada wrote: "Thank you very much for your RFC. But move to voting phase is too fast." The pipeline ahead is stacked: deprecations expects its call to vote next week, and Duration finishes its cooldown just in time for the mid-August freeze.

Quick hits — and there are a lot, so this is a 2-slide round. July 2 was patch day: security releases for 8.2, 8.3, 8.4, and 8.5, and 8.6.0 alpha 1 is out for testing. Eric Norris and Tim Düsterhus published the minimum-supported-versions RFC — newer autoconf, and MySQL 5.7.3 or MariaDB 10.2.4 for persistent connections — and an anonymous tester promptly found a real connection leak on old MySQL, declaring: "There is connection leak here!" — Eric's tracked down the cause and is weighing a fix. Nicolas Grekas redesigned serializable closures and offered a slimmed-down fallback, nudging the list that 8.6 won't wait. Osama Aldemeery floated a PREG_THROW_ON_ERROR flag — implementation already built. And Nick Sdot posted a tiny RFC: default values on readonly properties, a 5-line removal — zero replies so far.

Still going. Literal scalar types turned into an enums-versus-literals standoff, where Nick warned: "We should not make PHP another TypeScript." Ben Ramsey added a Foundation-SIGs section to Working Groups and wants feedback before he votes it — or withdraws it. The DTLS experiment graduated to a working 1.2 branch; Jakub Zelenka wants a draft PR. Pierre Joye synced bundled GD with libgd 2.4 and is untangling Windows dependencies. Pratik Bhujel's terminal helpers got Derick's blessing — ship it via PIE, since PECL takes no new packages. And Pratik also asked whether fixing sscanf's %c whitespace bug — in place since PHP 4.3.2 — breaks anyone on master.

So that's the week: a deprecations list that fought about WordPress and then about evidence, with the call to vote days away; a Duration RFC wrapped up and waiting out its cooldown; 2 rival answers to function autoloading colliding in real time; typed closures winning the room while the lexer holds the door; and the one ballot that closed, passing 26 to 1. Links to every thread are below. We're Artisan Build. See you next week.


r/symfony 15d ago

News My Symfony page made 87 queries. This profiler tab found the N+1 in 2 seconds.

27 Upvotes

Before: page felt slow, no idea why.

After: opened the profiler, it pointed straight at the N+1. 87 queries → 3 after the fix. It's a bundle that reads your Doctrine queries in the Web Profiler and flags N+1s, slow queries, and missing indexes, with the fix suggestion right there. I really recommend this tool.

Repo: https://github.com/ahmed-bhs/doctrine-doctor


r/symfony 17d ago

Weekly Ask Anything Thread

3 Upvotes

Feel free to ask any questions you think may not warrant a post. Asking for help here is also fine.


r/symfony 18d ago

A Week of Symfony #1018 (June 29 – July 5, 2026)

Thumbnail
symfony.com
5 Upvotes

r/symfony 19d ago

Twig 3.28.0 released

Thumbnail
symfony.com
24 Upvotes

r/symfony 20d ago

Case Study: Driving Green Innovation: How Symfony Empowered Veolia’s Digital Shift in Industrial Waste Management

Thumbnail
symfony.com
7 Upvotes

r/symfony 21d ago

News This Week in PHP Internals | July 1, 2026

Thumbnail
youtu.be
3 Upvotes

While PHP Internals is not technically directly related to Symfony, internals does affect us all.


Hello world, it's Canada Day 2026, and here's what happened This Week in PHP Internals.

This week's episode is supported by OurCVEs. Hundreds of CVEs ship every week, and almost none of them are about you — until one is. OurCVEs inventories your entire infrastructure and only surfaces the security risks that actually apply to your team. Free for open source at ourcves.com.

This week's top story is still Gina P. Banyard's Deprecations for PHP 8.6 — the once-a-year housekeeping RFC that gathers a stack of unrelated removals under one roof, where each one stands or falls on its own separate vote. With 8.6's first alpha getting built this very week, the clock is loud. But the fight this week wasn't about any single removal — it was about evidence: does every deprecation owe voters an impact analysis? Tim Düsterhus argued no, at least not as an unconditional rule — a deprecation has years of runway, and a survey of existing code can't measure the upside of a cleanup.

Juliette Reinders Folmer had offered to build those impact analyses, and her exchange with Tim turned personal — an accusation of gaslighting, which Tim rejected. But she was far from alone on the substance. Rowan Tommins came to her defense, and he didn't warm up first. Rowan wrote: "I hate this argument." His point: deprecating something is really a proposal to remove it later, so the impact of that removal is exactly what voters deserve to see — and to leave it out to protect your case, he said, would be dishonest. Larry Garfield backed the same call: put the impact on the table, or read the angry blog posts come December.

And this particular RFC kept growing right up against the freeze. Seifeddine Gmati proposed deprecating list(), and got the room's attention: Ayesh Karunaratne clocked "7 million hits" for list( on GitHub and called the break too big; Rowan noted you can't really retire list() while array() stays — to which Seif said, fine, then maybe deprecate array() too. Nick moved to reserve namespace as a constant name. Ilia Alshanetsky floated finally sunsetting open_basedir — Derick Rethans said "Yes, but for PHP 9," while Jakub Zelenka was firmly against it. Add a careful fight over how narrowly to kill the dechunk filter, plus Tim's pitch to retire gettype() for get_debug_type(), and that's a lot of small knives being sharpened at once.

Carrying over: Tim and Derick's Time\Duration class — the immutable stopwatch value that's meant to be the first brick of a modern date-and-time API. One line of context, then this week's moves: they're dropping the word "period" from the method names (Derick pointed out ISO itself walked away from it); they're lifting the ban on negative durations after Paweł Kraśnicki showed up with a real use case; and the whole thing may slim down for 8.6 — ship addition, subtraction and multiplication now, and let dividing one duration by another wait. Ignace Nyamagana Butera and Nick are already bikeshedding whether that division should hand you back a tuple or a tidy little value object.

The single busiest thread of the week was brand new: Rob Landers formally opened Primary Constructors — the whole constructor hoisted up onto the class line itself. His numbers are the pitch: something like 30 to 40 percent of all constructors are completely empty, and by his count 71 percent of Laravel and 61 percent of Symfony classes could use this. The catch is deliberate — a class with a primary constructor can't also declare a regular __construct, and it can't carry a body.

That no-body rule is the whole fight. Nick pushed for a body — mostly so readonly classes have a way through — and warned this could ship as yet another half-a-feature. But Rob held the line. He wrote: "If you need a body, use a constructor -- that's what they're for." Rowan and Tim are with Rob — Tim called the limitation "a feature," and put it simply: "[To] reduce typing alone is not a sufficiently strong argument in favor of a new feature." Seifeddine went further: "Personally, I really dislike this feature." His read — primary constructors don't remove repetition, they just relocate it. Larry, meanwhile, wants a Kotlin-style init block bolted on. Plenty's still unresolved — visibility, attributes, anonymous classes — so we'll be keeping an eye on this one.

Newcomer Michal Kral floated a spicy pre-RFC: methods on scalars. Write (3)->pow(2), or " hello "->trim()->upper(), with the call rewritten at compile time into a hidden helper — but only when the compiler can already prove the value is a scalar. He was upfront that he built it with an AI assistant. The reception was cool: Seifeddine's core objection is that PHP compiles one file at a time, so "the compiler already knows it's a scalar" covers almost no real code — the same line would work or fail depending on what's autoloaded. His fix, nicely put: "Solve the naming problem with naming, not by blinding the tooling." And Rob warned the whole thing leans on casts, which in PHP are dangerous(int) of the string "123password" is just 123.

Alex Pătrănescu opened a pre-RFC for runtime modules — a way to give each package its own private symbol table so two versions of the same library can finally coexist in one request. Rowan Tommins spent the week reframing it as containers — a boundary you run other people's code inside, Docker-style — and kept circling the genuinely hard part: what happens when an object crosses the wall between two containers? A second contributor, Alexander Egorov, pitched version "tags" instead; Rowan's worry is that tags leak the container's insides right back out. No code yet — but a problem the whole ecosystem feels.

The rawest thread of the week came from a user, not an internals regular. Michael Morris wrote what he openly called a "Disheartening Rant" after Edmond Dantes said his own TrueAsync RFC has, in his words, a 90 percent chance of not being accepted. Morris didn't hold back: "If you want PHP to be the next COBOL, this is how you go about it." His killer example is WebSockets — the thing PHP still can't really do on its own. Ilia Alshanetsky pushed back gently (he's actually written COBOL, and reports it isn't dead): async matters, but its reach in a request-based language is narrower than it looks.

Larry Garfield drew the line that matters — the same one that just sank generics. Larry wrote: "Don't confuse 'this is not the async we're looking for, done in a painful process' with 'we don't want async at all, ever.' The first is what happened. The second is simply untrue." His critique isn't of async — it's of how TrueAsync arrived: enormous, one author, hundreds of far-reaching decisions, feedback taken selectively. His fix is a real working group to design it together. Nobody's against the destination — they're against the map.

To the ballots — and this was a brutal fortnight for the marquee names. Seifeddine's Bound-Erased Generics closed and was declined: 7 in favour, 19 against, 10 abstaining — nowhere near the two-thirds. And Nicolas Grekas's __exists() magic method went down with it, 2 to 13. The two features that would've made the headlines both missed.

But look what did pass — the quiet, careful stuff, every one without a single No. Tim's deprecation of returning values from __construct and __destruct: accepted unanimously, 39 to nothing. Sjoerd Langkemper's cap on php://filter chains — that local-file-inclusion-to-RCE fix — accepted 30 to nothing, 2 abstaining. And Weilin Du's Locale display-keyword additions: in, 18 to nothing, 2 abstaining. And one's still live on the board — Jordi Kroon's move to lift third-party extension docs out of the manual is out in front at 25 to 1, one abstaining, with the vote closing July 3; on the side questions the room is leaning toward a php.net subpath over a separate subdomain, 14 to 8, and toward dropping the old user notes rather than migrating them, 20 to 4. The pattern's getting hard to miss: the bold swings keep getting sent back, while the tidy, well-scoped changes keep sailing home.

Quick hits. That newcomer arc — Sepehr Mahmoudi's grapheme_mask — got RFC karma and a warm discussion, then tried to call a vote for July 3 and was told, kindly, it's not ready: no discussion link, freeze period not met, window too short — the process catching a first-timer before the fall. Khaled Alam's write-to-constants RFC grew to cover class constants, so its vote slipped. Gianfrancesco Aurecchia's DTLS idea converged fast — Jakub steered it from a new class to a simple dtls:// stream, maybe no RFC needed at all. Gina volunteered to review the long-stranded snmp extension work. Seifeddine's Literal Scalar Types reached version 0.3. Jorg Sowa's case-sensitive-PHP revival was withdrawn. And PHP 8.6.0 alpha 1 got built — which is why everyone's sprinting.

So that's the week: a deprecations RFC that turned into a fight about honesty, a stopwatch class quietly going on a diet, a brand-new primary-constructors debate, a heartfelt plea for async — and the two flagship votes falling while the small ones walked right in. Links to every thread are below. We're Artisan Build. See you next week.


r/symfony 21d ago

Symfony YAML Security Audit - Shielder

Thumbnail
shielder.com
1 Upvotes

r/symfony 23d ago

An iOS app to open & view local .html files on iPhone/iPad — for eyeballing Twig-rendered output saved as HTML

0 Upvotes

If you save a rendered page (or any .html) and open it on an iPhone, iOS shows raw source — there's no native HTML viewer. I built a small one that renders it.

Html Preview:

• Renders .html / .htm / .xhtml via iOS WebView (real page, not code)

• Handles multiple encodings (UTF-8, Windows-1252, ISO Latin-1)

• Opens from Files / Share Sheet / Mail

• On-device — nothing uploaded, no tracking

On the App Store: https://apps.apple.com/app/id6760443436

Site: https://html.cybergame.ai/

Handy for eyeballing a rendered template or a saved page on a phone without deploying. How do you check HTML output on mobile?


r/symfony 24d ago

Composer in Docker: best practices for production images

Thumbnail
nth-root.nl
1 Upvotes

r/symfony 24d ago

Weekly Ask Anything Thread

2 Upvotes

Feel free to ask any questions you think may not warrant a post. Asking for help here is also fine.