je souhaiterai avoir votre avis quant à la pertinence de ma classe. Il s'agit d'une classe pour l'insertion dans une table. Je souhaitais utiliser prepare pour optimiser cette requête mais j'espère avoir bien compris.
Donc voici le code et merci pour vos avis et conseil.
class requetes{
function __construct(){
$this->connexion=SPDO::getInstance();
}
/**
* MISE À JOUR ET INSERTION DANS UNE TABLE
**/
PUBLIC FUNCTION modifyTable($table, array $set, $condition = NULL) {
IF(!EMPTY($condition)) {
try{
array_walk($set, create_function('&$val, $key', '$val "$key \'$val\'";'));
$this->req="UPDATE ".$table." SET " . implode(", ", $set) . " WHERE ".$condition;
$this->connexion->exec($this->req);
}
catch(PDOException $e) {
throw new myException("Erreur de mise à jour = ".$this->sql." Message : ".$e->getMessage());
}
}
ELSE {
try{
$nb=count(array_keys($set));
$tab=array_keys($set);
$this->sql = "INSERT INTO ".$table." (" . implode(", ", array_keys($set)) . ") VALUES (:".implode(", :", array_keys($set)).")";
$this->statement = $this->connexion->prepare($this->sql);
FOR ( $i=0; $i<$nb; $i++ ){
$this->statement->bindParam(':'.$tab[$i], $set[$tab[$i]]);
}
$this->statement->execute();
}
catch(PDOException $e) {
throw new myException("Erreur d'insertion = ".$this->sql." Message : ".$e->getMessage());
}
}
}
}
J'ai du mal à comprendre ton array_walk() avec create_function(). Ce serait pas plus clair avec un foreach ? (et plus performant par la même occasion, j'ai déjà benché : array_walk() est lent).
Je pense qu'il serait plus propre d'avoir 2 méthodes distinctes pour l'insertion et pour la mise à jour (mais c'est mon avis perso, hein).
Je ne comprends pas pourquoi ta classe n'étend pas, tout simplement, PDO (ou SPDO qui semble être ta classe étendue). Ca me semblerait plus simple, plus cohérent, mais là encore, libre à toi d'écrire ta classe en suivant le motif de conception de ton choix.
Dans l'utilisation, il n'est pas nécessaire d'utiliser la fonction addslashes() puisque la méthode prepare() de PDO s'occupe d'échapper les caractères spéciaux (y compris les guillemets si besoin est). Ca fait doublon, quoi, mais c'est pas une faille ou une réelle erreur (ça ne plantera pas, et ça ne rendra pas le code plus ou moins vulnérable).
L'utilisation des blocs try...catch ne me parait pas nécessaire, puisque je ne crois pas que PDO::exec() lance d'exception : il n'y a donc rien à attraper... Par contre, vérifier que la requête s'est bien exécutée en comptant le nombre de ligne affectées (attention, en cas d'update, la valeur retournée peut parfois surprendre, notamment lors de l'utilisation de ON DUPLICATE KEY...)
Les noms des fonctions et les mots clés sont supposés être écrits en minuscules (PHP est sensible à la casse, il est fort possible que PHP renvoit des erreurs de type WARNING, mais que la configuration ne les affiche pas).
Euh voilà tout ce que je peux en dire pour le moment ;)
--
Neige
Souvent la réponse à votre question se trouve dans la doc. Commencez par là ;)
array_walk() parcourt un tableau pour appliquer une fonction sur chaque élément du tableau. Donc, ça, on peut le faire avec foreach(). Quant à create_function(), étant donné ta fonction anonyme, il est tout à fait possible de la remplacer par... du code PHP qui fait la même chose. Mais j'ai du mal à voir ce que tu veux faire avec cette fonction anonyme...
Ton bloc try...catch ne va jamais lancer d'exception, parce qu'il n'en interceptera jamais. Les fonction PDO::exec() et PDOStatement::execute() renvoient uniquement un booléen et ne lancent pas d'exception. Ton bloc try...catch est donc inutile : il faut vérifier si la fonction s'exécute correctement ou non (si elle renvoit TRUE ou FALSE) pour savoir si une erreur s'est produite.
PDO::__construct() lance une exception, mais elle est en dehors de tes bloc try...catch
--
Neige
Souvent la réponse à votre question se trouve dans la doc. Commencez par là ;)
Ton bloc try...catch ne va jamais lancer d'exception, parce qu'il n'en interceptera jamais. Les fonction PDO::exec() et PDOStatement::execute() renvoient uniquement un booléen et ne lancent pas d'exception.
Toutes deux peuvent lever des exceptions, tout dépend du traitement demandé (via PDO::ATTR_ERRMODE)
Ok. Au temps pour moi (une fois de plus pfffffffffffffffff). C'est que je ne configure jamais cette option, je laisse par défaut la valeur à ERRMODE_SILENT.
Mais encore une fois de plus supplémentaire (et sans vouloir faire de pléonasme) quand on n'a pas toutes les infos sur ce que fait/veut la personne, on fait c'qu'on peut avec c'qu'on a ^^ (ça, c'est pour mon autodéfense)
--
Neige
Souvent la réponse à votre question se trouve dans la doc. Commencez par là ;)
ok merci pour ces infos. En fait je cherche à produire une classe regroupent toutes les fonctions d'action sur une table : add, supp et up
Il est vrai que j'avais l'option PDO::ATTR_ERRMODE donc un message avec try catch
Je vais essayer d'optimiser tout ça alors. Par contre qq'un connaît une classe similaire à ce que je veux faire car j'ai beau chercher
Ce que tu veux faire, c'est implémenter le modèle CRUD (Create / Read / Update / Delete). Et des classes basées sur PDO qui implémentent ce modèle, ça doit déjà exister... jette un oeil par là : http://www.google.fr/#q=crud+pdo
--
Neige
Souvent la réponse à votre question se trouve dans la doc. Commencez par là ;)
En PHP, quand tu utilises une variable en tant que tableau, il faut OBLIGATOIREMENT la définir au préalable.
En fait, là, tu as probablement une erreur qui n'est pas affichée, du fait que error_reporting() ne définit pas un niveau d'erreur assez élevé.
Si tu demandes à récupérer un objet, faut pas manipuler un tableau...
Chaque ligne du résultat sera une instance de stdClass.
Bon mais c'est ta méthode entière qui n'est pas optimisée. Avec ça, tu vas parcourir 2 fois chaque résultat. C'est vraiment du temps perdu pour rien quand on sait que PDOStatement implémente Traversable : on peut itérer directement sur le résultat, qui est une instance de PDOStatement, dans une boucle foreach. C'est plus propre, plus rapide, plus tout...
--
Neige
Souvent la réponse à votre question se trouve dans la doc. Commencez par là ;)
désolé de dire ça mais t'aurais pas un exemple s'appliquant à ce code. Vraiment je suis épaté de voir à quel point tout ça te semble si simple.
J'ai vraiment du mal avec la boucle foreach et je ne l'utilise jamais. D'après toi qu'est ce qui pourrais remplacer ma fonction pour me permettre d'avoir un tableau avec l'ensemble des résultats. Car pour l'insertion et la suppression c'est ok mais là....
Encore désolé de t'importuné, j'imagine que t'as autre chose à faire mais là...Depuis que je t'ai écrit je me suis mis au pdo et donc comme tu vois j'ai déjà du mal avec qq notion de php mais j'ai besoin de réussir...moralement. En plus depuis que j'ai eu des infos par toi j'ai super progresser à mon goût bien sur ...
J'ai mieux à faire, oui, peut-être, mais prêcher pour PDO, c'est un peu obsessionnel chez moi... Tu utiliserais l'extension mysql, j'aurais jamais répondu... Mais forcément, quelqu'un qui cherche à utiliser PDO, je l'aide, pour pas qu'il revienne à du procédural (parce que ce serait dommage de régresser).
Pour comprendre comment fonctionne foreach() (j'ai été un peu perturbé lors des premières utilisations) il "suffit" de lire la doc ET de faire des essais sur du code à la con.
Pour comprendre comment utiliser une instance de PDOStatement dans une boucle foreach, il est préférable de comprendre comment fonctionnent les itérateurs, mais ce n'est pas indispensable.
Quand tu as compris comment itérer sur un tableau avec foreach(), il faut juste savoir qu'un itérateur, lors de son itérateur, peut renvoyer deux valeurs utilisées par foreach() :
- l'index (la position du curseur dans la boucle d'itération, le plus souvent il s'agit d'un entier >= 0)
- la valeur de l'item courant
La première forme ne se soucie pas de la clé du tableau. Qu'il s'agise d'un tableau indexé numériquement ou associativement, on ne récupère que les valeurs, dans l'ordre dans lequel elles sont présentes dans le tableau, donc dans l'ordre dans lequel le tableau a été défini ou trié.
Avec un résultat de requête PDOStatement, c'est exactement la même chose. On passe simplement l'objet PDOStatement dans la boucle foreach et on récupère la valeur (laquelle peut être un tableau indexé nuémriquement ou associatif, un objet stdClass ou une instance d'un objet défini spécifiquement, tout dépend de la configuraon apportée avec PDOStatement::setFetchMode())
En gros, ta classe n'a pas besoin de retourner la liste des lignes du résultat : elle peut se contenter de retourner le résultat (une instance de PDOStatement) que tu vas utiliser plus tard dans l'affichage des données. Si tu parcours une première fois le résultat pour stocker les lignes dans un tableau, quand tu vas les afficher, tu vas ENCORE parcourir ces mêmes résultats, mais dans le tableau PHP cette fois... Bref, deux boucles pour le prix d'une... Pour afficher 5 résultats, c'est pas la fin du monde ni du script, mais quand on gère des résultats de plusieurs centaines d'enregistrements, et que plusieurs fois dans un script on parcours chaque résultat 2 fois, y'a un vrai manque à gagner.
Pour pouvoir renvoyer un résultat de requête, il ne faut pas que celui-ci soit stocké en tant que propriété de la classe. PHP5 passe TOUS les objets par référence, modifier le résultat (stocker dans la propriété le résultat d'une autre requête) empêchera de pouvoir utiliser le résultat qu'on a récupéré plus tard, puisqu'il aura été remplacé (euh pour moi, c'est clair, mais je sais pas si ça l'est pour tout le monde).
J'essaie de faire mieux... Dans ton cas, quand tu exécutes une requête, le résultat est stocké dans une propriété de ta classe. Ainsi, tu ne le manipules pas de l'extérieur. Je comprends l'intérêt que tu as à faire ça, je vais te montrer la limite.
Quand on souhaite itérer sur un résultat directement, lors de l'affichage de données (avec une boucle foreach donc), on a besoin de conserver ce résultat bien au chaud. Si ta méthode renvoie le résultat, c'est à dire :
return $this -> stmt;
et si plus tard tu exécutes une autre requête, la valeur de $this -> stmt aura changé. De même que la variable dans laquelle tu auras stocké le premier résultat. Tout ça parce que PHP5 ne renvoie pas une copie du résultat (contrairement à PHP4 qui renvoyait des copies d'objets), mais une référence à l'original : le résultat n'est instancié qu'une seule fois. Cf la doc PHP sur les références, notamment le premier commentaire de la page en lien, qui explique les références sur les objets avec PHP5.
Donc pour pouvoir itérer plus tard, et pouvoir malgré tout exécuter d'autres requêtes entre l'exécution de la première et l'affichage de son résultat, il FAUT récupérer une nouvelle instance de PDOStatement depuis ta méthode qui exécute la requête.
Une solution serait d'étendre la classe PDOStatement et spécifier à la classe PDO le nom de la classe à utiliser pour retourner des résultats.
Et c'est sur cette classe que tu vas exécuter des méthodes qui traitent le résultat.
Une autre solution est de cloner le résultat (avec le mot-clé clone) pour le retourner.
(En fait, ce serait plus simple si je voyais le code complet de ta classe)
Dans ton code PHP :
<?php
$db->select('*', 'rubriques', 'id_rubrique > ?');
$db->bindValues(array('8'));
$rubriques = $db->queryObjectArray();
?>
Lors de l'affichage des données :
<?php
foreach ($rubriques as $k => $rub) {
echo $k.' - Test '.$rub->id_rubrique.'
';
}
?>
Sinon, pour ton information, PDOStatement possède une méthode qui renvoit toutes les lignes d'un résultat en une seule fois : PDO::fetchAll() qui en gros, fait ce que tu fais... Mais je ne recommande pas cette méthode, puisqu'elle nécessite elle aussi de parcourir 2 fois le résultat (une première fois par PDOStatement, une seconde fois quand on affiche chaque ligne). Elle n'est intéressante que si l'on a besoin de travailler sur le tableau de résultat pour le trier, ou faire des manipulation complexes (cf la source de Prince418)
Euh voilà, j'vais m'arrêter là pour le moment...
--
Neige
Souvent la réponse à votre question se trouve dans la doc. Commencez par là ;)
j'ai pas tout lu, mais chapeau bas !!
quand je pense que certains disent que les "mascottes" et autres "gourous" ne répondent que par des "lis la doc" / "cherche sur google" ... il y a de quoi rire
Bonne soirée,
Kohntark -
NB : je sais, je n'apporte pas grand chose (... que faut il apporter de plus ?) mais je tenais à faire la remarque.
Au fait je vais tester mais le truc est que lors de l'affichage je vais afficher l'id, le titre,le message et la date donc c'est là que la boucle foreach prend toute sa difficulté.
Si en voyant la source plus haut t'as moyen de voir...
Merci.