Ah la la. C'est assez rare pour être souligné, mais je viens de me battre avec Symfony pendant près de deux heures avec un problème assez déroutant de prime abord : lorsque dans une action vous faites quelque chose d'aussi anodin que ceci :

public function executeBar()
  {
    try
    {
      // Some stuff here, if successful redirect user to somewhere else
      $this->setFlash('notice', 'Action was successful');
      $this->redirect('@whatever_route');
    }
    catch (Exception $e)
    {
       $this->getRequest()->setError('errors', 'Something has failed somewhere, sorry dude');
       $this->logMessage('Big boo boo occured: '.$e->getMessage(), 'err');
       return sfView::SUCCESS;
    }
  }

Et bien dans ce cas là, la redirection s'opère MAIS l'ensemble du rendu sera tout de même produit et envoyé au navigateur [1] - ce qui peut s'avérer très couteux sur un site internet au final [2]. La raison en est très simple, la méthode redirect() de la classe sfActions met fin à l'execution par ce moyen que l'on peut qualifier de hardi :

public function redirect($url, $statusCode = 302)
  {
    $url = $this->getController()->genUrl($url, true);
    if (sfConfig::get('sf_logging_enabled'))
    {
      $this->getContext()->getLogger()->info('{sfAction} redirect to "'.$url.'"');
    }
    $this->getController()->redirect($url, 0, $statusCode);
    throw new sfStopException();
  }

Oui, vous avez bien lu, on interrompt le script en levant une exception, ici de type sfStopException. Le problème, c'est que dans mon exemple précédent, la méthode redirect() est appellée dans un bloc try { } catch { }, et donc l'exception levée est interceptée et l'action n'est au final pas stoppée. Vicieux, hein ?

Pour régler le problème, on peut par exemple toujours effectuer ses appels à la méthode redirect() en dehors d'un block try { } catch { } [3], ou encore tester le type de l'exception levée. Dans notre exemple, cette dernière solution ressemblerait à ça :

public function executeFoo()
  {
    try
    {
      // Some stuff here, if successful redirect user to somewhere else
      /// ...
      $this->setFlash('notice', 'Action was successful');
      $this->redirect('@whatever_route');
    }
    catch (sfStopException $e)
    {
      return sfView::HEADER_ONLY;
    }
    catch (Exception $e)
    {
      $this->getRequest()->setError('errors', 'Something has failed somewhere, sorry dude');
      $this->logMessage('Big boo boo occured: '.$e->getMessage(), 'err');
      return sfView::SUCCESS;
    }
  }

C'est pas super sexy, mais ça fonctionne, et ça a le mérite de m'inspirer deux morales à cette histoire :

  1. tester le type des exceptions que l'on catche, c'est bien
  2. lever une exception pour arrêter un script, c'est super cracra et mériterait éventuellement d'être patché ;)

Edit: Je m'exprime mal, c'est pas super cracra, c'est juste que ça introduit une petite complexité supplémentaire. Mais l'utilité de la chose est bien entendu totalement avérée si on a besoin d'effectuer des opérations particulières avant la fin du script ( ce qui est rarement le cas, enfin chez moi).

Notes

[1] Avec tout ce que ça comporte de requête SQL et de templates calculés pour rien

[2] Et oui bien sûr, faire un redirect() dans un bloc try catch c'est pas forcément le meilleur endroit, mais c'est teeeellement pratique :p

[3] Qui sera donc exécuté de toute façon si aucune exception n'est levée.