PHP 5 Framework Comparisons: Bootstrap
Taking a look at the bootstrap process
Posted 8 months ago by Tom Maiaroto.
So when I first picked up the Lithium framework for PHP, there weren't a lot of options out there. I mean Lithium really started jamming on the new features of PHP 5.3+ almost as soon as they were available. I think Symfony2 was quick to come on the scene as well, but now...There's a bunch.
I see a lot more buzz around these modern PHP frameworks (as I like to call them, and what I mean by that is any framework using namespaces, new PHP 5.3+ features, maybe it's closures, etc.). So I think it's a good time to start evaluating the landscape a little bit. In the least I enjoy watching how it evolves. Who borrows from who, which communities get larger, which features are most revered, etc. This is no different than really any point in history with open source PHP be it frameworks or content management systems.
So I'm going to write a series of articles with observations and comparisons. To be clear I'm not trying to hate on anyone's work or sit here and tell you which is the best (or which I feel is the best). I feel this particular kind of research and advancement in PHP land is super important for everyone. Ok, overview out of the way, let's get on with it.
The Bootstrap Process
I think this is a good thing to look at for any framework. It's essentially the same as looking at starting up a car and watching how it idles. You can tell a lot from how a car starts up and idles if you know what to watch and listen for.
I'm taking a look at the following frameworks in this study (linked to the call graphs):
What am I looking at? I'm using webgrind to look at the function calls, the call graph, and to a lesser importance the load times. Testing performance in terms of "time" is not really an easy or fair thing to do to be honest. A lot of people do it, but to be frank fractions of seconds don't really make or break any application that I've ever heard of. Plus you really don't know what a developer's own code does or how it will change the load times and your testing machine is not a web server, you have other things going on that skew results. Last note on the subject - your caching strategy can evolve over time and greatly affect performance as well.
Why are function calls and the call graphs so important? Well, for starters, all applications must go through this bootstrap process. This comparison doesn't care what you pile on top of the framework. So if you're concerned about scalability and performance, this is something you should consider because it is an out of the box process you can't avoid (perhaps you can trim it down if you modify a few things).
I also look at two loads. One is a cold bootstrap process without anything cached. The second load does include cached assets, etc. My server is using APC as well. So the warm bootstrap is really what you should consider under normal operation. Why bother with the cold? Well, by comparing the two, we can see what the frameworks like to do in order to cache and optimize their bootstrap process. This, perhaps, helps us draw conclusions about how invested a framework is in performance and optimization.
The call graphs are also interesting to review because it tells us a lot about the architecture of each framework and how they are solving certain problems and performing common tasks for a web application.
Without further explanation, here is a quick chart that will show you each framework's bootstrap process in terms of number of functions called and execution time (again take the times with a grain of salt).
The colors? Blue are internal PHP functions, gray are includes/requires and your autoloading stuff (caveat here, Symfony2's cold bootstrap process seems to hide this), green represents class methods being called (this is the actual framework code given we're dealing with OO code here), and orange are procedural functions which are here and there and likely everywhere in any application (however aren't the bulk of what's being called).
Laravel seems to call the most functions in order to bootstrap an application. Keep in mind it actually loads a lot of Symfony2 classes as dependencies. From looking at the call graph, you'll notice that there's a lot of autoloading going on (same goes for Symfony2 unsurprisingly). I believe you also see more function calls in any framework or application that contains an event dispatcher. This is because of all the dispatch calls (which are called fire() in Laravel) and other functions surrounding an event system. Bare bones Laravel only calls its fire() method 4 times. How will this change after you put your application code on top? It'll vary of course, but keep that in mind. The last thing to note about Laravel here is that there appears to be no view caching. I know there's ways to go about this and if you subscribe to its "blade" templating system you may have more options available to you out of the box, but the framework has a ways to go on this front. A lot of philosophy still circulates around the belief that caching a view result is not desirable. So your mileage will vary and I do believe you can squeeze extra performance out, but it will be up to you and not out of the box. It's also interesting to note that on subsequent loads of Laravel, the function calls slightly increase. This isn't too alarming in my opinion because it's only slight, but one may be interested in diving deeper into as to why this is (no the charts weren't accidentally flipped I double checked). A guess as to why this is? Caching mechanisms in anticipation of optimizing additional code added by developers and future performance gains through these new function calls. Would make the most sense (and I hope something like that is the case).
I know the image has Symfony2 last, but since Laravel is so closely related with Symfony2 I'll write about it next. It weighs in next too with the second most function calls required to bootstrap an application. I of course profiled a simple hello name (Symfony's example) page with this in the production environment. It would be unfair to test under production due to all of the lovely and helpful utilities that Symfony provides (cool toolbar and such). Symfony2 does a pretty awesome job of caching what's going on and I believe the framework values caching more than Laravel from a "we're going to try to do it for you automatically out of the box" perspective. Symfony's call graph is pretty straight forward and easy to follow too. It is far less complex than Laravel's. A quick glance at each of the call graphs is actually pretty telling about the process and organization of each framework. Like Laravel, there's a whole lot of autoloading going on with Composer. Well over a hundred calls right there. This is where the two frameworks are quite similar in their process (aside from Laravel borrowing from Symfony2).
FuelPHP is the lightest among all of these frameworks here. No surprise here if you've browsed their documentation and API. It is a very lightweight and modular framework by design. Like Laravel they also got creative with some of the function names and really make you feel like driving views is a tough cumbersome job. I think Laravel and FuelPHP are very similar in this regard, there is a lot of emphasis and tooling around the render and template process. They both like the idea of view models for example. Like all frameworks in the bootstrap process, autoloading is a big part of what's going on, but FuelPHP doesn't outsource this job to Composer for its own needs if you look at its call graph. It'll rely on Composer for external library loading (except for FuelPHP packages of course written specifically for FuelPHP and if you look into it's Autoloader class you'll see what's going on with Composer and fallback loading); however, there's this internal loading process going on. In this regard FuelPHP is similar to Lithium. As a result of internalizing this process, there are less calls when it comes to loading things than there are in Symfony2 and Laravel. Less than half actually depending on how you look at it. There's a lot of checks for the existence of classes and then about 27 in this case (this changes as the framework changes and as you add your stuff on top) calls to its autoloader. That's a less than a quarter of what you see with the frameworks relying more on Composer. Keep in mind this isn't necessarily Composer's fault, we need to keep in mind the size of each framework's API and the organization of the API. There is an obviously smaller footprint for FuelPHP out of the box.
Lithium is similar to FuelPHP in that it has its own autoloader. In fact Lithium's autoloader is quite sophisticated and can transform libraries with non PSR-0 classes to more of a standard. Of course nothing prevents you from using Composer with Lithium either. So why not just use Composer? Why the emphasis on this robust autoloader? Lithium was created before Composer was popular (or even existed?). It was quick to adopt PSR-0 and has remained a firm supporter of the standard. To be clear, all of these frameworks are firm supporters of PSR-0, but once upon a time other things in PHP land were not all on board yet. Lithium's bootstrap process isn't quite as lightweight as FuelPHP's, though it is certainly calling less than half of the number of functions as Laravel and Symfony2. Again I told you to take time with a grain of salt, but if you loosely look at the load time, you can tell that Symfony2 and Laravel are going through more costly operations than FuelPHP and Lithium. I believe Symfony2 does a better job mitigating what's going on in this regard with caching than Laravel. Lithium also values caching greatly and does cache its view templates out of the box.
If you were to look at Lithium's call graph, you might notice more time spent on closures. This is because Lithium has its filter system which introduces aspect oriented programming practices into the framework. Rather than an event dispatcher system, which you'll find in Laravel and Symfony2, Lithium covers most of its API in a filterable system. This allows you to intercept functions and solve your cross cutting concerns in an elegant way. This is, arguably, a more efficient alternative than dispatching a bunch of events. It also leads to greater control over each method whereas you end up a bit limited with your "before" and "after" callbacks in a typical event dispatching system. Of course with great power comes great responsibility...So it's also quite easy to create a mess if you're not careful. Debugging has also been criticized, but I personally don't find debugging any PHP application under any framework all too challenging. If you're used to swashbuckling and debugging PHP, then I don't think closures present a huge challenge. If you're coming from another language, then I can understand the gripes.
I hope that I've been able to shed some light on how each framework's bootstrap process differs from a mile high perspective. I'm not going to say one is better than the other. I firmly believe in personal preference. However, I also believe a framework should start off pretty lean. It should be a focused spearhead and not a broad feather. I think FuelPHP and Lithium sit in the spearhead camp for flight and dynamics where Symfony2 and Laravel sit in the feather camp for flight stability and dynamics. If that analogy makes sense. Or use a bullet vs buckshot analogy if you like. Rest assured they all get the job done. They just go about it through different means. Which do you associate more with?
As far as autoloading is concerned, look at the massive shift toward Composer, right? If you look at the timing here you'll see how some frameworks adjusted to accommodate Composer and how others straight up decided to rely more heavily upon it. Certainly speaks volumes as to our value of Composer as a PHP community.
It's also a good topic in and of itself. As Composer changes, how will it affect the bootstrap process of all these frameworks out there? I think that's actually a pretty important thing to watch out for.
In future posts I'll get into different common aspects of the frameworks such as the rendering engines, design patterns, and other conventions each framework leads the developer to use. I'm going to go through the process of building a simple, consistent in functionality, blog in each framework. Keep in mind that each of these frameworks are flexible and by no means should you, as a developer, ever feel restricted. If you feel suffocated or restricted by a framework, I think that's when you may wan to look into another one.
Filed under web developmentphpreviews and opinions
Search for Posts
Popular Labelssocial media virality score general internet web development reviews and opinions php web tools hosting lithium web design
- 16 Jun Social Media Analytics on a Budget
- 15 May Thinking About Using Laravel?
- 22 Apr Why Dart?
- 16 Jan PHP 5 Framework Comparisons: Bootstrap
- 02 Jan GitHub Issues Feels
- 23 Dec News Ox: Building a Better News Aggregator
- 18 Dec Discovery and Ranking
- 12 Dec Viral News Search
- 06 Dec Flexible Twitter Bootstrap Grid
- 04 Dec Problems With Google Analytics