IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

Avis/conseils/suggestions sur mon formulaire d'inscription


Sujet :

Langage PHP

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Février 2008
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 11
    Points : 8
    Points
    8
    Par défaut Avis/conseils/suggestions sur mon formulaire d'inscription
    Bonjour,

    je débute en php et souhaiterais avoir quelques conseils et suggestions concernant mon formulaire d'inscription.
    J'ai quelques questions :

    1. est il nécessaire d'échapper les variables issus d'un formulaire lorsque l'on utilise des requêtes préparées ? Ne serais ce pas doublon ?

    2. Je n'ai pas echappé mes variables 'entier' avec intval notamment à cause de la variable code postal '$cp' ligne 17, qui est ensuite testé comme condition ligne 35 afin notamment de pouvoir obtenir le message d'erreur correspondant.
    Suis je obligé de l'échapper uniquement au moment de la condition ? Car si je l'échappe avant, ma condition sera tirs validée puisque 'intval' l'aura transformée en entier meme si cette dernière est à l'origine un string ? (serais dans ce cas égal à 0)

    3. N' y at'il pas moins fastidieux que le 'try' et 'catch' de PDO pour capturer les erreurs et empêcher aux membres de voir des infos stratégiques en cas d'erreur de la db ?

    4. LE PLUS IMPORTANT : AVEZ VOUS DES CONSEILS, REMARQUES ET SUGGESTIONS POUR AMELIORER LA LISIBILITE, LA SECURITE ET LES BONNES PRATIQUES A UTILISER POUR M'AMELIORER ?

    Merci d'avance à tous et longue vie à développez.com





    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    <?php
     
    if (isset($_POST['envoyer']))
    {		
    	// On échappe les variables pour sécuriser
    	$pseudo=mysql_real_escape_string($_POST['pseudo']);
    	$password=mysql_real_escape_string($_POST['password']);
    	$password_verification=mysql_real_escape_string($_POST['password_verification']);
    	$email=mysql_real_escape_string($_POST['email']);
    	$email_verification=mysql_real_escape_string($_POST['email_verification']);
    	$genre=$_POST['genre'];
    	$prenom=mysql_real_escape_string($_POST['prenom']);
    	$nom=mysql_real_escape_string($_POST['nom']);
    	$birthday=$_POST['birthday'];
    	$adresse=mysql_real_escape_string($_POST['adresse']);
    	$adresse_complement=mysql_real_escape_string($_POST['adresse_complement']);
    	$cp=$_POST['cp'];
    	$ville=mysql_real_escape_string($_POST['ville']);
     
    	if ((!empty($email)) && (!empty($email_verification)) && (!empty($password)) && (!empty($password_verification)) && (!empty($pseudo)) && (!empty($genre)) && (!empty($prenom)) && (!empty($nom)) && (!empty($birthday)) && (!empty($adresse)) && (!empty($cp)) && (!empty($ville)))
    	{
    		// On vérifie que les deux mails sont identiques
    		if ($email==$email_verification)
    		{	
    			// On vérifie que les deux mots de passe sont identiques
    			if ($password==$password_verification)
    			{
    				// On vérifie que le format du mail est valide
    				if(verifmail($email))
    				{
    					// On vérifie que le mot de passe soit égal ou supérieur à 6 caractères
    					if((strlen($password))>=6)
    					{
    						// On vérifie que le code postal est un entier
    						if(intval($cp))
    						{
    							// On vérifie que le login ne soit pas deja utilisé
    							try
    							{
    								$pdo_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
    								$bdd=new PDO('mysql:host='.$host.';dbname='.$db.'',''.$db_user.'',''.$db_password.'');
    								$rep=$bdd->prepare('SELECT login FROM user WHERE login=:login');
    								$rep->execute(array(
    									'login'=>$pseudo));
    								$resultat=$rep->fetch();
    								$rep->closeCursor();
    							}
    							catch (Exception $e)
    							{
          							die('Erreur : ' . $e->getMessage());
    							}
    							if($resultat['login'] != $pseudo)
    							{
    								// On vérifie que le mail ne soit pas deja utilisé
    								try
    								{
    									$pdo_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
    									$bdd=new PDO('mysql:host='.$host.';dbname='.$db.'',''.$db_user.'',''.$db_password.'');
    									$rep=$bdd->prepare('SELECT email FROM user WHERE email=:email');
    									$rep->execute(array(
    										'email'=>$email));
    									$resultat=$rep->fetch();
    									$rep->closeCursor();
    								}
    								catch (Exception $e)
    								{
          								die('Erreur : ' . $e->getMessage());
    								}
    								if($resultat['email'] != $email)
    								{					
    									// On ajoute l'utilisateur en base de donnée
    									try
    									{
    										$pdo_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
    										$bdd=new PDO('mysql:host='.$host.';dbname='.$db.'',''.$db_user.'',''.$db_password.'');
    										$rep = $bdd->prepare('INSERT INTO user (login, password, date_signup, email, genre, prenom, nom, birthday, adresse, adresse_complement, cp, ville) VALUES(:login, :password, :date_signup, :email, :genre, :prenom, :nom, :birthday, :adresse, :adresse_complement, :cp, :ville)');														$rep->execute(array(
    											'login'=> $pseudo,
    											'password'=> sha1($password),
    											'date_signup'=> date("Y-m-d H:i:s"),
    											'email'=> $email,
    											'genre'=> $genre,
    											'prenom'=> $prenom,
    											'nom'=> $nom,
    											'birthday'=> $birthday,
    											'adresse'=> $adresse,
    											'adresse_complement'=> $adresse_complement,
    											'cp'=> $cp,
    											'ville'=> $ville));
    										$rep->closeCursor();
    									}
    									catch (Exception $e)
    									{
          									die('Erreur : ' . $e->getMessage());
    									}
    									$form=false;  
    									echo "Votre compte a été créée"; 
     
    								}
    								else
    								{
    									$form=true;
    									$error='Email déjà utilisé';
    								}
    							}
    							else		
    							{
    								$form=true;
    								$error='Login déjà utilisé';	
    							}		
    						}
    						else
    						{
    							$form=true;
    							$error='Code postal invalide';		
    						}
    					}
    					else
    					{
    						$form=true;
    						$error='Votre mot de passe doit comporter 6 caractères ou plus';		
    					}
    				}
    				else
    				{
    					$form=true;
    					$error='L\'adresse mail entrée est invalide';					
    				}
    			}
    			else
    			{
    				$form=true;
    				$error='Les deux mots de passe entrés sont différents.';
    			}
    		}
    		else
    		{
    			$form=true;
    			$error='Les deux adresses mails entrées sont différentes.';
    		}	
    	}
    	else
    	{
    		$form=true;
    		$error='Tous les champs sont necessaires';
    	}	
    }
    else 
    {
    	$form=true;
    }
     
     
    if ($form)
    {
    	if (isset($_SESSION['login']))
    	{
    		redirect('?page=404');
    	}
    	else 
    	{?>
    		<h2>Créez votre compte</h2><?php 
    		if (isset($error))
    		{ 
    			echo '<p class="alert">'.$error.'</p>';
    		}?>
    		<form name="inscription"  action="" method="post">
    			<table>
    				<tr>
    					<td class="colonne_titre_champ"><label for="email">Email</label></td>
    					<td class="colonne_champ"><input type="text" name="email" id="email" value="<?php echo $email ?>"></td>
    				</tr>
    				<tr>
    					<td class="colonne_titre_champ"><label for="email_verification">Retapez votre email</label></td>
    					<td class="colonne_champ"><input type="text" name="email_verification" id="email_verification" value="<?php echo $email_verification ?>"></td>
    				</tr>
    				<tr>
    					<td class="colonne_titre_champ"><label for="password">Mot de passe</label></td>
    					<td class="colonne_champ"><input type="password" name="password" id="password" value="<?php echo $password ?>"></td>
    				</tr>
    				<tr>
    					<td class="colonne_titre_champ"><label for="password_verification">Retapez votre mot de passe</label></td>
    					<td class="colonne_champ"><input type="password" name="password_verification" id="password_verification" value="<?php echo $password_verification ?>"></td>
    				</tr>
    			</table><br/>
     
    			<table>
    				<tr>
    					<td class="colonne_titre_champ"><label for="pseudo">Pseudo</label></td>
    					<td class="colonne_champ"><input type="text" name="pseudo" id="pseudo" value="<?php echo $pseudo ?>"></td>
    				</tr>
    			</table><br/>
     
    			<table>		
    				<tr>
    					<td class="colonne_titre_champ"><label for="genre">Genre</label></td>
    					<td class="colonne_champ">
    						<select name="genre" id="genre">
    							<option value="1">Monsieur</option>
    							<option value="2">Madame</option>
    						</select>
    					</td>
    				</tr>	
    				<tr>
    					<td class="colonne_titre_champ"><label for="prenom">Prénom</label></td>
    					<td class="colonne_champ"><input type="text" name="prenom" id="prenom" value="<?php echo $prenom ?>"></td>
    				</tr>		
    				<tr>
    					<td class="colonne_titre_champ"><label for="nom">Nom</label></td>
    					<td class="colonne_champ"><input type="text" name="nom" id="nom" value="<?php echo $nom ?>"></td>
    				</tr>	
    				<tr>
    					<td class="colonne_titre_champ"><label for="birthday">Date de naissance</label></td>
    					<td class="colonne_champ"><input type="date" name="birthday" id="birthday" value="<?php echo $birthday ?>"></td>
    				</tr>
    			</table><br/>
     
    			<table>		
    				<tr>
    					<td class="colonne_titre_champ"><label for="adresse">Adresse</label></td>
    					<td class="colonne_champ"><input type="text" name="adresse" id="adresse" size="60" value="<?php echo $adresse ?>"></td>
    				</tr>
    				<tr>
    					<td class="colonne_titre_champ"><label for="adresse_complement">Complément d'adresse</label></td>
    					<td class="colonne_champ"><input type="text" name="adresse_complement" id="adresse_complement" size="60" value="<?php echo $adresse_complement ?>"></td>
    				</tr>
    				<tr>
    					<td class="colonne_titre_champ"><label for="cp">Code Postal</label></td>
    					<td class="colonne_champ"><input type="text" name="cp" id="cp" size="5" value="<?php echo $cp ?>"></td>
    				</tr>
    				<tr>
    					<td class="colonne_titre_champ"><label for="ville">Ville</label></td>
    					<td class="colonne_champ"><input type="text" name="ville" id="ville" value="<?php echo $ville ?>"></td>
    				</tr>				
    				<tr>
    					<td colspan="2" class="boutons"><input type="submit" value="Envoyer" name="envoyer"><input type="reset" value="Annuler"></td>
    				</tr>	
    			</table>
    		</form><?php
    	}
    }
    ?>

  2. #2
    Modératrice
    Avatar de Celira
    Femme Profil pro
    Développeuse PHP/Java
    Inscrit en
    Avril 2007
    Messages
    8 633
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Développeuse PHP/Java
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2007
    Messages : 8 633
    Points : 16 372
    Points
    16 372
    Par défaut
    Citation Envoyé par skhattane Voir le message
    1. est il nécessaire d'échapper les variables issus d'un formulaire lorsque l'on utilise des requêtes préparées ? Ne serais ce pas doublon ?
    Effectivement, normalement PDO s'occupe d'échapper les variables.

    Citation Envoyé par skhattane Voir le message
    3. N' y at'il pas moins fastidieux que le 'try' et 'catch' de PDO pour capturer les erreurs et empêcher aux membres de voir des infos stratégiques en cas d'erreur de la db ?
    Ben, en théorie la gestion d'exceptions est censée faciliter la vie... je vois pas en quoi encadrer ta requête par un try/catch est plus fastidieux qu'un bon vieux or die.

    Sinon au niveau structure : au lieu de faire tes tests dans des ifs imbriqués, tu peux tout tester dans des ifs successifs et renseigner un booléen $en_erreur. Ensuite, tu encadres tes requêtes avec un if qui teste ton booléen $en_erreur. (le même principe que ton booléen $form en fait)
    Modératrice PHP
    Aucun navigateur ne propose d'extension boule-de-cristal : postez votre code et vos messages d'erreurs. (Rappel : "ça ne marche pas" n'est pas un message d'erreur)
    Cherchez un peu avant poser votre question : Cours et Tutoriels PHP - FAQ PHP - PDO une soupe et au lit !.

    Affichez votre code en couleurs : [CODE=php][/CODE] (bouton # de l'éditeur) et [C=php][/C]

  3. #3
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    est il nécessaire d'échapper les variables issus d'un formulaire lorsque l'on utilise des requêtes préparées ? Ne serais ce pas doublon ?
    Toujours vérifier / valider / nettoyer les données à manipuler !

    PDO échappe les variables mais ça ne te protège pas contre les XSS, pour ça il y a les filtres et strip_tags.

    Les filtres sont un must have en qualité de sécurisation des entrées sorties (à mettre des deux cotés donc pour se prémunir des attaques).

    Je n'ai pas echappé mes variables 'entier' avec intval notamment à cause de la variable code postal '$cp' ligne 17, qui est ensuite testé comme condition ligne 35 afin notamment de pouvoir obtenir le message d'erreur correspondant.
    Suis je obligé de l'échapper uniquement au moment de la condition ? Car si je l'échappe avant, ma condition sera tirs validée puisque 'intval' l'aura transformée en entier meme si cette dernière est à l'origine un string ? (serais dans ce cas égal à 0)
    C'est pas bien grave, PDOStatement::bindParam ou PDOStatement::bindValue prends un paramètre qui permet de typer tes données.

    N' y at'il pas moins fastidieux que le 'try' et 'catch' de PDO pour capturer les erreurs et empêcher aux membres de voir des infos stratégiques en cas d'erreur de la db ?
    Tu n'est pas obligé de spécifier l'attribut ERRMODE à Exception, en revanche, il faut systématiquement vérifier le retour de PDOStatement::execute.

    Ben, en théorie la gestion d'exceptions est censée faciliter la vie... je vois pas en quoi encadrer ta requête par un try/catch est plus fastidieux qu'un bon vieux or die.
    La gestion des exception n'est pas là pour simplifier la vie du programmeur. Déjà, les exception ne sont levées par PDO que si l'attritbut ATTR_ERRMODE est à ERRMODE_EXCEPTION. Quand une exception est levée, il n'est pas forcément nécéssaire de la catcher, l'exception va remonter la pile d'appels jusqu'à la racine où elle provoquera une erreur fatale si elle n'est pas attrapée entre temps ou si l'exception handler n'est pas défini.
    Une exception est par définition exceptionnelle: on ne la lance que quand il n'y a plus rien d'autre à faire. L'exemple type est le cas de comportement incorrect au niveau d'un constructeur, vu qu'il ne renvoie rien, comment notifier le bloc parent qu'il y a eu un erreur ? On lève une exception.

    Dans tous les cas il faut tout vérifier et ne JAMAIS faire de "or die". Cette pratique à été introduite dans beaucoup de scripts PHP par des développeurs incompétents et malheureusement dans énormément de tutoriaux. Il y a toujours quelque chose à faire en cas d'erreur critique (à minima mettre une info dans un fichier de log avant de sortir).

    AVEZ VOUS DES CONSEILS, REMARQUES ET SUGGESTIONS POUR AMELIORER LA LISIBILITE, LA SECURITE ET LES BONNES PRATIQUES A UTILISER POUR M'AMELIORER ?
    Oui:
    • ne pas mélanger PDO et mysql_*
    • utilise des modes de fetch intelligents comme FETCH_INTO ou FETCH_CLASS pour réccupérer directement des instances de modèles prêtes à l'usage
    • wrappe tes instances de PDOStatment dans des IteratorIterator afin de pouvoir y coller des FilterIterator ou des LimitIIterator qui sont des solutions paliatives aux problèmes de portabilité de SQL en PHP
    • Utilise un Singleton PDO pour éviter d'ouvrir malencontreusement plusieurs instances (ce qui est aussi inutile que dangereux la plupart du temps)
    • LIS LA DOC (je suis sérieux, trop peu de gens le font vraiment)


    Note:
    • Il n'est utile d'appeller PDOStatement::closeCursor que si on récuppère plusieurs sets de donnés (par exemple avec une procédure stoquée) ce n'est pas le cas dans ton code
    • mêler le PHP au HTML est une mauvaise pratique, sépare le traitement de la mise en forme au niveau des fichers (si possible, implémente le pattern MVC)
    • toute ta séquence de vérification peut être avantageusement réduite en utilisant filter_input_array
    • Ouvre la connection au début du script et émets une erreur si ça ne marche pas (si ton script ne peut pas fonctionner sans BDD, alors c'est inutile de l'executer si on n'arrive pas à ouvrir la connection)
    • tu ne vérifie pas le retour de PDOStatement::execute, comment peux-tu savoir si ça c'est mal passé ?
    • NE JAMAIS LAISSER REMONTER LES MESSAGES D'ERREUR DE PHP COTE CLIENT (comme tu le fais avec ton die) C'EST UNE FAILLE DE SECURITE
    • tu ouvres deux fois la connection à la base, c'est inutile, une seule connection suffit


    Dans tous les cas, teste, teste et teste encore, c'est en essayant et en ratant inlassablement qu'on apprends le plus.

  4. #4
    Futur Membre du Club
    Profil pro
    Inscrit en
    Février 2008
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 11
    Points : 8
    Points
    8
    Par défaut
    Bonsoir tout le monde, et merci pour ces deux réponses. C sympa
    Sur vos conseils,j'ai lu la doc PDO, et j'ai appris pas mal de choses.
    J'ai également regardé du coté des filtres et strip_tags et je pense en avoir compris l'intérêt.

    au lieu de faire tes tests dans des ifs imbriqués, tu peux tout tester dans des ifs successifs et renseigner un booléen $en_erreur. Ensuite, tu encadres tes requêtes avec un if qui teste ton booléen $en_erreur. (le même principe que ton booléen $form en fait)
    J'ai imbriqué afin que le script ne doit pas interpréter toutes les conditions si ce dernier détecte des le début une condition non valide. Si je les met les uns à la suite des autres, meme en cas de condition non valide en début de script, elles seront toutes vérifiées. En même temps, cela permettrait d'avoir l'intégralité des messages d'erreurs à présenter en haut de mon formulaire en cas de multiples saisies erronées.
    D'ailleurs a ce propos, auriez vous une structure en tête pour récupérer tous les messages d'erreurs et les afficher en entête de formulaire lors de saisies erronées ? Je ne trouve pas très élégant de créer une variable par erreur et afficher toutes ces variables au dessus du formulaire avec des if à gogo. Pas de possibilité d'utiliser un tableau associatif d'erreurs ou quelque chose du genre ?

    ne pas mélanger PDO et mysql_*
    J'ai du mal à comprendre : je ne dois pas utiliser mysql_real_escape_string avec PDO?
    Dans ce cas, il vaut mieux utiliser les filtres et strip_tags ? Pas certain d'avoir saisi.

    utilise des modes de fetch intelligents comme FETCH_INTO ou FETCH_CLASS pour réccupérer directement des instances de modèles prêtes à l'usage
    Concernant les fetch de type FETCH_INTO ou FETCH_CLASS, le but est de renvoyer la reponse d'une requête sous forme d'objet (nouvelle instance). Cependant quel est l'intérêt de récupérer un objet à la place d'un tableau associatif ou numéroté ? C'est de pouvoir accéder aux méthodes de PDOStatement ?

    il faut systématiquement vérifier le retour de PDOStatement::execute.
    Concrètement, je fais comment ?
    Je verifie si "$mon_objet->execute()" renvoie "true" ?
    et si ce n'est pas le cas, que dois je faire ? je balance un message d'erreur ou lève une exception ?

    wrappe tes instances de PDOStatment dans des IteratorIterator afin de pouvoir y coller des FilterIterator ou des LimitIIterator qui sont des solutions paliatives aux problèmes de portabilité de SQL en PHP
    Alors la, j'avoue, j'ai rien compris.
    Je me documente sur les iterator et je reviendrais aux questions, si j'ai un soucis.
    Donc probablement bientôt

    Pour le pattern MVC, c'est en cours, je ne voulais pas tout faire d'un coup. :lil:

    La gestion des exception n'est pas là pour simplifier la vie du programmeur. Déjà, les exception ne sont levées par PDO que si l'attritbut ATTR_ERRMODE est à ERRMODE_EXCEPTION. Quand une exception est levée, il n'est pas forcément nécéssaire de la catcher, l'exception va remonter la pile d'appels jusqu'à la racine où elle provoquera une erreur fatale si elle n'est pas attrapée entre temps ou si l'exception handler n'est pas défini.
    Une exception est par définition exceptionnelle: on ne la lance que quand il n'y a plus rien d'autre à faire. L'exemple type est le cas de comportement incorrect au niveau d'un constructeur, vu qu'il ne renvoie rien, comment notifier le bloc parent qu'il y a eu un erreur ? On lève une exception.
    Auriez vous un bon tuto/cours au sujet des exceptions /erreurs et gestionnaire d'erreurs ? Pacque la franchement

    toute ta séquence de vérification peut être avantageusement réduite en utilisant filter_input_array
    J'y ai jeté un coup d'oeil, c'est noté.

    Pour le singleton, et le fait que j'ai ouvert une connexion à la db plusieurs fois.
    Nous sommes d'accord que le singleton permet de n'instancier qu'une seule fois la classe. (en gros de s'assurer qu'une seule connexion à la db est ouverte.)
    Cependant je pensais que le closecursor permettait de fermer la connexion.
    Hors je m'aperçois que cela n'a absolument rien à voir.

    Donc question :
    1. Dois t'on obigatoirement fermer la connexion à une db ? Si oui, en fin de script ? Et comment ? En tuant l'objet $connexion ? Si c'est en tuant l'objet, le simple fait d'aboutir à la fin du script, ferme donc automatiquement la connexion ?
    2. Le closecursor sert concrètement a quoi ? j'ai lu la doc PDO et j'ai compris que c'est lorsque l'on n'a pas récupéré l'intégralité de la réponse d'une requete et que l'on souhaite exécuter une seconde requete. Dans mon script, cela veut il dire qu'étant donné que j'ai dans ma requete un WHERE qui limite ma réponse à une seule ligne, l'intégralité de la réponse est récupérée et que dans ce cas, je n'ai pas besoin de fermer le curseur pour exécuter la requête suivante ?

    Questions subsidiaires :
    1. Quelle différence entre PDO::exec et PDO::query ?

    En tout cas, un grand merci de prendre de votre temps pour éclairer ma lanterne.

  5. #5
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    J'ai du mal à comprendre : je ne dois pas utiliser mysql_real_escape_string avec PDO?
    Dans ce cas, il vaut mieux utiliser les filtres et strip_tags ? Pas certain d'avoir saisi.
    Soit tu utilise PDO soit tu utilise mysql_* mais pas les deux, c'est redondant et dangereux. Avec les requêtes préparées il n'est plus nécéssaire d'utiliser real_escape_string.

    Concernant les fetch de type FETCH_INTO ou FETCH_CLASS, le but est de renvoyer la reponse d'une requête sous forme d'objet (nouvelle instance). Cependant quel est l'intérêt de récupérer un objet à la place d'un tableau associatif ou numéroté ? C'est de pouvoir accéder aux méthodes de PDOStatement ?
    Non, l'idée c'est de récupérer un objet avec des méthodes bien pratiques, par exemple, si tu récupères une ligne (tuple) de la table article sous forme d'objet, ce serait bien pratique de disposer d'une méthode pour obtenir tous les commentaires non ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    $query = "SELECT * FROM articles WHERE id=123";
    $stmt = $pdo->query($query);
    $stmt->setFetchMode(PDO::FETCH_CLASS, 'Article');
    $article = $stmt->fetch();
    foreach ($article->getComment() as $comment) {
      ...
    }
    Tu vois le principe ?

    Je verifie si "$mon_objet->execute()" renvoie "true" ?
    et si ce n'est pas le cas, que dois je faire ? je balance un message d'erreur ou lève une exception ?
    Oui, il faut systématiquement vérifier le retour. Si c'est false, à toi de décider ce qu'il faut faire mais en tout cas tu sais qu'il ne faut pas travailler avec les résultats.

    wrappe tes instances de PDOStatment dans des IteratorIterator afin de pouvoir y coller des FilterIterator ou des LimitIIterator qui sont des solutions paliatives aux problèmes de portabilité de SQL en PHP
    Alors la, j'avoue, j'ai rien compris.
    Je me documente sur les iterator et je reviendrais aux questions, si j'ai un soucis.
    Donc probablement bientôt
    Explication sur ce thread: http://www.developpez.net/forums/d10...emnt-iterator/
    Pour comprendre le mécanisme des itérateurs en PHP, je te renvoie à la doc.

    Auriez vous un bon tuto/cours au sujet des exceptions /erreurs et gestionnaire d'erreurs ? Pacque la franchement
    Voir la doc: http://php.net/manual/fr/language.exceptions.php
    La gestion des exceptions en PHP est très similaire à celle de Java, à l'exception () du mot clé finaly qui n'existe pas en PHP.


    Pour le singleton, et le fait que j'ai ouvert une connexion à la db plusieurs fois.
    Nous sommes d'accord que le singleton permet de n'instancier qu'une seule fois la classe. (en gros de s'assurer qu'une seule connexion à la db est ouverte.)
    Cependant je pensais que le closecursor permettait de fermer la connexion.
    Hors je m'aperçois que cela n'a absolument rien à voir.
    Avec PDO, il n'existe aucun moyen certain de fermer la connexion explicitement. closeCursor est une méthode de PDOStatement, c'est PDO qui caractérise la connection. En fait, PHP fermera la connexion à la fin du script ou s'il est mis à null et que le garbage collector passe dessus (en PHP 5.3 uniquement et impossible de savoir quand cela se produit).

    1. Dois t'on obigatoirement fermer la connexion à une db ?
    Non, PHP le fait pour toi à la fin du script.

    2. Le closecursor sert concrètement a quoi ?
    De mémoire, PDOStatement::closeCursor sert à libérer les résultats d'une requête en cas de requêtes non mises en cache (unbuffered queries). Vu qu'il est impossible d'effectuer de nouvelle requête tant qu'on a pas réccupéré tous les résultats de la requête en cours dans ce cas, on appelle closeCursor pour spécifier qu'on a fini de travailler sur ce jeu de résultat et qu'on va effectuer de nouvelles requêtes.
    Appeler cette méthode est inutile si on n'a pas mis l'attribut PDO::MYSQL_ATTR_USE_BUFFERED_QUERY à false dans PDO donc par défaut c'est inutile.

    Quelle différence entre PDO::exec et PDO::query ?
    PDO::exec renvoie directement le nombre de lignes affectées par la requête.
    PDO::query renvoie un PDOStatement.
    Donc exec est adapté aux INSERT, UPDATE, DELETE et query aux SELECT.
    Je te recommande l'usage systématique de PDO::prepare

  6. #6
    Futur Membre du Club
    Profil pro
    Inscrit en
    Février 2008
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 11
    Points : 8
    Points
    8
    Par défaut
    Ok merci pour ces réponses. Je commence à comprendre.
    Par contre concernant PDO::FETCH_CLASS

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    $query = "SELECT * FROM articles WHERE id=123";
    $stmt = $pdo->query($query);
    $stmt->setFetchMode(PDO::FETCH_CLASS, 'Article');
    $article = $stmt->fetch();
    foreach ($article->getComment() as $comment) {
      ...
    }
    Si je comprends bien, tu renvoies le résultat de la requête sous forme d'objet (instance de la classe 'Article') ?
    L'intérêt est donc de pouvoir appeler les méthodes de la classe 'Article'.

    Dans ce cas, 4 questions :

    1. peux tu me confirmer que dans ce cas au préalable tu auras probablement un include('Article.class.php'); dans lequel une classe 'Article' sera déclarée ?

    2. Si tel est le cas, comment récupère ton les résultats de la requete au sein de la classe ? D'apres ce que je lis dans la doc de PDO, il va renvoyer des variables avec les intitulés des colonnes de la table. Donc si je comprends, on récupère au sein de la classe des variables du type: $id $titre $auteur ,etc. correspondant aux noms des champs de la table articles ?

    3. enfin ce système ne pose t'il pas de pbl avec l'utilisation d'un constructeur ?
    Car si FETCH_CLASS instancie la classe articles et que pour x raisons, son constructeur l'instancie histoire d'avoir un objet tout prêt des qu'on l'appel (j'ai cru voir ça quelque part), cela ne pose t'il pas de soucis ? Ou je suis complètement à coté de la plaque ?

    4. enfin si on récupère au sein de la classe des variables en fonction des noms de colonnes, je suppose qu'il est mal venu de les récupérer directement au sein de nos attributs. En gros faire un =, mais qu'il vaut mieux passer par la méthode _setAttribut implémentée plus bas dans la classe?

    C'est peut être la qu'intervient la notion d'hydratation des objets ? Me trompe-je
    Je ne sais pas si je suis complètement a coté de la plaque donc pas tapper si je raconte n'importe quoi ...

    sam

  7. #7
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    peux tu me confirmer que dans ce cas au préalable tu auras probablement un include('Article.class.php'); dans lequel une classe 'Article' sera déclarée ?
    Il faut soit que la classe Article soit chargée (avec include ou require) ou qu'un autoloader ait été mis en place (voir http://php.net/manual/fr/language.oop5.autoload.php)

    Si tel est le cas, comment récupère ton les résultats de la requete au sein de la classe ? D'apres ce que je lis dans la doc de PDO, il va renvoyer des variables avec les intitulés des colonnes de la table. Donc si je comprends, on récupère au sein de la classe des variables du type: $id $titre $auteur ,etc. correspondant aux noms des champs de la table articles ?
    En fait, les valeurs des attributs de la classe correspondront à celles des colonnes. Il faut alors que ces attributs soient soit publiques soit que les méthodes magiques __get et __set soient définies.

    enfin ce système ne pose t'il pas de pbl avec l'utilisation d'un constructeur ?
    Car si FETCH_CLASS instancie la classe articles et que pour x raisons, son constructeur l'instancie histoire d'avoir un objet tout prêt des qu'on l'appel (j'ai cru voir ça quelque part), cela ne pose t'il pas de soucis ? Ou je suis complètement à coté de la plaque ?
    Lors de chaque fetch, le constructeur de la classe sera implicitement invoqué (par défaut sans paramètres, il est possible de spécifier sous forme de tableaux les paramètres du constructeurs).
    Voici le prototype de setFetchMode à utilise dans ce cas:
    - bool PDOStatement::setFetchMode ( int $PDO::FETCH_CLASS , string $classname , array $ctorargs )
    (voir http://php.net/manual/fr/pdostatement.setfetchmode.php)

    enfin si on récupère au sein de la classe des variables en fonction des noms de colonnes, je suppose qu'il est mal venu de les récupérer directement au sein de nos attributs. En gros faire un =, mais qu'il vaut mieux passer par la méthode _setAttribut implémentée plus bas dans la classe?
    PDOStatement va lui même renseigner les attributs de l'instance une fois la classe instancié (voir plus haut).
    Ils sont directement utilisables avec l'opérateur -> comme pour n'importe quelle instance.

    C'est peut être la qu'intervient la notion d'hydratation des objets ? Me trompe-je
    Connais pas... Je vais regarder. J'aurais tendance à dire que PDOStatement popule des instances.

    Exemple

    Considérons le jeu de données suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    mysql> select * from test;
    +----+------+---------+
    | id | name | surname |
    +----+------+---------+
    |  1 | foo  | bar     |
    |  2 | foo2 | bar2    |
    |  3 | foo3 | bar3    |
    +----+------+---------+
    3 rows in set (0.00 sec)
    Nous allons créer une classe toute bête pour ces données:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class Test {
    	public $id;
    	public $name;
    	public $surname;
     
    	public function __construct () {
    		// Visualiser l'appel au constructeur
    		var_dump(__METHOD__);
    	}
     
    	public function greeting () {
    		echo "Bonjour {$this->name} {$this->surname}";
    	}
    }
    La méthode greeting va nous permettre d'afficher un message de bienvenue.

    Voici donc comment s'utilise le mode FETCH_CLASS:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    $pdo = new PDO('mysql:dbname=test;host=localhost', 'root', '');
    $stmt = $pdo->query('SELECT * FROM test');
     
    $stmt->setFetchMode(PDO::FETCH_CLASS, 'Test');
     
    foreach ($stmt as $item) {
    	$item->greeting();
    	echo "<br />";
    }
    Produit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    string 'Test::__construct' (length=17)
     
    Bonjour foo bar
     
    string 'Test::__construct' (length=17)
     
    Bonjour foo2 bar2
     
    string 'Test::__construct' (length=17)
     
    Bonjour foo3 bar3
    On remarque que le constructeur est appelé à chaque fois qu'on réccupère une nouvelle entrée, ceci contraste avec un autre mode de fetch lui aussi très utile: FETCH_INTO:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $pdo = new PDO('mysql:dbname=test;host=localhost', 'root', '');
    $stmt = $pdo->query('SELECT * FROM test');
     
    $test = new Test;
    $stmt->setFetchMode(PDO::FETCH_INTO, $test);
     
    foreach ($stmt as $item) {
    	$item->greeting();
    	echo "<br />";
    }
    Produit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    string 'Test::__construct' (length=17)
     
    Bonjour foo bar
    Bonjour foo2 bar2
    Bonjour foo3 bar3
    Dans ce deuxième cas, on utilise une instance existante et PDOStatement va la populer à chaque itération. L'avantage est d'éviter de se retrouver avec plusieurs instances et d’appeler plusieurs fois le constructeur.

    Pour aller plus loin

    Nous pouvons construire des classes de modèles implémentant un CRUD (Create, Retrieve, Update, Delete), ce sont des méthodes capables de faire respectivement des créations, réccupération, mise-à-jour et suppression de données, tout cela encapsulé dans une seule classe.

    Voici un exemple de classe de modèle générique (extrait du framework Axiom):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    <?php
    /**
     * Axiom: a lightweight PHP framework
     *
     * @copyright Copyright 2010-2011, Benjamin Delespierre (http://bdelespierre.fr)
     * @licence http://www.gnu.org/licenses/lgpl.html Lesser General Public Licence version 3
     */
     
    /**
     * Model Base Class
     *
     * @abstract
     * @author Delespierre
     * @package libaxiom
     * @subpackage core
     */
    abstract class Model {
     
        /**
         * Model key id
         * @var string
         */
        protected $_id_key = 'id';
     
        /**
         * Model's data
         * @var array
         */
        protected $_data = array();
     
        /**
         * Statements cache
         * @var array
         */
        protected $_statements = array();
     
        /**
         * Initialize a model statement (part of CRUD)
         * @abstract
         * @param string $statement
         * @return PDOStatement
         */
        abstract protected function _init ($statement);
     
        /**
         * Default constructor
         * @param mixed $id
         * @throws RuntimeException
         */
        public function __construct ($id = null) {
            if ($id !== null && $id !== false && !$this->find($id))
                throw new RuntimeException("Cannot instanciate model", 2009);
        }
     
        /**
         * __sleep overloading
         * @return array
         */
        public function __sleep () {
            return array('_id_key', '_data');
        }
     
        /**
         * Getter
         * @param string $key
         * @return mixed
         */
        public function __get ($key) {
            return isset($this->_data[$key]) ? $this->_data[$key] : null;
        }
     
        /**
         * Setter
         * @param string $key
         * @param mixed $value
         * @return void
         */
        public function __set ($key, $value) {
            $this->_data[$key] = $value;
        }
     
        /**
         * __isset overloading
         * @param string $key
         * @return boolean
         */
        public function __isset ($key) {
            return isset($this->_data[$key]);
        }
     
        /**
         * Get internal data
         * @internal
         * @return array
         */
        public function getData () {
            return $this->_data;
        }
     
        /**
         * Retrieve method
         * Will return false in case of error
         * @param mixed $id
         * @return Model
         */
        public function find ($id) {
            if (!$this->_init("retrieve"))
                throw new RuntimeException("Cannot initialize " . __METHOD__, 2010);
     
            if ($this->_statements['retrieve']->execute(array(":{$this->_id_key}" => $id))) {
                if ($this->_statements['retrieve']->rowCount()) {
                    $this->_data = $this->_statements['retrieve']->fetch(PDO::FETCH_ASSOC);
                    return $this;
                }
            }
            return false;
        }
     
        /**
         * Create methode
         * Will return false in case of error
         * @param array $data
         * @throws RuntimeException
         * @return Model
         */
        public function create ($data) {
            if (!$this->_init("create"))
                throw new RuntimeException("Cannot initialize " . __METHOD__, 2011);
     
            if ($this->_statements['create']->execute(array_keys_prefix($data, ':'))) {
                $id = Database::lastInsertId();
                return $this->find($id);
            }
            return false;
        }
     
        /**
         * Update method
         * @throws RuntimeException
         * @return boolean
         */
        public function update ($data = array()) {
            if (!$this->_init("update"))
                throw new RuntimeException("Cannot initialize " . __METHOD__, 2012);
     
            if (!empty($this->_data)) {
                $inputs = array_merge($this->_data, array_intersect_key($data, $this->_data));
                return $this->_statements['update']->execute(array_keys_prefix($inputs, ':'));
            }
            return false;
        }
     
        /**
         * Delete method
         * @throws RuntimeException
         * @return boolean
         */
        public function delete () {
            if (!$this->_init("delete"))
                throw new RuntimeException("Cannot initialize " . __METHOD__, 2013);
     
            if (!empty($this->_data))
                return $this->_statements['delete']->execute(array(":{$this->_id_key}" => $this->_data[$this->_id_key]));
            return false;
        }
    }
    Et voici un exemple de classe concrête de modèle (Model est abstraite car il manque une information: les requêtes à effectuer, il faut donc la faire hériter):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    <?php
    /**
     * Axiom: a lightweight PHP framework
     *
     * @copyright Copyright 2010-2011, Benjamin Delespierre (http://bdelespierre.fr)
     * @licence http://www.gnu.org/licenses/lgpl.html Lesser General Public Licence version 3
     */
     
    /**
     * User Model
     *
     * @author Delespierre
     * @version $Rev: 74 $
     * @subpackage User
     */
    class User extends Model {
     
        protected function _init ($statement) {
            if (isset($this->_statements[$statement]))
                return $this->_statements[$statement];
     
            switch ($statement) {
                case 'create':
                    $query = 'INSERT INTO `ax_users` (`login`,`password`,`name`,`surname`) VALUES (:login,:password,:name,:surname)';
                    break;
                case 'retrieve':
                    $query = 'SELECT * FROM `ax_users` WHERE `id`=:id';
                    break;
                case 'update':
                    $query = 'UPDATE `ax_users` SET `login`=:login, `password`=:password, `name`=:name, `surname`=:surname, '.
                    		 '`creation`=:creation, `last_connection`=:last_connection WHERE `id`=:id';
                    break;
                case 'delete':
                    $query = 'DELETE FROM `ax_users` WHERE `id`=:id';
                    break;
                default:
                    throw new RuntimeException("$statement is unexepected for " . __METHOD__, 10001);
            }
     
            return $this->_statements[$statement] = Database::prepare($query);
        }
     
        public static function exists ($username, $password) {
            $query = "SELECT `id` FROM `ax_users` WHERE `login`=:login AND `password`=:password";
            $stmt = Database::prepare($query);
     
            $password = md5($password);
            $stmt->bindParam(':login', $username, PDO::PARAM_STR);
            $stmt->bindParam(':password', $password, PDO::PARAM_STR);
     
            if ($stmt->execute()) {
                if ($stmt->rowCount()) {
                    $row = $stmt->fetch();
                    return new self($row['id']);
                }
                return false;
            }
            else
                throw new RuntimeException("Error with query");
        }
     
        public static function getUsers ($search_params = array()) {
            $query = "SELECT * FROM `ax_users`";
     
            if (!empty($search_params)) {
                $pieces = array();
                foreach ($search_params as $key => $value)
                    $pieces[] = "`$key`=:$key";
                $query .= " WHERE " . implode(' AND ', $pieces);
            }
     
            $stmt = Database::prepare($query);
            if ($stmt->execute(array_keys_prefix($search_params, ':'))) {
                $user = new self;
                $stmt->setFetchMode(PDO::FETCH_INTO, $user);
                return new PDOStatementIterator($stmt);
            }
            return false;
        }
    }
    On peut l'utiliser de cette façon:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // créer un utilisateur
    $user = new User;
    $user->create(array(
      'login' => 'test',
      'password' => md5('test'),
      'name' => 'Test',
      'surname' => 'FooBar',
    ));
     
    // Trouver un utilisateur
    if ($user = User::exists($login, $password)) ...
     
    // Metter à jour un utilisateur
    $user->name = "Random";
    $user->update();
     
    // Supprimer un utilisateur
    $user->delete();
    Plutôt sympa comme syntaxe non ? La création d'objets modèle est une partie cruciale du paradigme MVC, c'est quelque peu laborieux de créer toutes les classes nécéssaires mais l'avantage se fait clairement sentir en termes d'évolutivité, de portabilité et surtout de maintenance du code source.

  8. #8
    Expert éminent sénior

    Profil pro
    Inscrit en
    Juin 2002
    Messages
    6 152
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 6 152
    Points : 17 778
    Points
    17 778
    Par défaut
    Citation Envoyé par Benjamin Delespierre Voir le message
    En fait, les valeurs des attributs de la classe correspondront à celles des colonnes. Il faut alors que ces attributs soient soit publiques soit que les méthodes magiques __get et __set soient définies.
    Les attributs peuvent être de visibilité restreinte avec le mode FETCH_CLASS. Et, pour ceux qui ne sont pas publics, il n'y a pas d'appel à __set (uniquement pour les inexistants/non déclarés).

    Tout l'opposé, ou presque, (attributs publics sinon __set requise) de FETCH_INTO où, du fait de son fonctionnement, __set ne sera exécutée qu'une seule fois pour chaque attribut inexistant.

    Chacun de ces modes a ses avantages et ses inconvénients (FETCH_CLASS permet, en outre, plus de choses).

    Citation Envoyé par Benjamin Delespierre Voir le message
    Lors de chaque fetch, le constructeur de la classe sera implicitement invoqué (par défaut sans paramètres, il est possible de spécifier sous forme de tableaux les paramètres du constructeurs).
    À noter, que par défaut (sans l'option PDO::FETCH_PROPS_LATE - introduit en 5.2.0), les propriétés de la classe sont initialisées avec les valeurs de la base avant l'appel du constructeur (donc, dans ces circonstances, le constructeur pourrait, volontairement ou non, écraser les valeurs issues de la base).

  9. #9
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    Merci pour la correction J'utilise massivement le mode FETCH_INTO (quitte à utiliser clone par derrière) alors je ne l'avais jamais remarqué ce comportement.

    Il est vrai également que la doc n'est pas toujours très explicite à ce sujet...

  10. #10
    Futur Membre du Club
    Profil pro
    Inscrit en
    Février 2008
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 11
    Points : 8
    Points
    8
    Par défaut
    Ouch la réponse !!!
    C plus un forum, c'est un live tuto

    Je comprends mieux le fonctionnement.
    Je vais prendre un peu de temps a vraiment essayer de bien décortiquer les classes d'Axiom que tu as fourni. Je reviens aux questions si besoin. Ca risque ...

    Deja une :
    La diff entre FETCH_CLASS et FETCH_INTO signifie donc qu'avec INTO, il n'y aura jamais qu'une seule et unique instance qui sera mis a jour successivement par les résultats successifs de la requête. Si tel est le cas, si on appele ensuite une méthode de cette instance, celle ci se fera avec la dernière ligne de données que lui aura renvoyé la requêtes ?

    Au fait concernant la notion d'hydratation, c'est dans le tuto sur la POO
    Concretement il s'agit d'une fonction "hydrate()" qui est appelée directement depuis le constructeur de la classe et qui va appeler automatiquement les setters en fonction du nom des attributs passés en paramètres lors de l'instanciacion de la classe.

    Je pense que ca revient à peu près au même qu'un FETCH_CLASS sauf que l'attribution des valeurs aux attributs se fait via un tableau associatif.

    J'ai testé la fonction, alors je met mon script : (soyez indulgents)
    Celle ci impose de fait une convention de nommage des setters, ce qui n'est peut être pas plus mal.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    <?php
    class User
    {
    	private $id;
    	private $login;
    	private $prenom;
    	private $nom;    	
     
    	public function __construct(array $tableau)
    	{
    		$this->hydrate($tableau);
    	}
     
    	public function hydrate(array $tableau)
           {
               foreach ($tableau as $key => $value)
               {
                   $method = 'set'.ucfirst($key);
     
                   if (method_exists($this, $method))
                   {
                       $this->$method($value);
                   }
               }
           }
     
    /* ----------------- Setters-------------------*/
     
    	public function setId($id)
    		{
    			$this->id = $id;
    		}
     
    	public function setLogin($login)
    		{
    			$this->login = $login;
    		}
     
    	public function setPrenom($prenom)
    		{
    			$this->prenom = $prenom;
    		}
     
    	public function setNom($nom)
    		{
    			$this->nom = $nom;		
    		}
     
    /* ----------------- Getters-------------------*/
     
    	public function id()
    		{
    			return $this->id;
    		}
     
    	public function login()
    		{
    			return $this->login;
    		}
     
    	public function prenom()
    		{
    			return $this->prenom;
    		}
     
    	public function nom()
    		{
    			return $this->nom;
    		}
     
    }
     
    $tab=array('id'=> 47,'login'=> 'Samlamenace','prenom'=> 'Tyler','nom'=> 'Durden');
    $perso = new User($tab);
    echo $perso->id().' '.$perso->login().' '.$perso->prenom().' '.$perso->nom();
    ?>
    En tout cas, merci bcp pour l'aide que vous apportez, ça donne vraiment envie de progresser. C cool

  11. #11
    Modératrice
    Avatar de Celira
    Femme Profil pro
    Développeuse PHP/Java
    Inscrit en
    Avril 2007
    Messages
    8 633
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Développeuse PHP/Java
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2007
    Messages : 8 633
    Points : 16 372
    Points
    16 372
    Par défaut
    L'avantage de la méthode d'hydratation, c'est qu'on peut aussi s'en servir pour faire une mise à jour d'un objet existant (par exemple, dans le cas d'un formulaire modifiant un enregistrement existant)
    Au passage, vu que tu as normé tes setters, autant aussi normer les getters en getMachin()
    Modératrice PHP
    Aucun navigateur ne propose d'extension boule-de-cristal : postez votre code et vos messages d'erreurs. (Rappel : "ça ne marche pas" n'est pas un message d'erreur)
    Cherchez un peu avant poser votre question : Cours et Tutoriels PHP - FAQ PHP - PDO une soupe et au lit !.

    Affichez votre code en couleurs : [CODE=php][/CODE] (bouton # de l'éditeur) et [C=php][/C]

Discussions similaires

  1. Besoin d'avis sur mon formulaire
    Par Olivier Regnier dans le forum Web
    Réponses: 2
    Dernier message: 16/11/2007, 09h46
  2. Réponses: 1
    Dernier message: 06/10/2006, 21h03
  3. Question sur mon formulaire de contact
    Par Analfabete dans le forum Langage
    Réponses: 3
    Dernier message: 24/04/2006, 18h12
  4. la date et heure sur mon formulaire
    Par azde7015 dans le forum Access
    Réponses: 11
    Dernier message: 07/02/2006, 10h40
  5. avie et probleme sur mon site
    Par coucou449 dans le forum Balisage (X)HTML et validation W3C
    Réponses: 3
    Dernier message: 23/12/2005, 09h34

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo