(encore un article fourre-tout, je me demande comment je peux avoir des lecteurs réguliers !)

Comme j'en ai déjà parlé dans ces billets, j'utilise Google Calendar pour recevoir des alertes SMS sur certaines actions du site Web.
Tout a toujours bien marché, jusqu'à ce que je tombe sur l'erreur suivante :

ARRÊT DU SCRIPT : Erreur PHP.

Erreur sur [/chemin/absolu/C/lib/debug.php:43]
#1  Debug::err_handler(2, include(Zend/Gdata/Calendar/Extension/EventEntry.php) [function.include]: failed to open stream: No such file or directory, /chemin/absolu/lib/Zend/Loader.php, 83, Array ([class] => Zend_Gdata_Calendar_Extension_EventEntry,[dirs] => ,[file] => Zend/Gdata/Calendar/Extension/EventEntry.php)) called at [/chemin/absolu/lib/Zend/Loader.php:83]
#2  Zend_Loader::loadClass() called at [/chemin/absolu/lib/Zend/Loader.php:83]
#3  Zend_Loader::loadClass(Zend_Gdata_Calendar_Extension_EventEntry) called at [/chemin/absolu/lib/Zend/Gdata/App.php:1028]
#4  Zend_Gdata_App->__call(newEventEntry, Array ())
#5  Zend_Gdata_Calendar->newEventEntry() called at [/chemin/absolu/C/lib/external.php:89]
#6  External::notify(« Ma notification » par Auteur, Par Auteur (ID 5) connecté sur 86.76.215.215, le 1275504058) called at [/chemin/absolu/C/membres/redaction.php:59]
#7  include(/chemin/absolu/C/membres/redaction.php) called at [/chemin/absolu/index.php:80]

La partie qui m'a aidée, c'est include(Zend/Gdata/Calendar/Extension/EventEntry. php).
En fait, le problème est causé par l'utilisation de la fonction PHP set_error_handler() : une fois définie, cette fonction prend en compte toutes les erreurs, même celle qui sont normalement supprimées avec l'opérateur @. Et la librairie Google, basée sur Zend, utilise justement cet opérateur !

Bref, long story short comme disent les Américains : il faut tester dans la fonction de callback d'erreur le niveau d'error_reporting() (appelée sans argument, la fonction renvoie le niveau actuel). Si on obtient 0, c'est qu'on est en « error-control ».

Juste pour les curieux, les fonctions de Debug :

set_error_handler('Debug::err_handler',-1);

//Et un extrait de la classe Debug
//Pour le réutiliser, n'oubliez pas de déclarer class Debug { } !

/**
* Appelé quand une erreur se produit / est déclenchée par le code et nécessite l'affichage d'un message d'erreur.
* Note : cette fonction est préférable à exit() car elle facilite le débuggage et le trace des erreurs en production.
* @param Msg:String Le message à afficher
* @return :void La fonction ne retourne jamais, le script est interrompu.
*/
public static function fail($Msg)
{
	echo '

ARRÊT DU SCRIPT : ' . $Msg . '

'; ob_start(); //Récupérer la pile d'appel de fonction. Elle est envoyée sur la sortie standard, ce qui justifie l'utilisation de la tamporisation de sortie. debug_print_backtrace(); //Supprimer de la pile d'appel la ligne qui fait référence à Debug::fail() qui ne sert bien évidemment à rien : $trace = preg_replace('`#0 .+ called at`','Erreur sur',ob_get_clean()); //Et terminer le script la dessus. exit('<pre>' . $trace . '</pre>'); } /** * Gestionnaire personnalisé d'erreurs défini avec set_error_handler. * Permet d'éviter d'afficher les erreurs PHP à l'utilisateur, et de récupérer proprement, par exemple en affichant une page d'erreur et en envoyant un mail à l'administrateur avec le contexte de l'erreur. * @param errno:int le numéro de l'erreur, inutile. * @param errstr:String la description de l'erreur, plus utile ;) * @param errfile:String le fichier dans lequel s'est produit l'erreur * @param errline:int la ligne du fichier * @param errcontext:array un gros tableau (très gros tableau même dans la plupart des cas) qui contient la liste des variables définies au moment du bug. * @return :void La fonction ne retourne jamais, le script est interrompu. */ public static function err_handler($errno, $errstr, $errfile, $errline, array $errcontext) { if(error_reporting()!=0)//Si on est pas en mode de suppression d'erreurs avec @ Debug::fail('Erreur PHP : ' . $errstr); } /** * Appelé quand une requête SQL produit une erreur. * Affiche l'erreur SQL et la pile d'appel. */ public static function sqlFail() { self::fail(mysql_error()); }