This article was originally published on the Symfony blog of my former employer, Driebit. That particular blog doesn't exist anymore (the company definitely does!), so I thought it might be interesting to republish it here.

Last week I was one of the several hundreds of PHP developers who traveled "all te way" to Amsterdam for the Dutch PHP Conference 2010. Though I had the impression that many PHP developers are using the symfony framework for their web applications, the speakers at this conference were friendlier towards the "father of the framework", Fabien Potencier, than towards the framework itself. Fabien is a much admired developer himself, who is very conscious about software architecture, latest trends in PHP development and also is aware of the importance of fully covering the framework's code with unit tests. In this article I will try to apply to the symfony framework, several comments on PHP programming and frameworks that I heard during this conference.

A few characteristics of the symfony framework don't encourage the average PHP developer to bring forth high quality code. A framework by itself doesn't ask of the developer who is working with it to fully take advantage of the whole programming language, in this case PHP. Many of the common tasks a developer has to complete, are for more than 50% provided by the framework itself, e.g. handling requests, URL parsing, redirecting, form handling, etc. The other half of the task at hand can be easily completed using a small subset of the PHP language, combined with some nice helper functions. This way, common tasks can be done very quickly, but the developer is also encouraged to complete the less common tasks, using the same familiar subset of the PHP language, and the tools provided by the framework over and over again. It then becomes difficult to switch to another framework or no framework at all, and still accomplish great things, because in those situations the developer can't depend on the familiar and very convenient framework components anymore. To stay aware of the endless possibilities of the PHP language itself, and to become not too dependent on the (symfony) framework, I encourage developers to try and learn to master their task, not only to complete the task (a phrase borrowed from Jon Jagger, see 97 Things Every Programmer Should Know). Try for example using the great Standard PHP Library (SPL) classes, exceptions and functions in your code (see Standard PHP Library (SPL)).

While learning all these great new things about the programming language, and while reading other people's code (for example the symfony code base) you'll become a better programmer. This makes it easier to refactor your code, which means implementing smarter or more efficient ways to do something. Refactoring – when done correctly – improves at once the readability, maintainability, and extensibility of your code, mostly by dividing large functions into several smaller ones and relocating parts of your code that belong to different or yet unexisting classes. Thus every method gets one small task, which can be easily understood by a code reviewer, can also be more easily changed by a developer and may also be much easier to extend, without copying the entire content of the parent method that is overwritten. All the abovementioned characteristics of good refactoring seem to be applicable to the symfony framework code base. Nevertheless, symfony's admin generator doesn't do a good job when it comes to readability, maintainability and extensibility. Every symfony developer knows this. When he wishes to change the behavior of even the smallest part of the admin generator, he almost always ends up copying large parts of the generated code and changing only small parts of it. "This is not very D.R.Y." as a critical code reviewer might say. One step in the right direction has of course been made, by providing the admin generator configuration and helper classes. These are nice examples of how the whole code base of the admin generator could and should be cut up into smaller pieces, which only handle a small part of the business logic, and thus could easily be extended by the PHP developer who is working with the generated module.

When it comes to another part of the framework, the symfony developers seem to be doing exactly the opposite. They are putting a lot of effort in decoupling and making the framework code base less explicit and more flexible. With Symfony 2, the biggest part of the framework's core objects will be created and managed by a "dependency injection container". While this allows the developer to make his own choices about implementation, some speakers at the Dutch PHP Conference worried about this tendency to "over-abstract". It is a very good thing to avoid hard coupling in your classes, but using a dependency injection container makes your application also dependent and in a sense again "hard coupled". This brings up the question if there should be a "dependency injection container factory" and there is no reason why one should not want a "dependency injection container factories factory", and so on. Except for the fact that this should make it very difficult to be a PHP developer and live happily at the same time.

Another way in which symfony falls somewhat short at the moment, is the lack of a good ORM implementation. Of course this is not really a fault of the framework itself, but as it can only be integrated with two ORM implementations, the shortcomings of these implementations reflect on the framework itself. Doctrine as well as Propel in their 1.x versions are based on the "Active Record" design pattern, in which every model object that stands for a record in a database table, inherits many properties and methods from parent classes, that handle the way the object's properties should be saved in the database table. This is bad for testing purposes, because the object and it's persistent state in the database are tightly coupled, but also brings a lot of overhead into a project. Luckily, with Symfony 2 the new version of Doctrine (version 2) will be shipped, which is a completely redesigned ORM, based on the "Data Mapper" design pattern. This means objects don't inherit from an "Active Record" class and can be instantiated apart from any connection to a database. This also means that model object classes are lean and mean and can more easily be subjected to unit tests, that they may extend other classes than the "Active Record" class and in theory may have nothing to do with persistent data in the first place. When it seems a good idea to store the object's data to a database, this may be implemented at some time in the future.

Though much of the above can be seen as critical notes on symfony, I wish to state that using symfony is in the end a great idea. It is a "full stack framework", which enables PHP developers to accomplish much more greatness than they would have been able to when only using the standard set of PHP functions and writing only PHP code that is executed serially. My comments on the framework can be "redirected" mostly to shortcomings of the developer himself or to third party software on which symfony relies. Other shortcomings will hopefully be addressed in future versions of symfony (or Symfony, as it should be spelled when the second version arrives).

One way in which symfony really makes the developer's life better, which also is a highly underrated and not too often used feature of symfony, is its doctrine/propel:data-load task and the way it allows developers to define test data in YML-files, called fixtures. One way to enhance these fixtures is by using PHP functions in them, because they will be parsed by the PHP interpreter before being loaded into the database. Thus, you can create functions for generating random strings, numbers, etc. and paste them in the fixtures, so you can easily create a lot of random objects for test purposes. Like this:


for ($i = 0; $i <= 100; $i++)
  Product_<?php echo $i; ?>:
    name: ‘<?php echo someRandomStringFunction(); ?>'

Before executing the data-load task, it may be a good idea to run the PHP interpreter

php data/testfixtures/products.yml

to see if your PHP code generates the result you are looking for (and no errors).

After that you can run

php symfony doctrine:data-load data/testfixtures/products.yml

or the equivalent task for propel.

PHP Symfony2 DPC conference
This website uses MailComments: you can send your comments to this post by email. Read more about MailComments, including suggestions for writing your comments (in HTML or Markdown).