The silly Laravel versus Symfony articles

 

This silly battlefield image is AI created and reflects Laravel vs. Symfony articles.
Sometimes reading low quality content is amusing. And when it comes to blog articles with comparisons between Laravel and Symfony most of these articles are of very bad quality. They are often very amusing for the fact that the writer of the article clearly has a preference for one of the frameworks. They contain many bad reasoning or things that the user considers not subjective. Still they are interesting to a level that shows what other programmers are struggling with a specific framework.

My personal background

Every programmer has a background that influences their choices in a framework. When I started my professional career I started with Symfony 1. The Symfony framework everybody knows nowadays is actually a full rewrite of Symfony 1 where they ditched all bad architecture designs. The most obvious ones was the overuse of singletons and use of inheritance for all the database entities with an active record ORM (a very early version of PropelORM, which happen to be also completely rewritten again).

When I switched over to Symfony I suddenly had to learn lots of new functionality and different way of thinking. But it developed me as a programmer as I tend to write my code testable and try to do it framework agnostic and everything with dependency injection.

So when I learned Laravel my first impressions were very negative as I saw the bad, untestable architecture choices first. How could someone with the right mind ever prefer this over Symfony?

However after some working with it I started to see that there is more than just testability of your code as in the end you just need to write a working application, which Laravel does deliver. And in the end I see that Symfony adapts to architectural choices made in Laravel and the other way around.

Auto-wiring

A good example is auto-wiring services. In Symfony you used to have to register every service manually in a services.xml or services.yaml which is a custom format used by Symfony (and means the learning curve is higher than Laravel).
Besides many requests for auto-wiring it took some time before it was introduced in Symfony; Fabien Potencier (the main developer behind Symfony) never wanted this as he was afraid the application code was getting too much dependency on the framework. It is also hard to perform in development since a code change rebuilds the service container.
However after Laravel implemented it, it seems Symfony learned from it and introduced it as well.

The differences between auto-wiring are minimal, but the biggest difference is that in Symfony you need to setup which classes should be auto-wired and which should not. This makes Laravel looks easier but the real issue is with a certain consequences of these choices. For example if I have a controller in Laravel with a eloquent model argument, it will not work properly if the SubstituteBinding middleware is not enabled as it will fallback on making the eloquent model a service. This could lead to some nasty bugs and probably data corruption.
In Symfony a misconfigured controller argument will lead in an error that you did something wrong so the chances are low this would ever be deployed in production.

The silly performance tests

A large amount of blog articles do performance tests between the frameworks. Often the setup of both applications written in Symfony and Laravel gives me so much questions that I consider these performance tests quite questionable.
  • Often the Laravel example is using Eloquent as ORM and the Symfony example is using Doctrine. This means you are effectively benchmarking Doctrine/Eloquent at the same time. With the extensive use of reflection and keeping track of all entities in the unit of work for Doctrine, Doctrine is always significantly slower than eloquent.
  • Symfony outperforms Laravel in the kernel the moment opcache is enabled as all caching files are executable php files. The moment you do not have opcache configurd properly Symfony will have worse performance.
  • Many of these tests mention nothing about running it in development or production mode. For example Symfony runs the webprofiler in development mode, but this makes request 4 times slower.
So if you want to say anything about performance the only thing you can investigate is how Symfony and Laravel work behind the scene.
  • Symfony outperforms Laravel in the service registration part in production mode as Symfony will only calculate this once and will get this back almost instantly because it has become a hardcoded class. With Laravel the service binding is always dynamic and will always be re-evaluated with every request you make.
  • Development mode is a different story: there is so much logging and file modified change checks that Symfony will always be slower than Laravel.
  • Eloquent is MUCH faster than Doctrine, but it has no transactions out of the box. Doctrine will always check all entities it has retrieved or persisted for changes which takes a lot of time but at least the programmer does not have to think for himself in which order it should save his entities.
  • Symfony routing is the fastest routing system written in PHP after it started using the strategy of the fastroute library, but it is also more rigid as it caches the url matching in a auto-generated PHP file. With very dynamic routing Symfony routing should not be used. Again this has some serious implications on benchmark tests.

The template engines

The template engines are another 'criteria' I often see in these blog articles. Symfony uses Twig and Laravel uses Blade as template engine.
If the article writer prefers Laravel, Blade always wins from Twig as you can always use PHP in your templates. And if the article writer prefers Symfony, Twig always wins because Twig never allows you to use php directly. In the end it's often a preference from the developer.

I do have some negative experience with Blade and upgrading a project with blade components from Laravel 6 to 7 where they decided to change them in the HTML from @component to <x-component>. No error was thrown when you were using the old solution.
For Twig the sandboxing is sometimes annoying as I need to write a twig extension to have access to a regular php function. Some php functions are already available, but they are often under a different name then the php function, so you need to read the documentation to get around this point.

Conclusion

I think both frameworks are getting better and learn from each other. Without Laravel Symfony would keep it at configuring services in services.yaml and no auto-wiring. And Laravel is getting better in upgrades and testability. In the end both frameworks get the job done.

There are still some things I do notice for both frameworks that are the critical differences between the frameworks that result in a programmer having a strong preference to one.
  • Symfony enforces you to use good practices and punishes bad design choices. If you are a less experienced developer this could feel intimidating and increases the learning curve. Don't know dependency injection? It's fine in Laravel as an inexperienced user will love Laravel facades to use as a service.
  • Symfony requires more operational skills to run highly efficient and could lead to a very sluggish application, while Laravel performs fine.
  • Symfony also loves to throw errors if you have a misconfiguration. Laravel will just silently ignores this and continues executing. Missing environment variable? Symfony will not run the application. Laravel will just execute and send null to  your poor service.
  • Symfony loves to overuse annotations/attributes to configure a class, Laravel just don't like making objects and prefers using typehint-less arrays. It depends on the developer what you prefer.
  • In Symfony you have to follow SOLID, so instead of inheritance you define an interface and put final on your actual class implementation. In Laravel you use inheritance and lots of traits for reusability. On popular Laravel sites it even tells you about the unfinalize package to remove those annoying final keywords. The package also has suggestions on github to make private properties protected.


Comments