Upgrade to Pro — share decks privately, control downloads, hide ads and more …

2025: Performance Milestone for the Symfony eco...

Avatar for Antoine Bluchet Antoine Bluchet
November 27, 2025
110

2025: Performance Milestone for the Symfony ecosystem

This presentation, "2025: Performance Milestone for the Symfony Ecosystem," dives into the evolution of Symfony, its commitment to performance, and the components driving its future.

Key Topics Include:

20 Years of Symfony: Tracing the framework's journey from a rigid full-stack solution (v1/v2) to a flexible, performance-focused component system (v4+).
Modern Performance Components: A deep look at new components like the JsonStreamer for minimal memory usage and 10x faster serialization of large JSON volumes, and the ObjectMapper (7.4/8.0) for improved handling of nested classes and lazy loading.
API Platform Integration: Showing how these new components are used within API Platform.
The PHP Revolution: Celebrating 30 years of PHP and exploring modern performance gains, including the use of FrankenPHP in worker mode to achieve significant gains over traditional NGINX + PHP-FPM setups.
Future Optimizations: Highlighting ongoing work in the Object Mapper and Serializer components that promise up to 50% and 87% performance improvements, respectively.

This talk is essential for developers interested in high-performance PHP, modern Symfony development, and the future of API creation with API Platform.

Avatar for Antoine Bluchet

Antoine Bluchet

November 27, 2025
Tweet

Transcript

  1. 20 years of Symfony ✔ From Symfony 1 to Symfony

    4+ ✔ Innovation and Backward compatibility ✔ Flex ✔ Adaptable and performant
  2. Dependency Injection use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Dumper\PhpDumper; $container = new ContainerBuilder();

    // ... register services and parameters ... $container->compile(); $dumper = new PhpDumper($container); file_put_contents('Container.php', $dumper->dump());
  3. ✔ streaming JSON interface ✔ Achieves minimal memory usage for

    large data volumes ✔ 10x faster serialization and 50% less memory usage JsonStreamer Component symfony.com/blog/new-in-symfony-7-3-jsonstreamer-component
  4. JsonStreamer Caveats ✔ Error handling during streaming ✔ Only public

    properties ✔ Harder to customize than normalizers
  5. JSON-LD { "@context": "/contexts/Book", "@id": "/books/25", "@type": "https://schema.org/Book", "title": "1984",

    "condition": "https://schema.org/UsedCondition", "author": "/authors/20" } https:/ /edge-side-apis.rocks
  6. use Symfony\Component\JsonStreamer\Mapping\PropertyMetadata; use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoaderInterface; use Symfony\Component\TypeInfo\Type; final class WritePropertyMetadataLoader implements

    PropertyMetadataLoaderInterface { public function load(string $className, array $options = [], array $context = []): array { $properties = $this->loader->load($className, $options, $context); $properties['@id'] = PropertyMetadata::createSynthetic( Type::string(), ['api_platform.jsonld.json_streamer.write.value_transformer.iri'] ); // ... return $properties; } }
  7. use ApiPlatform\Metadata\CollectionOperationInterface; use ApiPlatform\Metadata\IriConverterInterface; use Symfony\Component\JsonStreamer\ValueTransformer\ValueTransformerInterface; final class IriValueTransformer implements

    ValueTransformerInterface { public function __construct(private readonly IriConverterInterface $iriConverter) {} public function transform(mixed $value, array $options = []): mixed { return $this->iriConverter->getIriFromResource( $options['_current_object'], UrlGeneratorInterface::ABS_PATH, $options['operation'] instanceof CollectionOperationInterface ? null : $options['operation'], ); } }
  8. ✓ Mapping of nested classes with promoted read-only properties ✓

    Map to embedded object with property access ✓ Bypass lazy ghost with class transform ✓ Lazy loading ✓ Cache attributes in memory (soyuka) ObjectMapper (7.4/8.0)
  9. Future optimizations ? ✔ Object Mapper (symfony/pull/61515) 50% perf improvement

    ✔ Serializer (symfony/pull/52905) 87% perf improvement (by @Nyholm Tobias Nyholm) Help reviewing!
  10. ✔ API Platform release manager ✔ Developer, biker, builder ✔

    Father ✔ Open source advocate ✔ CTO at Les-Tilleuls.coop Antoine Bluchet aka soyuka https:/ /github.com/soyuka
  11. 10 years of API Platform ✔ API Platform 4.2 ✔

    JsonStreamer component ✔ ObjectMapper component
  12. 30 years of PHP ✔ PHP 8 revolution ✔ PHP

    Foundation (2021) ✔ JIT ✔ Lazy proxies / ghost JetBrains PHPverse 2025
  13. FrankenPHP with Docker FROM dunglas/frankenphp:php8.5 # add additional extensions here:

    RUN install-php-extensions \ pdo_mysql \ gd \ intl \ exif \ zip \ opcache ENV FRANKENPHP_CONFIG="worker ./public/index.php" RUN cp $PHP_INI_DIR/php.ini-production $PHP_INI_DIR/php.ini COPY php-tweaks.ini /usr/local/etc/php/conf.d/php-tweaks.ini COPY . /app Symfony 7.4 detects the worker mode see https:/ /github.com/symfony/symfony/pull/60503
  14. Tips ✓ Cloud ready: environment variables for every configuration ✓

    Log to stderr is a good practice with containers ✓ Single container really helps with pragmatic configuration ✓ Watch mode to restart the worker in dev mode symfony.com/doc/current/performance.html
  15. NGINX vs FrankenPHP Scaleway DEV1-S (2 vCPUs, 2 GB RAM)

    Database Server: 2 vCPUs, 2 GB RAM, MySQL Benchmark Tool: wrk (on a separate DEV1-S instance) Nginx + PHP-FPM: pm.max_children = 15 FrankenPHP (Worker Mode): worker.num = 36 FrankenPHP (Thread Mode): num_threads = 36 (Worker vs. Thread) Performance Benchmark on a Sylius Application
  16. Conclusion ✔ Use worker mode ✔ Find worker { num

    } sweet spot ✔ Must read: github.com/php/frankenphp/discussio ns/1981
  17. PHP Extensions in Go ✔ Go ecosystem is awesome ✔

    frankenphp extension-init Scaffolder ✔ Declare your php functions in go comments frankenphp.dev/docs/extensions/