Pedro Gil Candeias

Symfony vs Laravel vs Codeigniter vs Plain PHP

I had a couple of hours to kill on a train journey recently and decided to compare a few php frameworks just for kicks. The goal of the test was twofold:

  • Measure performance overhead
  • Compare the coding styles encouraged by each framework

A Debian7 / nginx / php 5.5 VM was spun up using Vagrant, with pretty much the default settings. Opcache was enabled, but otherwise no caching was involved. A mysql 5.5 database was created, with a ‘custmers’ table holding 200 rows. Benchmarks were to be conducted on a page displaying the first N customers, as specified by a ‘count’ querystring parameter. A benchmark was conducted upon a static file in order to get a baseline performance reading.

Disclaimer: these tests were not conducted with anything resembling statistical rigour. And, as is the case with all things benchmarky, your mileage may and will bloody well vary.

With that out of the way…


Host:   OSX 10.8.4 / Intel i5 2.3Ghz / 8Gb / SSD
VM:     VirtualBox + Debian Wheezy / 1Gb

Stack:  nginx 1.4.2 / php5-fpm / php 5.5.0 / mysql 5.5.31

Read top $count records from the customers table and render a template with that information.

ab -c 5 -n 1000 http://bench.(*).dev/customers?count=5


Framework           ORM         Templating  Req/s       Time /req

static file         -           -           2654.53     1.884

Symfony 2.3.5       Doctrine    Twig        50.83       98.365
Laravel 4           Eloquent    Blade       54.43       92.006
Codeigniter 2.1.4   CI_Model    php         302.28      16.541
Bespoke PHP         -           php         433.33      11.538
Single file php     -           php         1624.66     3.078

Bespoke PHP was a piece of custom code consisting of a light routing library matching url patterns to anonymous functions in the style of microframeworks like Slim and Silex.

Single file php, like the name implies, was a single file with database access at the top and html mixed with php at the bottom. Just like old times.


Symfony has the greatest overhead, as expected. Every single request runs through lots and lots of classes, providing hook points for injecting code at any point; an opcode cache mitigates the problem, but there’s no way around running lots of code.

The good news is that, with PSR-0 autoloading and a decent dependency injection container, it’s quite clever about what it runs after the bare minimum. Even if you have a huge application with lots of models, controllers and assorted libraries, it only loads what it needs for each request. So yes, all of Symfony’s flexibility implies quite some base overhead, but resource consumption doesn’t necessarily grow with the application.

There’s a lot of quality bundles available at Packagist, documentation is second to none and, despite heavy development, stuff rarely breaks on new releases. When something does break, chances are someone caught it before you did and documented the solution – which is usually pulled into the next release very quickly.

Symfony configuration does tend to be quite dense and its namespacing practices do lean towards the verbose. But on the other hand, everything is nicely decoupled. Testing and reusing code comes very naturally in a Symfony project.

Laravel is touted as a great alternative to Codeigniter, mixing its simple interface with the power of Composer-driven package management. It uses a LOT of Symfony components, to the point where I find using Laravel is a bit like running Symfony with different ORM and templating engines. It sits somewhere between Silex and Symfony in complexity and available toolset.

Why they introduced yet another ORM and templating engine, though, is beyond me. Blade has an inconsistent interface, using brackets for output and @ signs for control structures. Eloquent is… a bit weird. Better than Codeigniter’s active record implementation for sure, but it felt about as ugly to use. Laravel also makes extensive use of Singletons, which I find very strange in a framework that’s based on Symfony. Singletons are a bit of a cheat, essentialy serving as global variables. They have their uses, but have little raison d’ĂȘtre when a dependency injection container is available.

I was a bit surprised at Laravel benchmarking neck and neck with Symfony in terms of speed. But considering both frameworks are based on the same foundation, this test was quite simple and Symfony only loads what it needs, the results make sense.

Codeigniter benefits tremendously from its inherent simplicity in this sort of benchmark. In this scenario, CI executes little else beyond database initialization and route matching before calling the controller so it does go like the clappers as advertised. Trouble is, it’s not very bright. Its router has no knowledge of HTTP methods other than GET, its request handler only adds POST to that list, there are no options to serialize responses to anything other than html and it proudly advocates plain old php as the templating engine. Which is a fine choice if you’re looking for raw speed but not very good for maintainability at all. And the less said about CI’s idea of an ActiveRecord implementation, the better.

Then there’s the killer. Codeigniter, having no idea the PSR0 exists or even that php5.3 is out, does not employ namespacing. To prevent class name collisions, its core classes have silly olde style names like CI_Model and CI_DB_MySQL. And should you wish to use libraries, or plugins, or helpers, which so far as I can tell differ only in the folder they’re installed in, you must declare them all in the bootstrapper. Which duly loads them to memory. It’s easy to see how this can become a problem on larger applications with lots of libraries.

On simple projects, Codeigniter is good enough. On more compelex ones, its shortcomings can be overcome by simply relegating it to the role of router and using Composer to install a better ORM, an actual templating engine, whatever libraries are needed, etc. But then why use CI at all? It’ll just be a bad router getting in the way of your application.

Codeigniter was great in its day. That day is now well and truly past, and no amount of Hello World speed can make up for its flaws.

Closing words

The very act of using a framework is a choice of convenience over speed. Frameworks bring order to chaos, speed to both early and late stages of development. That convenience costs performance, but we use them anyway because, in most places, developer time is way more expensive than server time. In most places, most of the time, you can easily add more servers to your frontend cluster or beef up your database machines. But hiring new skilled developers is hard enough; convincing good developers to work in messy, unstructured codebases these days is a hard sale indeed.

I like Symfony. It makes development logical and, dare I say it, easy. I’ve been using it for most of my personal projects and all of my freelancing ones for over two years now. There’s a steep learning curve, but the exceptional documentation makes it easy to climb. And it encourages the use of good programming practices like inversion of control, dependency injection, single resposibility principle, and more. Performance wise, commodity servers like DigitalOcean’s $5 vps can run it at well below 100ms per request under moderate loads, making scale issues moot for web apps in their early stages. I wouldn’t run an ad network on it, though.

If I did have to deploy something like an ad network in php, I’d probably go for bespoke code on the frontends but code the backoffices in Symfony simply due to how good the toolset is and how maintainable Symfony projects end up being. I’m not convinced Laravel, with its limited configuration options and opinionated development practices is a better choice, especially since it doesn’t bring a significant performance boost to the table. It may be easier to get into, though, which is in itself a huge plus and just might make it the right framework for many projects.

As for Codeigniter, well, we have a big project running on it at work and lets just say thing aren’t getting any easier.

Reusing My Own Code With Composer


Composer is a package manager for php that’s gained a lot of traction lately. It ties in nicely with version control systems like git, greatly simplifies dependency management, and has a lot of great packages at Packagist.

Symfony, an extremely popular php framework, has been using Composer since version 2.1, which is only logical as both tools leverage the PSR-0 interoperability standard. Silex too, Symfony’s lightweight brother, uses Composer for installation and dependency management.

In practice

Which brings me nicely to a product I’m currently building. It’s a landing page platform for online marketing campaigns, and it’s split in two sub-projects:

  • The client and administration backoffices, made in Symfony;
  • A separate website in Silex just for serving the landing pages and gathering data.

Both websites are written in php and talk to the same database, which means there’s a clear opportunity for reusing the database access code. I could simply copy my Symfony entities over to the Silex application, but then I’d need to keep track of changes in my head and manually ensure both projects were up to date.

Or I could move the entities into their own bundle, turn it into a separate project versioned with git, and use Composer to install and manage it in both websites like a boss.

Isolating the entities

I began by moving them into a separate bundle called simply My\EntitiesBundle, dropping them nicely in the src/My/EntitiesBundle/Entity folder and running a quick find & replace to update their namespaces and all the use statements. Because Symfony2 bundles follow the PSR-0, I was already halfway done.

Creating a package

1) Move the bundle somewhere outside of the Symfony app. This will be the package.

cd {symfony root}
mkdir -p ../entitiesbundle/lib/My
mv src/My/EntitiesBundle ../entitiesbundle/lib/My

2) Then create composer.json at the package root

    "name": "my/entitiesbundle",
    "type": "library",
    "description": "Doctrine entities for the Tranquility project",
    "license": "private",
    "authors": [
            "name": "Pedro Gil Candeias",
            "email": ""
    "require": {
        "php": ">=5.3.0",
        "friendsofsymfony/user-bundle": "*",
        "doctrine/orm": "~2.2,>=2.2.3",
        "doctrine/doctrine-bundle": "1.2.*"
    "autoload": {
        "psr-0": {"My": "lib/"}

Notice the require property. It tells Composer which packages this one depends on, so that it can install them. A php version can also be specified; Composer doesn’t handle php upgrades but it can throw an error if it finds the current php installation doesn’t match the requirements.

Also notice the autoload property. It’s there to tell PSR-0 compatible autoloaders that the My namespace maps to the {bundle root}/lib folder.

3) Initialize a git repository for the package

cd {package root}
git init
git add .
git commit -m "Initial commit"

Composer leverages git tags and branches, mapping them to version and stability levels. This lets you specify exactly what version you want for your project.

In recap, I ended up with this file structure…

entitiesbundle/      Doctrine Entities (Composer package)
  |_ .git
  |_ .gitignore
  |_ composer.json
  |_ lib/
    |_ My
      |_ EntitiesBundle
        |_ ...

… and a package ready for distribution. If I wanted to I could now push it to github, bitbucket or pretty much anywhere else: Composer can use repositories other than Packagist, as we’ll see in a minute.

Installing the package

Time to tell the Silex app to install it. This meant of course opening its composer.json. I should explain both packages and projects use that file. The one in a package holds its metadata like name, author identification, namespace and dependencies; the one in a project is basically just a list of dependencies. This is what the file on the landing pages project looked like initially:

    "require": {
        "silex/silex": "1.0.*@dev",
        "twig/twig": ">=1.8,<2.0-dev",

Pretty simple, basically just requiring silex and twig. They both declare a bunch of dependencies of their own, but Composer resolves and downloads all that for me.

Here’s the file after declaring my package:

    "repositories": [
            "type": "vcs",
            "url": "/Users/pedro/project/tranquility/entitiesbundle"
    "require": {
        "silex/silex": "1.0.*@dev",
        "twig/twig": ">=1.8,<2.0-dev",
        "my/entitiesbundle": "dev-master",
        "dflydev/doctrine-orm-service-provider": "1.0.*@dev"

That repositories bit tells Composer where to look for packages in addition to Packagist. In my case, it’s a local path under version control.

"my/entitiesbundle": "dev-master" is the line that actually declares my package as a dependency. "dev-master" tells it to pick up whatever’s in the master branch, regardless of stability.

"dflydev/doctrine-orm-service-provider": "1.0.*@dev" is a nice service provider for Silex (also Pimple and Cilex) that simplifies the use of Doctrine ORM. But that’s beyond the scope of this piece.

Fun time

cd {silex root}
composer update

And we’re done! Assuming the Doctrine ORM Service Provider is set up correctly, I can now reuse my doctrine entities in the Landing Pages sub-project. Whenever I make a change to them, just have to commit it and run composer update. This last step can be automated with a post-commit hook.


We all know code duplication is bad and modularity is good. The adoption of PSR-0 goes a long way towards making code distributable and therefore reusable, but by itself is insufficient. A good package management tool like Composer helps in that regard.

Building modular code also encourages the developer to think of a web application not as a tightly integrated stack, but as a collection of components each doing a specific job. This is good because decoupled code is testable code. And testable code, covered by a good test suite, saves time on any non-trivial project under active development.

Reusing my Doctrine Entities in the Silex sub-project might not have been strictly necessary, as I could have simply queried the database directly, but it was a great way of learning about Composer from the perspective of actually building packages for it and made me reflect on practical ways of implementing modular design for my code.

Introducing Clarity


Team chat apps are all the rage these days, and little wonder.

The larger the team, the more difficult it is for everyone to be on the same IM network. Plus, IM is awkward for more than two people. And good luck keeping logs when everyone keeps switching from mobile to laptop and back.

Enter web chat apps.

Because a web app runs on the browser, there’s nothing to download. Just log onto a website and you’re good to go. Plus, logs are saved automatically in the server and, as a bonus, chat rooms can be persistent.

Sadly, having sampled quite a few offerings, I think there’s a problem. Some apps are too complicated, offering many features but requiring you to learn yet another formatting system. Others are very expensive. Still others can’t decide whether they’re free or not. Some impose a team member limit. Others only allow a few simultaneous connections. All in a bid to sell you “extra features” and squeeze a few more dollars just so you can have a normal chat experience.

So I went ahead and made Clarity, a simple team chat web app with a simple pricing model (just $9/month per project) and no limits on users or chat rooms. It’s real time, so you can have normal chats with your colleagues, and it’s also persistent so people can communicate with their team without everyone needing to be online at the same time. Chat history is persistent too, so it’s always possible to recall what was said.

It’s online now.

Google Glass

Google Glass looks like an amazing piece of kit. But do I want one? Well…

  • It looks ridiculous.
  • It’s a huge privacy concern for other people.
  • Issuing voice commands in public is silly.

So no, not keen on wearing it in public every day at all.

In private, though…

  • Taking in on a trek through unknown country seems potentially useful.
  • Summoning a manual or an example video while working on my mountain bike would be nice.
  • Wearing this under my paintball goggles in order to access map and tactical information would be awesome.

So yeah, I guess I want one. I just won’t be seen wearing it.

On Ignorance

So I just watched a couple videos of some pasty spanish dudes explaining that they love veganism because of photoshopped sci-fi landscapes. I’m revolted at the degree to which their message is engineered for maximum dramatic effect at the expense of factual accuracy.

By carefully peppering a few crumbs of truth across an argument, it’s possible to make all of it come across as truthful by association. An audience that’s not in full posession of the facts will easily be swayed by such arguments and intelligence makes little difference.

Preying upon ignorant audiences is easy and entirely too effective. The only defence is knowledge.

Don’t be a puppet. Always be learning.

Coming to Work on Out of Office Day

Today is, apparently, Out of Office Day here in Portugal. It’s a movement to raise awareness on remote working and as such I think it’s a brilliant idea.

Indeed, I’m always going on about how mandatory office attendance and rigid 8+ hour workdays are not at all suited to today’s information economy.

But I don’t like to do things just for the sake of it. And I don’t think that working remotely should be some kind of dogma. I believe in choosing what’s best for one’s needs.

So I chose not to adhere to Out of Office Day because it just happens that today I’d like to see my peers face to face and float ideas around, hoping for the sort of conversation that arises more easily when people are in the same vicinity.

I’m just glad I’m allowed to make that choice.

Schools Should Teach How to Code

There’s a reason why programming is done in something called a language. Programming is a form of communication, in which one tells machines what they must do.

Many years ago in my country most people worked in fields and factories. Bills were only passed to make elementary education mandatory when it became clear that workers needed to be literate enough to understand instruction manuals for the machinery they operated.

These days, jobs are disappearing and many believe they’re gone for good: many tasks are simply done faster and better by robots and/or computers. Those who don’t speak Machine are at a distinct disadvantage, having to rely on programmers to tell their computerized servants about their business requirements.

Learning to read and write doesn’t force you to become a professional writer, they’re just skills that help with whatever it is you choose to do for a living.

I think it’s much the same with programming, so schools should teach kids at least the rudiments of code. I know I’ll teach mine.

New Blog

I’ve been meaning to build my own blogging app for a while now. Something simpler than my current blog at Posterous, without all the client-side scripts and extraneous social features.

Now that Posterous is shutting down, I’m out of excuses. So here it is. Check out the source.

By the way, my old posts from Posterous can be found here: