When facing the start of a brand new PHP application, there is one decision that can’t be overlooked: which framework should you use?
Theoretically, you could start with none, but assuming the project at hand is anything but trivial, that’d probably be a bad idea.
The good news is you’re not exactly short of options to choose from.
The bad news is you’re not exactly short of options to choose from, which can make the decision a little harder than you might expect.
At a glance, there’s one main difference between Symfony and Laravel which is that Symfony is both an Application Framework and a set of reusable components, while Laravel is simply a Framework. In fact, Laravel uses quite a few of Symfony’s components.
For the purpose of this post, I’ll refer to Symfony as a Framework but keep in mind that, because of how it’s built you should consider it a meta-framework.
In the following sections, you’ll learn the similarities and differences between them and how to choose the one that best suits the needs of your project.
Points We Will Cover in This Article
- What they have in common
- Installation procedure
- Directory structure
- CLI tool
- Template Engine
- Framework Extensions
- Project governance
What They Have in Common
Needless to say, the first similarity you’ll notice is that they are both PHP frameworks.
But that’s just the beginning. Here are the most outstanding features of both:
- Open Source projects
- Based on the MVC pattern (which means there are no big conceptual differences)
- A CLI tool is available for common tasks
- Code is organized in a particular way
- Testing tools are available
- Cover the full stack leveraging existing projects (ORMs, Template Engines, etc…)
- Can be run on multiple platforms (Operating systems and database engines)
- Have built-in internationalization features
- Can be easily extended
Now let’s get into the specifics so you can get a better understanding of their differences.
Prior to running the commands, I’ll be showing you’ll have to install the following:
- PHP 7.2+
When it comes to installation, they’re both fairly easy to start with, since both use composer, there’s not much mystery to it.
The easiest way to get a Symfony project started is by running the following command:
composer create-project symfony/website-skeleton sfTest
This will, assuming every dependency is met, leave you with a basic web application you can further customize to meet your needs.
An alternative installation method, which is actually recommended by Symfony, is to install a new binary in your system.
Should you choose this option, the command used to create a new project is:
symfony new sfTest --full
There are several advantages to using this method, one of them is you have a very handy command:
Which will help you detect and eventually fix any missing dependencies.
Either way, upon successful installation you’ll get a welcome screen telling you what the next steps are.
Laravel also offers different ways of installing, the easiest one is running the following command:
composer create-project laravel/laravel lvlTest
Another way to get a Laravel project started is by previously installing a Laravel installer (much like Symfony) by running:
composer global require laravel/installer
laravel new lvlTest
Symfony Directory Structure
If you go into your newly created project and ask for a files list you’ll get this from Symfony:
Your code is expected to be organized as follows:
- src will contain all of your business logic (Entities, Containers, Services, etc…)
- templates will hold the presentation code (mostly html-like files)
- tests will be stored in the tests directory
- migrations will be the place for database upgrade scripts
And then there are other artifacts that have a particular place in the project:
- bin is where you’ll find useful CLI tools
- vendor is where dependencies live (common behavior to every composer-based application)
- config is where the configuration will be
- in translations you’ll put the i18n related resources
- var is a directory used internally by the framework, mostly for optimization purposes
Finally, the public directory will be the point of contact with the outside world, here you’ll find the application’s entry point: the index.php file.
Laravel Directory Structure
In the case of Laravel, this is what you’ll see:
In the case of Laravel, the code is distributed along the following directories:
- app holds the core code of your application
- database is where you keep all of your database related code (Migrations, initialization scripts, Models, etc…)
- in tests you’ll store your testing code
- your templates and other static files will be stored at resources
The configuration will mostly live within config, though the URL-to-Controller mapping will be stored in routes
In the case of Symfony, the CLI tool is found at bin/console, by simply running this command:
From your project’s root directory you’ll get a complete list of available commands:
And then, if you need help with a specific command, you can run:
php bin/console help <COMMAND>
For instance, let’s look for help on make:auth command:
php bin/console help make:auth
It’s very much likely that you’ll be spending quite a bit of time using the console component if you use Symfony.
In the case of Laravel, a similar tool is available right at the root directory of your application: artisan.
If you run:
You’ll get a result like:
A very familiar look, right? The fact is artisan is built using the very same Symfony/console component, that’s why its UI is so similar to Symfony's console.
Coding in Symfony is heavily based around the concept of Dependency Injection, which creates loosely coupled classes, making testing and long-term maintenance easier.
While virtually any ORM can be used in conjunction with Symfony, the default is Doctrine, which implements the DataMapper pattern.
In Laravel, the default ORM is Eloquent which is based on ActiveRecord.
The main difference between these two models is that in Doctrine entities are POPOs, meaning they can be used in a variety of scenarios, even outside of the context of the ORM.
Eloquent proposes a structure where the Models are extensions to a base class that has all the logic for database access.
One advantage to using the DataMapper pattern is the ability to further optimize database operations by queueing them instead of immediately running them.
Symfony offers different kinds of configuration, which may be a little hard to understand at first glance.
There’s configuration by environment (.env files) which are meant to hold the very basic information for the application to run such as database access.
Then there’s the bundles configuration (YAML, XML or PHP files located within config/packages) which are meant to determine the behavior of the application in a given environment. For instance, the handling of email should not be the same in production as in testing or development.
Finally, there’s another way to deal with configuration: PHP annotations for PHP < 8 and class attributes por php >= 8. This is the most common case for routes and ORM mapping information.
Usually, a combination of all of them is used within a project.
The case of Laravel is a little simpler, there are .env files at the project root and simple PHP based files inside the config.
In Symfony, the default template engine used is Twig while Laravel uses Blade as the default template engine but you can use a different one if you choose to… you can even opt for not using one at all!
Syntax aside there are no big differences between them, though Blade is usually perceived as simpler than Twig.
You can get a more detailed comparison between both template engines in this post.
In the case of Symfony, the way to do it is by creating bundles. In Laravel’s terminology, these are called packages.
In both cases, they can be distributed as standalone code libraries which can be brought into future projects.
Installing a bundle in Symfony means downloading the code, editing the appropriate YAML file and indicating the bundle should be loaded at runtime by editing the file config/bundles.php.
This used to be somewhat complicated but nowadays, thanks to flex things got as easy as running a simple composer command such as:
composer require symfony/apache-pack
Which will take care of everything, leaving the bundle setup with a sensible default configuration.
In the case of Laravel the process is similar, just run a command like:
composer require laravel/breeze --dev
And everything you need to use the new package will be in place.
Symfony proposes the distinction between three types of tests: Unit, Integration, and Application.
The unit tests are not really specific to either one as they both rely on phpUnit for the purposes of QA for individual classes.
In the case of Integration tests, Symfony offers a base class called KernelTestCase, which extends the standard TestCase to allow the usage of the dependency injection container for testing several parts of the application at once.
Finally, the Application tests are not very different from the others in terms of code, but the idea behind them is to simulate user interactions, thus they rely on an HTTP client and a Dom Crawler.
Laravel proposes the usage of Feature tests (on top of Unit tests off course).
Feature tests aim to encompass large parts of the application, much like Symonfy’s Application tests.
In general, writing a Feature test for Laravel can be easier than the analogous for Symfony, since Laravel’s TestCase class offers a simpler API.
The performance measurement is always an obscure matter as it can be composed of many variables but most benchmarks give Laravel the upper hand when it comes to application speed.
However, Symfony is known for its many optimization options so, should performance really be an issue for you, there are levers to pull.
Symfony’s security system is powerful but, at the same time, a little complex to set up.
It allows for different ways of authentication as well as a very fine-grained permission model.
Laravel uses a rather simpler approach to security but, in the most common cases, the basic features will be enough.
Symfony supports several translation formats (PHP, .po .mo, XLIFF, etc…), while Laravel uses PHP and JSON only.
The deployment of a Symfony application implies:
- Uploading the code
- Creating the cache and logs directory and assigning appropriate permissions
- Creating environment files
- Installing third party libraries
- Building the cache
- Configuring the webserver
SymfonyCloud is a hosting service specifically designed to host Symfony applications.
The deployment of a Laravel application implies:
- Configuring the webserver
- Installing third party libraries
- Optimizing cache configuration loading
- Optimizing route loading
- Optimizing view loading
On the popularity front, Laravel is definitely the winner these days.
Here’s a comparison on Google Trends:
And by GitHub stats: Symfony has 25.5k stars and Laravel has 65.8k stars.
Another number to have in mind is regarding the community behind the frameworks: Symfony has 2394 contributors while Laravel has 2576.
The Symfony project has a very strict release calendar: you can expect a new minor version every 6 months and a major version every two years.
You can find more details about it here.
Recently Laravel moved from 6 months to a 12 months major release cycle. You can read more about this change here.
Support for Older Versions
Laravel offers both regular and LTS releases.
For LTS releases bug fixes are provided for 2 years and security fixes for 3 years, in opposition to 18 months of bug fixes and 2 years of security fixes for regular ones.
Symfony also has a release cycle based on regular and LTS versions.
In the standard versions, bugs and security issues are fixed for 8 months and LTS versions get support for 3 years when it comes to bug fixing, and 4 for security issues.
While both frameworks have extensive and detailed documentation available, Laravel’s docs are usually easier to read, understand and put to practice, while Symfony’s works better as a quick reference once you know the basics.
Which One Is Best for Your Software Development Project?
Of course, the answer depends on many factors but, in order to make a fair comparison, let’s say your team doesn’t possess any expertise in either.
Laravel was designed with RAD in mind, so in case your deadline is tight, you probably want to go with it, especially if your developers’ seniority is closer to jr. than sr.
Symfony was designed with long-term maintainability in mind, which makes it more suited for business environments.
If you’re looking at an application that will be a critical part of your organization’s success then you probably want to give Symfony a try as it will be a better base for more maintainable software over time.
Another factor to keep in mind is how easy it will be to bring new developers into your team should the need arise.
In general, it’s easier to hire Laravel developers so, unless you're willing to train new members of your team or risk delays in staffing projects, you’re going to be better off going with Laravel.
Here are a few resources to complement what you’ve just learned:
As you learned here, both frameworks are robust and mature tools that offer great features for professional and agile development using PHP.
No matter which one you choose, if you follow general best practices you can always switch without too much trouble, so pick the one you feel more comfortable with today and start building apps!