logo Homepage
+  NewbieContest
|-+  Programmation» Langages Web» [PHP] Error handler
Username:
Password:
Pages: [1] 2
  Imprimer  
Auteur Fil de discussion: [PHP] Error handler  (Lu 10094 fois)
Baelrog

Profil challenge

Classement : 363/54284

Membre Junior
**
Hors ligne Hors ligne
Messages: 85


Voir le profil
« le: 26 Août 2010 à 16:00:39 »

Salut à tous,

Après pas mal de googuelage et n'ayant rien trouvé d'utile, je viens voir si un maniaque de la gestion des erreurs aurait une réponse à mon problème.

Un petit exemple de mon soucis avec un bout de code stupide mais mettant bien les choses en valeurs:

<?php

$record = new stdClass();
$record->truc = 1;

eval('return $record->bidule == 1;');

?>

Dans cet exemple, on créé une stdClass, on défini un attribut nommé "truc", et dans un eval, on test un attribut "bidule" qui n'existe pas.
PHP dans sa grandeur et sa sagesse va donc tout naturellement me retourner une jolie notice m'indiquant le problème, et c'est la qu'intervient mon soucis.

Comment catcher cette notice ?

Avant de répondre, il faut tenir compte d'un paramètre. Je code sur un framework (Jelix pour ceux que ca intéresse) et je ne peux pas me permettre un "set_error_handler" vu que le framework le fait déjà a sa sauce.
J'ai trouvé un type ErrorException en natif sur php mais faut utiliser le set_error_handler, donc c'est mort.

Bref, j'ai besoin de savoir quand la notice est levée pour balancer une exception et faire un affichage des variables ayant générées le problème.

Si vous avez une idée, je suis preneur !

(Merci d'avance aux futur coups de mains)

« Dernière édition: 26 Août 2010 à 16:03:57 par Baelrog » Journalisée
Nil

Profil challenge

Classement : 79/54284

Membre Complet
***
Hors ligne Hors ligne
Messages: 223


Voir le profil WWW
« #1 le: 26 Août 2010 à 16:06:00 »

En gros, tu veux lever un exception SI et seulement SI l'attribut X n'est pas définie dans ton objet? Est-ce que j'ai bien compris?
Journalisée
Baelrog

Profil challenge

Classement : 363/54284

Membre Junior
**
Hors ligne Hors ligne
Messages: 85


Voir le profil
« #2 le: 26 Août 2010 à 16:24:20 »

En gros, oui. Je peux faire des test avec property_exists() sur l'objet, mais j'aimerais controler un peu mieux les possibles bug d'eval en général plutot que de me concentrer sur la résolution d'un cas particulier. D'où la gestion du notice.
« Dernière édition: 26 Août 2010 à 16:46:38 par Baelrog » Journalisée
Nil

Profil challenge

Classement : 79/54284

Membre Complet
***
Hors ligne Hors ligne
Messages: 223


Voir le profil WWW
« #3 le: 26 Août 2010 à 17:01:26 »

Je ne connais pas une solution spécifique à PHP parce que je ne suis pas un pro en PHP, mais voici quand même 2-3 points :

Problème
  • Ton truc de eval() ... c'est tout simplement horrible.  Même si tu étais capable de le faire fonctionner comme tu veux, essais pas ne pas recourir à ce genre de hack. Si tu montre ce bout de code à ta mère, elle ne sera pas fier de toi
  • Autre point moins important, les exceptions, c'est pour les traitements *exceptionnels*. Si tu t'attend à avoir cette erreur souvent, tu ne devrais pas lancer un exception, mais plutôt réorganiser ton code. Je ne peux pas vraiment t'aider davantage vu que je ne connais pas la structure de ton code, sorry.

Solutions
  • Tu pourrais te renseigner sur 'get_object_vars()' et ce genre de fonctions. La plupart des langages dynamiques offrent des fonctions/méthodes pratiques pour connaître le type des variables, les méthodes offertes par un objet, etc ... C'est probable que tu peux savoir que 'bidule' existe ou pas avec une de ces fonctions.
  • Tu pourrais te créer un attribut 'error' = true ou false, chaque fois que créé un objet stdClass. De cette façon, tu n'aurais qu'à regarder la valeur de 'error' et lancer ton exception selon la valeur. Mais je n'aime pas cette idée, la prochaine est meilleure.
  • Tu pourrais te créer une vrai classe au lieu d'utiliser ce genre de tableau associatif qu'est stdClass(). Dans ton constructeur, tu met '$this.error' à ce que tu veux, même concept que plus haut, mais tu n'as pas à initialiser toi-même l'attribut 'error' ... C'est important ce point, c'est le genre de détail qu'on oublie souvent. En plus, si ta classe évolue, ce sera beaucoup plus pratique d'avoir une vrai classe avec un vrai constructeur.

Voila, je crois que tu peux t'en sortir. Bonne chance.
Journalisée
Baelrog

Profil challenge

Classement : 363/54284

Membre Junior
**
Hors ligne Hors ligne
Messages: 85


Voir le profil
« #4 le: 26 Août 2010 à 17:19:43 »

Pour eval: je suis d'accord. Le problème c'est que je bosse sur une appli assez complexe vu le dynamisme qu'elle requière et dans mon cas eval est la solution la plus simple sans passer X heures à coder un process similaire. Pour faire simple, je dev un logiciel de paie pour une société. Les commerciaux ont des primes en fonction de divers critères sur des info d'autres bases de données. et le tout doit être administrer par les gens de la compta qui bien sur, n'ont jamais vu une ligne de code de leur vie. Donc pour évaluer les critères de déclenchement de ces primes par rapport aux données extract des bases (voir meme certaines calculer à la volée), vu que je ne connais la condition logique qui va être tester à l'avance (et ne peux donc pas faire de bêtes "if" à la queue-leuleu), il faut que j'eval ce bazar.


Pour les exceptions, oui t'inquiètes En fait, l'application est stable (plus que prévu même :p), mais certains changement dans l'entreprise impliquent certaines refontes des modes de calcul à des endroits totalement imprévisible en fonction de la nature de ces modif. Mais j'ai codé cette appli en faisant converger les données nécessaires à certains endroits très localisés où du coup, les bug sont visibles directement. Et cet eval est le dernier bastions d'emmerdes que je souhaite faire tomber en posant un listener sur ses activités pour rapidement identifier les futurs sources de problèmes.
Journalisée
Harry41

Profil challenge

Classement : 2130/54284

Néophyte
*
Hors ligne Hors ligne
Messages: 28

A vaincre sans périls, on triomphe sans gloire...


Voir le profil WWW
« #5 le: 27 Août 2010 à 02:44:40 »

Bonjour a vous deux !
Je suis d'accords avec Nil, il n'est jamais vraiment bon d'utiliser eval()...

Du coup, je vois 2 choix : faire un try catch dans ton eval() -> baaah, sale...
ou réfléchir un peux plus au problème.

Je pencherai plutôt sur la deuxième, ton problème peut se résoudre plus facilement et surtout plus sainement...
Si j'ai bien compris, en fonction d'un état ou d'un autre, tu va utiliser une valeur...

Du coup, pourquoi ne pas faire un truc du genre :
<?php

$record = new stdClass();
$record->rcdEtat = "monEtat";
$record->($record->rcdEtat) = "rcdValue";

du coup, on a $record->rcdEtat qui vaut le nom de l'état et $record->($record->rcdEtat) (ce qui reviens ici a faire $record->monEtat) vaut la valeur. Ainsi, 'aucune' chance de se planter.

du coup, au lieu de faire :
eval('if($record->rcdEtat == "etat1"){return $record->bidule == 1;}else if($record->rcdEtat == "etat2")[...]');

tu fais un switch sur $record->rcdEtat.  Mais tu peux aussi bien faire une fonction speciale dans ta classe qui fait ce que tu veux, car c'est elle qui semble avoir toutes les données, ce serait logique.

?>

Il faut savoir aussi que si tu cree une classe, autant y mettre les bons attributs de base et faire des getteurs setteurs appropries (soit un chacun si tu veux verif des trucs avant d'effectuer l'action, soit un getteur et un setteur global pour toutes les variables - voir plus bas).

La bonne programmation n'est pas en option
Apres, je suis peut être a cote de la plaque niveau comprehension de ton besoin

PS: des "if" à la queue-leuleu seront toujours plus propres qu'un eval()

<?php
function get($key){
    return $this->$key;
}

function set($key, $value){
    return $this->$key = $value;
}
?>
« Dernière édition: 27 Août 2010 à 02:55:15 par Harry41 » Journalisée

--
Harry 41
A vaincre sans périls, on triomphe sans gloire...
Baelrog

Profil challenge

Classement : 363/54284

Membre Junior
**
Hors ligne Hors ligne
Messages: 85


Voir le profil
« #6 le: 27 Août 2010 à 09:35:41 »

En fait, pour résumer, mon problème consiste à tracker les notice/warning sorties de l'eval. Ces erreurs ne sont pas catchable.

Mon exemple n'était qu'un bout de code générant ce problème et nullement mon utilisation actuel de l'eval.
Pour aller un poil plus loin dans l'explication de mon programme, voici un algo sommaire:


L'utilisateur saisie une liste de critère (champs en base + opérateur + valeur). Cette liste de critère est structuré par une condition logique (ex: 1 AND (2 OR 3), les chiffres nommant les numéros des critères ).

Ma classe prend un record de base de donnée, pour former avec ma condition logique précédente une truc du genre:
$record->champs1 operateur1 valeur1 AND ($record->champs2 operateur2 valeur2 OR $record->champs3 operateur3 valeur3)

Et la dessus j'applique un eval pour savoir si les critères au sein de la condition logique sont bon ou pas pour le record que je récupère.

Mais dans mon cas j'ai bêtement réglé le soucis en faisant un check dans l'objet pour savoir si les attribut à tester existent bien ou pas.


Par contre, mon besoin premier, est d'avoir un tracking efficace sur cette eval moisie vu que les notice/warning sont importante ici, et qu'un try catch ne permet pas de les chopper.
Journalisée
kony

Profil challenge

Classement : 360/54284

Membre Junior
**
Hors ligne Hors ligne
Messages: 52


Voir le profil
« #7 le: 27 Août 2010 à 12:46:35 »

Salut regarde du coté du design pattern "interpreter", je l'ai jamais mis en œuvre mais ca peut correspondent a ce que tu cherches pour te passer de eval si j'ai bien compris ce dont tu parles ^^
Journalisée
Iansus

Profil challenge

Classement : 50/54284

Membre Senior
****
Hors ligne Hors ligne
Messages: 262


Voir le profil WWW
« #8 le: 27 Août 2010 à 17:30:53 »

Si le problème est simplement de cacher les notices quand elles apparaissent pour faire des tests sur des variables qui n'existent pas forcément, un simle @ devant l'instruction devrait suffire.

<? eval('return @($record->bidule == 1);'); ?>
Journalisée
Nil

Profil challenge

Classement : 79/54284

Membre Complet
***
Hors ligne Hors ligne
Messages: 223


Voir le profil WWW
« #9 le: 27 Août 2010 à 20:33:11 »

Pardonne mon ignorance Iansus, mais qu'est que l'opérateur @ est supposé faire? C'est quoi sa ou ses fonctions en PHP? Ça se cherche un peu mal sur google ^^
Journalisée
awe

Profil challenge

Classement : 49/54284

Néophyte
*
Hors ligne Hors ligne
Messages: 28


Voir le profil WWW
« #10 le: 27 Août 2010 à 21:00:23 »

@Nil: @ ça cache les erreurs éventuelles (en tout cas ça le permet, peut être que ça fait plus).

sinon, j'ai pas très bien compris ce qui était demandé, mais tu peux créer un error/exception handler, puis restaurer l'ancien avec
restore_error_handler, par exemple, il me semble.

Et pour cacher les erreurs, ça doit se faire directement avec error_reporting();

J'espère ne pas être trop à côté de la plaque, ce qui est bien possible 
Journalisée

Need moar hacking challenges ? W3Challs
Iansus

Profil challenge

Classement : 50/54284

Membre Senior
****
Hors ligne Hors ligne
Messages: 262


Voir le profil WWW
« #11 le: 28 Août 2010 à 13:20:20 »

Pardonne mon ignorance Iansus, mais qu'est que l'opérateur @ est supposé faire? C'est quoi sa ou ses fonctions en PHP? Ça se cherche un peu mal sur google ^^

Désolé :p En effet, comme l'a dit awe, @ sert à masquer les notices engendrées par la fonction qu'elle précède.
Si on prend le code suivant :
Code:
<?php

$array 
= array("login" => "Iansus""pass" => "youdliketoknow");
if(empty(
$array["email"])) echo "Your email adress is missing !";

?>

La tu obtiendras une belle notice "email : no such index on line ...".
Si tu remplaces la condition par : if(@empty($array["email"])) echo "Your email adress is missing !";, plus de notice qui apparaît. Dasn ton cas, ça peut être utile, mais en général, c'est comme l'alcool, à consommer avec modération. Ça fait joli, mais c'est con de se ballader avec une notice qui pourra se transformer en Fatal error dans une version future de PHP.
Journalisée
ThunderLord
Profil challenge

Classement : 25/54284

Membre Junior
**
Hors ligne Hors ligne
Messages: 57


Voir le profil
« #12 le: 28 Août 2010 à 14:41:45 »

Code:
<?php

$array 
= array("login" => "Iansus""pass" => "youdliketoknow");
if(empty(
$array["email"])) echo "Your email adress is missing !";

?>

La tu obtiendras une belle notice "email : no such index on line ...".

Ou pas... Justement empty() tout comme isset() à quelques différences près, peut être utilisé pour tester la présence d'un élement dans un tableau, donc le code au dessus ne va certainement pas provoquer une notice, mais bien afficher "Your email adress is missing" (en passant, address prend deux d en anglais)
Journalisée

ThunderLord
Baelrog

Profil challenge

Classement : 363/54284

Membre Junior
**
Hors ligne Hors ligne
Messages: 85


Voir le profil
« #13 le: 31 Août 2010 à 16:07:31 »

@awe: Non tu n'es pas à coté de la plaque le restore_error_handler peut en effet etre une option, mais comme je l'ai dis au début, le framework a bien dérouté la gestion des erreur pour avoir quelque chose de bien foutu (point de vue très subjectif ), et vu qu'il peut y avoir des erreurs ailleurs, je n'ai pas envi de feinter la gestion actuelle pour me rendre compte dans 6 mois qu'il y avait un coin où ca crashait mais que l'appli ne pouvais me le dire . Je cherche donc une gestion de l'erreur très précise géographiquement dans le code. Si le try/catch fonctionnait sur les notice, j'aurais pas ce genre de problème .

Et pour les aficionados du @ en php, pour ma part je suis totalement contre. Autant fermer les yeux, on verra pas que l'appli crash Le framework se charge entre autre de récupérer ces notices pour les logger ou les envoyer par mails tout en les masquant (sur un serveur en prod). Je suis plutôt un partisan du 0 erreur et le @ n'aide pas à atteindre cet objectif.
Journalisée
Harry41

Profil challenge

Classement : 2130/54284

Néophyte
*
Hors ligne Hors ligne
Messages: 28

A vaincre sans périls, on triomphe sans gloire...


Voir le profil WWW
« #14 le: 01 Septembre 2010 à 02:15:22 »

hum... de meme, je ne suis pas pour l'@.
Mais vraiment, il faut oublier eval...
tu peux y arriver sans, et c'est comme un challenge, apres, tu te sens fort

Je pense qu'une fonction dans ton objet retournerai bien ta solution.
il faut bien sur utiliser qu'une seule variable pour l'operateur, et pour le champs et la valeur

$record->operateur = "+";
$record->key = "nomDuChamp";
$record->value = "valeurDuChamp";

et dans la fonction de ta classe, tu fais ce qu'il faut faire...
Si tu as besoins de plusieurs variable (plusieurs operateurs, etc)
tu peux faire un tableau d'objets.

voila, bon courage a toi
Journalisée

--
Harry 41
A vaincre sans périls, on triomphe sans gloire...
Pages: [1] 2
  Imprimer  
 
Aller à: