Ici on a choisi de quitter le script, mais le jour ó l’on décide de créer un fichier dans tmp avec toutes les erreurs rencontrées, la modification affecte seulement la fonction Connexion
Trang 1$ c o n n e x i o n = m y s q l _ p c o n n e c t ( $ p S e r v e u r , $pNom , $ p M o t P a s s e ) ;
i f ( ! $ c o n n e x i o n ) {
echo " D é s o l é , c o n n e x i o n au s e r v e u r $ p S e r v e u r i m p o s s i b l e \n " ;
e x i t ;
}
/ / C o n n e x i o n à l a b a s e
i f ( ! m y s q l _ s e l e c t _ d b ( $ p B a s e , $ c o n n e x i o n ) ) {
echo " D é s o l é , a c c è s à l a b a s e $ p B a s e i m p o s s i b l e \n " ;
echo " <b> M e s s a g e de MySQL : < / b> " m y s q l _ e r r o r ( $ c o n n e x i o n ) ;
e x i t ;
}
/ / On r e n v o i e l a v a r i a b l e d e c o n n e x i o n
r e t u r n $ c o n n e x i o n ;
} / / F i n d e l a f o n c t i o n
? >
La première ligne de la fonction est sa signature (ou prototype) Elle définit les
paramètres que la fonction accepte L’interpréteur vérifie, au moment de l’appel à une fonction, que le nombre de paramètres transmis correspond à celui de la signature L’apport essentiel de Connexion() par rapport à mysql_pconnect() est de tester le cas de l’échec de l’accès au serveur de MySQL et de prendre les mesures
en conséquence Les deux avantages de l’utilisation des fonctions donnés ci-dessus apparaissent dès cette simple implantation :
1 délégation : le script qui se connecte à MySQL a certainement des choses plus
importantes à faire que de tester ce genre d’erreur ;
2 partage : c’est le bénéfice le plus apparent ici On n’aura plus jamais à se soucier
de l’échec de l’accès au serveur De plus, la politique appliquée en cas d’échec est définie en un seul endroit Ici on a choisi de quitter le script, mais le jour
ó l’on décide de créer un fichier dans tmp avec toutes les erreurs rencontrées,
la modification affecte seulement la fonction Connexion()
REMARQUE –Pour l’instant les messages d’erreur sont affichés à l’écran Sur un site en production c’est une très mauvaise pratique, pour des raisons d’image et de sécurité La bonne méthode (quoique légèrement hypocrite) consiste à afficher un message courtois disant que
le site est en maintenance, et à envoyer un message à l’administrateur pour lui signaler le problème.
Exécution de requêtes
Selon le même principe, il est possible de définir des fonctions pour exécuter une requête avec MySQL Le fichierExecRequete.phpcontient trois fonctions : la première pour exécuter une requête, la seconde et la troisième pour récupérer une ligne du résultat respectivement sous forme d’objet (un groupe $o, dont chaque valeur v est accessible par $o->v) ou de tableau associatif (un tableau $t dont chaque valeur v est accessible par $t[’v’])
Trang 2Exemple 2.2 exemples/ExecRequete.php:Fonctions exécutant une requête
<? php
/ / E x é c u t i o n d ’ u n e r e q u ê t e a v e c MySQL
f u n c t i o n E x e c R e q u e t e ( $ r e q u e t e , $ c o n n e x i o n )
{
$ r e s u l t a t = m y s q l _ q u e r y ( $ r e q u e t e , $ c o n n e x i o n ) ;
i f ( $ r e s u l t a t )
r e t u r n $ r e s u l t a t ;
e l s e {
echo " <b> E r r e u r d a n s l ’ e x é c u t i o n de l a r e q u ê t e ’ $ r e q u e t e ’
</ b>< b r / > " ;
echo " <b> M e s s a g e de MySQL : < / b> " m y s q l _ e r r o r ( $ c o n n e x i o n ) ;
e x i t ;
}
} / / F i n d e l a f o n c t i o n E x e c R e q u e t e
/ / R e c h e r c h e d e l ’ o b j e t s u i v a n t
f u n c t i o n O b j e t S u i v a n t ( $ r e s u l t a t )
{
r e t u r n m y s q l _ f e t c h _ o b j e c t ( $ r e s u l t a t ) ;
}
/ / R e c h e r c h e d e l a l i g n e s u i v a n t e ( r e t o u r n e un t a b l e a u )
f u n c t i o n L i g n e S u i v a n t e ( $ r e s u l t a t )
{
r e t u r n m y s q l _ f e t c h _ a s s o c ( $ r e s u l t a t ) ;
}
? >
Le regroupement de fonctions concourant à un même objectif – ici l’exécution d’une requête, puis l’exploitation du résultat – est une pratique classique et mène à la
notion, elle aussi classique, de module Un module est un ensemble de fonctionnalités
qui correspond à une partie cohérente et bien identifiée d’une application plus large, placées en général dans un même fichier
2.1.2 Utilisation des fonctions
Les définitions de fonctions doivent être placées dans des fichiers séparés, lesquels sont inclus avec l’instruction require() ou require_once() au début de chaque script qui fait appel à elles Voici l’exemple 1.6, page 37, qui donnait un premier exemple d’accès à la base MySQL à partir d’un script PHP, maintenant réécrit avec quelques-unes des fonctions précédentes
Exemple 2.3 exemples/ExMyPHP4.php:L’exemple 1.6, avec des fonctions
<? xml v e r s i o n = " 1 0 " e n c o d i n g = " i s o−8959−1 " ? >
<!DOCTYPE html PUBLIC "−//W3C/ / DTD XHTML 1 0 S t r i c t / / EN"
" h t t p : / / www w3 o r g / TR / xhtml1 /DTD/ xhtml1−s t r i c t dtd ">
Trang 3<html xmlns= " h t t p : / / www w3 o r g / 1 9 9 9 / xhtml " xml : l a n g = " f r " >
<head >
< t i t l e >Connexion à MySQL< / t i t l e >
< l i n k r e l = ’ s t y l e s h e e t ’ h r e f = " f i l m s c s s " t y p e = " t e x t / c s s " / >
</ head >
<body >
<h1> I n t e r r o g a t i o n de l a t a b l e F i l m S i m p l e < / h1>
<? php
r e q u i r e _ o n c e ( " Connect php " ) ;
r e q u i r e _ o n c e ( " Connexion php " ) ;
r e q u i r e _ o n c e ( " E x e c R e q u e t e php " ) ;
$ c o n n e x i o n = Connexion (NOM, PASSE , BASE , SERVEUR) ;
$ r e s u l t a t = E x e c R e q u e t e ( " SELECT ∗ FROM FilmSimple " , $connexion ) ;
w h i l e ( $ f i l m = O b j e t S u i v a n t ( $ r e s u l t a t ) )
echo " <b> $ f i l m−>t i t r e </ b > , paru en $film −>annee , r é a l i s é "
" p a r $ f i l m−>p r e n o m _ r e a l i s a t e u r $film −>n o m _ r e a l i s a t e u r < br />\n" ;
? >
</ body >
</ html >
On peut apprécier l’économie réalisée dans la taille du code et la lisibilité qui
en résulte Entre autres avantages, il faut noter qu’il n’y a plus dans ce script aucune référence à MySQL Le jour ó l’on choisit d’utiliser – par exemple – PostgreSQL, les modifications ne touchent que les fonctions d’accès à la base et restent transparentes pour les autres scripts La portabilité d’un code MySQL/PHP sur plusieurs SGBD sera développée dans le chapitre 3
2.1.3 À propos de require et include
Il existe deux instructions pour inclure du code dans un fichier, require (et sa variante require_once) et include La différence est subtile :
• require(fichier ) se contente d’inclure le code de fichier dans le script
courant, et tout se passe ensuite comme si l’instruction require avait été
définitivement remplacée par le contenu de fichier ;
• include(fichier ), en revanche, correspond à une inclusion répétitive de
fichier, chaque fois que l’instruction est rencontrée.
En général, c’est une mauvaise pratique que de placer des instructions dans un fichier pour l’exécuter avec require ou include Le danger vient du fait que les variables manipulées dans les fichiers inclus viennent se confondre avec celles du script principal, avec des résultats imprévisibles et surtout difficilement détectables
Trang 4L’utilisation de fonctions est bien préférable car les variables des fonctions sont locales, et l’interaction avec le script se limite aux arguments de la fonction, faci-lement identifiables
En conclusion, il est fortement recommandé d’utiliser seulement require, et de
ne placer dans les fichiers inclus que des définitions de fonctions ou de constantes On
est sûr alors que le script ne contient ni variables ni instructions cachées La fonction
include() devrait être réservée aux cas ó il faut déterminer, à l’exécution, le fichier
à inclure Un exemple possible est un site multi-langues dans lequel on crée un fichier pour chaque langue gérée
Il est possible d’utiliser require récursivement Voici par exemple le fichier
UtilBD.php que nous utiliserons par la suite pour inclure en une seule fois les décla-rations de constantes et de fonctions pour l’accès à MySQL
Exemple 2.4 exemples/UtilBD.php:Un fichier global d’inclusion des constantes et fonctions
<? php
/ / F o n c t i o n s e t d é c l a r a t i o n s p o u r l ’ a c c è s à MySQL
r e q u i r e _ o n c e ( " Connect php " ) ;
r e q u i r e _ o n c e ( " Connexion php " ) ;
r e q u i r e _ o n c e ( " E x e c R e q u e t e php " ) ;
? >
La variante require_once assure qu’un fichier n’est pas inclus deux fois dans un script (ce qui peut arriver lors d’inclusion transitives, un fichier qui en inclut un autre qui en inclut un troisième )
2.1.4 Passage par valeur et passage par référence
Une fonction prend en entrée des paramètres et renvoie une valeur qui peut alors être stockée dans une variable du script appelant, ou transmise comme paramètre à une
autre fonction Les paramètres sont passés par valeur en PHP En d’autres termes, le
programme appelant et la fonction disposent chacun d’un espace de stockage pour les
valeurs de paramètres, et l’appel de la fonction déclenche la copie des valeurs depuis
l’espace de stockage du programme appelant vers l’espace de stockage de la fonction
REMARQUE –Attention, les objets sont passés par référence depuis la version 5 de PHP.
La conséquence essentielle est qu’une fonction ne peut pas modifier les variables
du programme appelant puisqu’elle n’a pas accès à l’espace de stockage de ce der-nier Une fonction effectue une ou plusieurs opérations, renvoie éventuellement le résultat, mais ne modifie pas ses paramètres Il s’agit d’une caractéristique importante (« pas d’effet de bord ») pour la lisibilité et la robustesse d’un programme Elle permet en effet d’estimer avec certitude, en regardant un script constitué d’appels
de fonctions, quel est l’effet de chacune Ce n’est malheureusement plus vrai dès que l’on recours à des pratiques comme l’utilisation de variables globales et le passage par référence
N’utilisez pas de variables globales si vous voulez garder un code sain Quant au
passage des paramètres par référence, il est possible en PHP La notion de référence
Trang 5(identique à celle du C++) correspond à la possibité de désigner un même contenu par plusieurs variables Soit par exemple le fragment suivant
$a = 3;
$b = &$a;
Les variables $a et $b référencent alors le même contenu, dont la valeur est pour l’instant 3 Toute modification du contenu par l’intermédiaire de $a sera visible de
$b et réciproquement Par exemple :
$a = 5;
echo $b; // Affiche la valeur 5
Il faut souligner, pour ceux qui sont familiers avec le langage C, que les références
ne sont pas des pointeurs puisque, contrairement à ces derniers, une référence est
un symbole désignant un contenu pré-existant (celui d’une autre variable) Pour la question qui nous intéresse ici, elles peuvent cependant servir, comme les pointeurs
C, à permettre le partage entre un contenu manipulé par un script et ce même
contenu manipulé par une fonction En passant en effet à une fonction la référence r
à une variable v du script appelant, toute modification effectuée par la fonction sur r impactera v.
Il est tentant d’utiliser le passage par référence dans (au moins) les deux cas suivants :
1 pour des fonctions qui doivent renvoyer plusieurs valeurs ;
2 quand les paramètres à échanger sont volumineux et qu’on craint un impact négatif sur les performances
En ce qui concerne le premier point, on peut remplacer le passage par référence par le renvoi de valeurs complexes, tableaux ou objets Voici un exemple comparant les deux approches Le premier est une fonction qui prend des références sur les variables du script principal et leur affecte le jour, le mois et l’année courante Les variables ceJour, ceMois et cetteAnnee sont des références, et permettent donc d’accéder au même contenu que les variables du script appelant la fonction Notez
que le passage par référence est obtenu dans la déclaration de la fonction en préfixant
par & le nom des paramètres
Exemple 2.5 exemples/References.php:Fonction avec passage par référence.
<? php
/ / E x e m p l e d e f o n c t i o n r e n v o y a n t p l u s i e u r s v a l e u r s g r â c e à un / / p a s s a g e p a r r é f é r e n c e s
f u n c t i o n a u j o u r d h u i _ r e f (& $ c e J o u r , &$ceMois , &$ c e t t e A n n e e )
{
/ / On c a l c u l e l e j o u r , l e m o i s e t l ’ a n n é e c o u r a n t e
$ c e J o u r = d a t e ( ’ d ’ ) ;
$ c e M o i s = d a t e ( ’m ’ ) ;