Exceptions

I see on a lot of projects stuff like this:

function getStuff()
{
  try
  {
    return $this->retrieveStuff()
  }
  catch (Exception $e)
  {
    return null;
  }
}

The issue, in this example, is not that we silence an error. It should be logged, but there could be a legitimate use for this. For instance, it requires a connection to a remote server we have no control over, and we still want to serve the rest of the content to the user, as the information is not vital.

No, my issue it that we catch all errors, when the aim was to catch only one error (for instance “unable to connect to that remote server”). Imagine now there is a real bug in retrieveStuff(), it would still be interpreted by developers as a connection errors.

The solution is to have one exception type per error type (it sounds obvious said that way, doesn’t it?), and only catch the specific error, for instance ConnectionError.

PHP’s error handling is historically bad, and even though new features use exceptions, the legacy ones don’t. Or sometimes functions should trigger a fatal error but it is only a warning, and the code continues, which can trigger unwanted and hard-to-debug results. There are amazing plugins for Symfony that convert errors to exceptions (and warnings seem to be handled properly, i.e. they are logged and don’t cause the page to fail). It’s a start.

However, even when you get exceptions, you can’t always filter them easily. For instance, in Symfony, there are many different errors that would throw the same class. Symfony has a handful of exceptions, Doctrine has a bit more (though they can be quite meaningless!). Overall, there are defined “by module” than “by error”.

Comparatively, Python’s handling of exceptions is exceptional1. There are exceptions for everything, and most of the time errors are handled by only checking the class and not the contents of the exception. It is probably the feature I love the most about Python. With the else, finally, and with statements, it is almost a pleasure to handle errors.

  1. sorry []
Posted in PHP, Python, Symfony | Leave a comment

Why I wouldn’t use Symfony for a new project

Symfony is pretty good for a PHP framework — it’s probably still one of the better ones. While Symfony is open source, its development clearly isn’t open.

Nowadays, it is mainly unmaintained. Well, it’s maintained by Sensio, which is very closed towards outsiders, and doesn’t apply fixes for versions below 1.3 even when patches are handed ready to them. Which means for instance that the official 1.0 doesn’t work with PHP 5.3 even though the fixes are available and straightforward.

I will pass on the worrisome attitude towards security of the most used plugin as I’ve talked about it extensively already. Constant reminders don’t even work.

There is much more activity towards Symfony2, which might explain the lack of updates to the 1.x branches. Symfony2 introduces more decoupling, which should avoid many bugs reported but ignored by the development team, probably because they are boring to fix and require very deep knowledge in Symfony’s architecture — I would have tried to fix them myself if I had the time and motivation; I’m afraid I usually take the easy route and work around them.

But how does Symfony2 looks for a developer? What I’ve seen is fairly standard and boring, and sometimes looks like sad attempts of reimplementing Python features in PHP. Why not use Python then?

Doctrine2 is even worse — it’s the same broken, undocumented API. Propel 1.5, with a minimum set of changes, became much more powerful and easy to use for a developer. At least there’s hope on this side.

Overall, it seems the Symfony lead developers don’t take much input from the community (like the decision to follow Zend conventions), and focus on making something fun to write, instead of fun to use. I have the choice between an undermaintened version and a future version which will break compatibility without giving me much advantages; moreover some of the stuff that was shown in conferences isn’t event implemented yet. I’m not used to see that in the free software word.

Time to switch?

Posted in PHP, Symfony | Tagged , , , , | Comments closed

Reducing the gap between Symfony and non-PHP frameworks

Something that always annoyed me is how tedious it is to install a Symfony project on a machine. Since I frequently need to intervene quickly on a project for work, and I was getting a brand-new machine, I really didn’t want to create an apache vhost (let alone install Apache: it’s painfully slow and its configuration is obscure and hard to debug), edit my /etc/hosts file, etc. for each project.

Moreover, developers are not system administrators and should not have to do complicated setups, especially when it turns out to be badly set up, and problems are “resolved” by “chmod 777″ or “chmod 666″ (which is indeed evil), a very sad but true practice promoted even by the developers of Symfony since there is a symfony fix-perms command that basically does that. It should have been named symfony break-perms or symfony please-make-things-insecure-i-want-to-go-back-to-windows or never been made.

On most non-PHP frameworks, there is a small embedded webserver that you can run on-demand. No configuration needed. Moreover, no special rights needed: a simple user can start it.

Since there was no such webserver written in PHP that was able to run Symfony properly, I chose to auto-configure lighttpd with a simple tool called symfttpd. The genconf tool was born.

However, I encountered another issue I didn’t think of before: for each project, I had to create symbolic links to the Symfony source code (another practice of the Symfony community, and there is no proper alternative in the PHP world). Hence, I created mksymlinks. For the developer, it is very simple to use: configure once on the machine, once per project, and that’s it.

genconf only generates a configuration, which is still very practical for a system administrator; moreover it is flexible and well-tested. But it still required the develop to configure something, and there still was the rights problem.

Hence I created spawn which handles starting and stopping the webserver, just like non-PHP frameworks do. As a nice addition, it keeps server and PHP logs in the log folder of the project.

symfttpd has even more uses; one I didn’t think of at first was that it can automate the installation of a project on a continuous integration platform, and can start a webserver for functional testing (both are used daily at work).

One of the most important aspects of symfttpd is that all tools are independent: you can use only mksymlinks or genconf (though spawn more or less requires the use of both, it isn’t set in stone). A system administrator will find use in mksymlinks and genconf, and a developer more in mksymlinks and spawn.

You’ll find extensive documentation on the project page; what will follow is a quick tutorial for developers.

Install the necessary packages:

# Debian/Ubuntu
aptitude install php5-cgi php5-cli lighttpd
 
# Gentoo
emerge php # with USE="cli cgi"
emerge lighttpd # with USE="fastcgi"
 
# Macports
port install php5 +fastcgi && port install lighttpd
 
# Windows
Nice try.

Get the symfttpd source code:

cd && git clone git://github.com/laurentb/symfttpd.git

There are also archives you can download here if you want to avoid git or bleeding-edge changes.

Basic configuration:

# notice the dot before symfttpd.conf.php
$EDITOR ~/.symfttpd.conf.php

Enter something like that:

< ?php
$options['sf_path']['1.0'] = '/home/myuser/symfony/1.0';
$options['sf_path']['1.4'] = '/home/myuser/symfony/1.4';

Of course, you have to have to adapt it to the Symfony versions you have installed and where you put them.

Configure the project:
If the project is using Symfony 1.4 in the lib/vendor/symfony, you don’t need to do anything. In case it is different, or to be on the safe side, create the file config/symfttpd.conf.php in your project. After, add the file to your project’s version control repository. If you’re lucky, someone already did it for you.

cd ~/myproject
# this time, no dot
$EDITOR config/symfttpd.conf.php
< ?php
$options['want'] = '1.3'; // The version of Symfony used by your project
$options['lib_symlink'] = 'lib/vendor/symfony'; // lib/vendor/symfony will lead to the "lib" directory of Symfony
~/symfttpd/mksymlinks

You're done.
It will create symbolic links for plugins too, even if the version of Symfony (1.0 for instance) doesn't handle them!

To start the server:

~/symfttpd/spawn

It will then tell you how to access it. It's time to stop fighting with old, unpredictable software like Apache and start developing again!

What's coming in future releases:

  • Colors
  • Interactive configuration
  • Server/PHP logs displayed in the terminal
  • Handling "sample" files
  • Custom configuration support on various places

Contributors are welcome.

Posted in PHP, Symfony, Sysadmin | Tagged , , , , , | 2 Comments
Bear