Symfony in Review: My Opinion on Recent Developer Experience Updates
Symfony is a technology I've worked with since 2017 on different projects. It's always been my go-to framework in the PHP ecosystem - I've always liked how modular it is and how it has evolved over time. It's no secret that even at Nelisa, Symfony is an integral part of our tech stack. I wrote a blog post two years ago about Symfony 6.3 features and how they help us with concise code. The framework has noticeably evolved since then, and I want to discuss it in today's post.
The evolution of the codebases I've worked with aligns with Symfony's natural progression, highlighting the framework's focus on separation of concerns, meaningful DX improvements, and genuinely useful components. A significant influence was also PHP itself - how it evolved as a language. Overall, I like where Symfony and PHP are heading, and I appreciate the path it took to get to where it is now. Here are some key features that have been integrated into the framework, playing a crucial role in how I leverage its capabilities.
Besides major updates, there are many DX improvements that came out in Symfony 7.3. These are mostly conveniences for existing parts of the framework, like the improved MapQueryString
attribute, native adaptation of PHP Lazy Objects, and using log channels per exception. There are many more minor improvements. I recommend checking out the Symfony blog for more details.
Stateless CSRF
A significant feature introduced in Symfony 7.2. A classic problem with traditional CSRF in Symfony is that it depends on sessions. This isn't a huge issue by itself, unless the application runs in a replicated setup and uses centralized session storage like Redis / Valkey.
I typically set a time-to-live (TTL) for sessions and enable the "Remember Me" feature. This approach refreshes the session and allows the project to function properly without requiring sticky sessions or other workarounds. However, it has one significant drawback: if a user submits a form after their session expires but before it's refreshed, the CSRF check fails and their submission may be rejected. This can become a serious issue in certain scenarios.
Stateless CSRF effectively solves this problem. However, this approach has its own drawbacks. It relies on cookies and Origin/Referer headers, which can cause bugs or inconsistent behavior when not configured properly, especially when running behind a reverse proxy. More information about this feature is in this Symfony blog post.
ObjectMapper Component
A component that was introduced in Symfony 7.3 as an experimental feature. As the name suggests, its main purpose is to bridge the gap between mapping of different objects. It allows us to use conditionals and renaming via attributes, which is handy, and it also includes formatter support.
I think this is a powerful addition to the framework. If I want to have a clear separation of concerns - let's say between application layers or between domains - I am inclined to use DTOs or value objects, and in services I usually use information from these objects to create or update entities. This component can reduce a lot of boilerplate code and/or factory methods while keeping things tidy. I hope this component will make it to the stable phase and that it will be further extended. More about this feature in Symfony docs.
JsonPath Component
Another experimental component from Symfony 7.3. This one allows us to query and extract data from JSON via JSONPath expressions. Before having this component, I usually decoded JSON and used PropertyAccess component. Thanks to this addition, I can work directly with JSON when needed. I like that it supports multiple approaches - querying via expressions, via fluent interfaces (building queries programmatically), and filtering as well. The component also comes with a bunch of assertions for testing. More about this feature in Symfony docs.
JsonStreamer Component
This experimental component, introduced in Symfony 7.3, focuses on JSON encoding and decoding in a very fast and efficient manner. It's a lot faster than the Serializer component while using significantly less memory. It works very well with DTOs and value objects and is a better fit for performance-demanding scenarios. It also allows value transformation, which is great for advanced scaffolding. More about this component in Symfony docs.
Although all new components are still experimental, some of them are already being integrated into projects like API Platform, so I believe they are here to stay. I like the direction where Symfony is headed - it goes in the direction of performance, better developer experience, and all these additions help me write better code with less boilerplate. I look forward to seeing what's coming next!