Au moment ó on effectuera une instanciation d’un objet de la classe BDMySQL, l’exécution se déroulera comme suit : • le constructeur défini dans la classe BD sera appelé, puisqu’il est h
Trang 1i f ( ! $ t h i s−>connexion = @mysql_pconnect ( $ s e r v e u r , $log in ,
$ m o t _ d e _ p a s s e ) )
r e t u r n 0 ;
/ / 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 ( $ t h i s−>nom_base , $ t h i s −>connexion ) )
r e t u r n 0 ;
r e t u r n $ t h i s−>connexion ;
}
/ / M é t h o d e d ’ e x é c u t i o n d ’ u n e r e q u ê t e
p r o t e c t e d f u n c t i o n e x e c ( $ r e q u e t e )
{ r e t u r n @ m y s q l _ q u e r y ( $ r e q u e t e , $ t h i s−>connexion ) ; }
/ / P a r t i e p u b l i q u e : i m p l a n t a t i o n d e s m é t h o d e s a b s t r a i t e s
/ / A c c è s à l a l i g n e s u i v a n t e , s o u s f o r m e d ’ o b j e t
p u b l i c 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 ) ; }
/ / A c c è s à l a l i g n e s u i v a n t e , s o u s f o r m e d e t a b l e a u a s s o c i a t i f
p u b l i c 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 ) ; }
/ / A c c è s à l a l i g n e s u i v a n t e , s o u s f o r m e d e t a b l e a u i n d i c é
p u b l i c f u n c t i o n t a b l e a u 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 _ r o w ( $ r e s u l t a t ) ; }
/ / E c h a p p e m e n t d e s a p o s t r o p h e s e t a u t r e s p r é p a r a t i o n à
/ / l ’ i n s e r t i o n
p u b l i c f u n c t i o n p r e p a r e C h a i n e ( $ c h a i n e )
{ r e t u r n m y s q l _ r e a l _ e s c a p e _ s t r i n g ( $ c h a i n e ) ; }
/ / R e t o u r du m e s s a g e d ’ e r r e u r
p u b l i c f u n c t i o n messageSGBD ( )
{ r e t u r n m y s q l _ e r r o r ( $ t h i s−>connexion ) ; }
/ / M é t h o d e a j o u t é e : r e n v o i e l e s c h é m a d ’ u n e t a b l e
p u b l i c f u n c t i o n s c h e m a T a b l e ( $ n o m _ t a b l e )
{
/ / R e c h e r c h e d e l a l i s t e d e s a t t r i b u t s d e l a t a b l e
$ l i s t e _ a t t r = @ m y s q l _ l i s t _ f i e l d s ( $ t h i s−>nom_base ,
$ n o m _ t a b l e , $ t h i s−>connexion ) ;
i f ( ! $ l i s t e _ a t t r ) t h r o w new E x c e p t i o n ( " Pb d ’ a n a l y s e de
$ n o m _ t a b l e " ) ;
/ / R e c h e r c h e d e s a t t r i b u t s e t s t o c k a g e d a n s l e t a b l e a u
f o r ( $ i = 0 ; $ i < m y s q l _ n u m _ f i e l d s ( $ l i s t e _ a t t r ) ; $ i ++) {
$nom = m y s q l _ f i e l d _ n a m e ( $ l i s t e _ a t t r , $ i ) ;
$schema [ $nom ] [ ’ l o n g u e u r ’ ] = m y s q l _ f i e l d _ l e n ( $ l i s t e _ a t t r , $ i ) ;
$schema [ $nom ] [ ’ t y p e ’ ] = m y s q l _ f i e l d _ t y p e ( $ l i s t e _ a t t r , $ i ) ;
$schema [ $nom ] [ ’ c l e _ p r i m a i r e ’ ] =
Trang 2s u b s t r _ c o u n t ( m y s q l _ f i e l d _ f l a g s ( $ l i s t e _ a t t r , $ i ) , "
p r i m a r y _ k e y " ) ;
$schema [ $nom ] [ ’ n o t _ n u l l ’ ] =
s u b s t r _ c o u n t ( m y s q l _ f i e l d _ f l a g s ( $ l i s t e _ a t t r , $ i) , " n o t _ n u l l ") ;
}
r e t u r n $schema ;
}
/ / D e s t r u c t e u r d e l a c l a s s e : on s e d é c o n n e c t e
f u n c t i o n _ _ d e s t r u c t ( )
{ i f ( $ t h i s−>connexion ) @ m y s q l _ c l o s e ( $ t h i s−>connexion ) ; }
/ / F i n d e l a c l a s s e
}
? >
On peut noter que la redéfinition du constructeur est inutile puisqu’il est déjà fourni au niveau de la classe parente En revanche, il faut en définir la partie spécifique, soit les méthodes connect() et exec() Au moment ó on effectuera une instanciation d’un objet de la classe BDMySQL, l’exécution se déroulera comme suit :
• le constructeur défini dans la classe BD sera appelé, puisqu’il est hérité, et non surchargé ;
• ce constructeur appelle à son tour la méthode connect() qui, elle, est définie
au niveau de la classe BDMySQL
Le constructeur lèvera une exception si la méthode connect() échoue On a bien l’interaction souhaitée entre le code générique de la classe parente et le code spécifique de la classe dérivée Le même mécanisme s’applique à l’exécution de requêtes, avec la méthode générique execRequete() appelant la méthode spéci-fique exec() (ainsi, éventuellement, que la méthode messageSGBD()), et levant une exception si nécessaire en fonction du retour de cette dernière Cela étant, une classe publique de la super-classe peut toujours être surchargée Si on souhaite par exemple lever deux exceptions différentes, une pour l’erreur de connexion au serveur
et l’autre pour l’erreur d’accès à une base, on peut redéfinir un constructeur pour la classe BDMySQL comme suit :
f u n c t i o n _ _ c o n s t r u c t ( $ l o g i n , $ m o t _ d e _ d a s s e , $ b a s e , $ s e r v e u r ) {
/ / On c o n s e r v e l e nom d e l a b a s e
$ t h i s−>nom_base = $ba s e ;
/ / C o n n e x i o n au s e r v e u r MySQL
i f ( ! $ t h i s−>connexion =
@ m y s q l _ p c o n n e c t ( $ s e r v e u r , $ l o g i n , $ m o t _ d e _ d a s s e ) )
t h r o w new E x c e p t i o n ( " E r r e u r de c o n n e x i o n au s e r v e u r " ) ;
/ / 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 ( $ t h i s−>nom_base , $ t h i s −>connexion ) )
Trang 3t h r o w new E x c e p t i o n ( " E r r e u r de c o n n e x i o n à l a b a s e " ) ;
}
Attention : quand une méthode est surchargée (donc redéfinie dans une classe dérivée), la méthode de la classe parente n’est plus appelée La surcharge est donc bien un remplacement de la méthode héritée C’est valable également pour le constructeur : la définition d’un constructeur pour la classe BDMySQL implique que le constructeur de la super-classe BD ne sera plus appelé au moment de l’instanciation d’un objet BDMySQL Il est cependant possible de faire l’appel explicitement grâce à
la syntaxe parent::BD() : voir l’exemple de la classe R´epertoire, page 128 Toutes les autres méthodes abstraites sont ensuite implantées par un simple appel
à la fonction correspondante de l’interface de programmation (API) MySQL Il est bien entendu possible d’étendre la puissance de la classe dérivée en lui ajoutant d’autres fonctionnalités de MySQL Ces méthodes seraient alors spécifiques aux instances de la classe BDMySQL et ne pourraient donc pas être appelées dans une application souhaitant pouvoir accéder à des SGBD différents et se fondant sur l’interface définie dans la super-classe BD
Regardons de plus près la méthode schemaTable Si tout se passe bien, elle renvoieun tableau associatif à deux dimensions décrivant pour chaque attribut (pre-mière dimension du tableau) les options de création de la table passée en paramètre (seconde dimension) Il s’agit à peu de choses près des informations du CREATE TABLE : longueur et type d’un attribut donné, et booléen indiquant si cet attribut fait partie de la clé primaire identifiant une ligne de la table
Cette fonction renvoie une valeur dont la taille peut être importante Cette
valeur, initialement stockée dans une variable locale de la méthode, schemaTable, doit ensuite être copiée vers une variable du script appelant Ce code est correct
mais on peut se poser la question de l’impact négatif sur les performances en cas d’appels intensifs à cette méthode pour des tables contenant beaucoup d’attributs L’utilisation d’un passage par référence peut alors s’envisager (voir la discussion page 61) On aurait le simple changement :
f u n c t i o n s c h e m a T a b l e ( $ n o m _ t a b l e , &$schema ) {
/ / Comme a v a n t
.
}
et la fonction alimenterait directement la variable du script appelant, dont on obtient ici une référence
La méthode schemaTable() est une méthode ajoutée (elle sera utilisée pour une autre classe, page 167) La déclarer sous forme de méthode abstraite au niveau de la classe BD enrichirait la spécification des interactions, mais imposerait l’implantation
de cette méthode dans toutes les sous-classes
Il reste à définir autant de sous-classes que de SGBD, soit ORACLE, ou Post-greSQL, ou encore SQLite, un moteur SQL directement intégré à PHP depuis la version 5, etc La classe ci-dessous correspond à PostgreSQL
Trang 4Exemple 3.5 exemples/BDPostgreSQL.php:La classe dérivée BDPostgreSQL
<? php
/ / S o u s−c l a s s e de l a c l a s s e a b s t r a i t e BD, i m p l a n t a n t l ’ a c c è s à / / P o s t g r e S Q L
r e q u i r e _ o n c e ( "BD php " ) ;
c l a s s BDPostgreSQL e x t e n d s BD
{
/ / P a s d e p r o p r i é t é s : e l l e s s o n t h é r i t é e s d e l a c l a s s e BD
/ / P a s d e c o n s t r u c t e u r : l u i a u s s i e s t h é r i t é
/ / M é t h o d e c o n n e c t : c o n n e x i o n à P o s t g r e S Q L
p r o t e c t e d f u n c t i o n c o n n e c t ( $ l o g i n , $ m o t _ d e _ p a s s e , $ b a s e ,
$ s e r v e u r )
{
/ / Q u e l q u e s a j u s t e m e n t s P o s t g r e S Q L
$ l o g i n = s t r T o L o w e r ( $ l o g i n ) ; $ b a s e = s t r T o L o w e r ( $ b a s e ) ;
i f ( $ s e r v e u r == ’ l o c a l h o s t ’ ) $ s e r v e u r = " " ;
/ / C r é a t i o n d e l a c h a î n e d e c o n n e x i o n
$chaineC = " u s e r = $ l o g i n dbname= $ b a s e p a s s w o r d = $ m o t _ d e _ p a s s e
h o s t = $ s e r v e u r " ;
/ / C o n n e x i o n au s e r v e u r e t à l a b a s e
r e t u r n $ t h i s−>connexion = pg_connect ( $chaineC ) ;
}
/ / M é t h o d e d ’ e x é c u t i o n d ’ u n e r e q u ê t e
p r o t e c t e d f u n c t i o n e x e c ( $ r e q u e t e )
{ r e t u r n @pg_exec ( $ t h i s−>connexion , $ r e q u e t e ) ; }
/ / −−−− P a r t i e p u b l i q u e −−−−−−−−−−−−−−−−−−−−−−−−−
/ / A c c è s à l a l i g n e s u i v a n t e , s o u s f o r m e d ’ o b j e 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 p g _ f e t c h _ o b j e c t ( $ r e s u l t a t ) ; }
/ / A c c è s à l a l i g n e s u i v a n t e , s o u s f o r m e d e t a b l e a u a s s o c i a t i f
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 p g _ f e t c h _ a s s o c ( $ r e s u l t a t ) ; }
/ / A c c è s à l a l i g n e s u i v a n t e , s o u s f o r m e d e t a b l e a u i n d i c é
f u n c t i o n t a b l e a u S u i v a n t ( $ r e s u l t a t )
{ r e t u r n p g _ f e t c h _ r o w ( $ r e s u l t a t ) ; }
/ / E c h a p p e m e n t d e s a p o s t r o p h e s e t a u t r e s p r é p a r a t i o n s à
/ / l ’ i n s e r t i o n
p u b l i c f u n c t i o n p r e p a r e C h a i n e ( $ c h a i n e )
{ r e t u r n a d d S l a s h e s ( $ c h a i n e ) ; }
/ / R e t o u r du m e s s a g e d ’ e r r e u r
p u b l i c f u n c t i o n messageSGBD ( )
{ r e t u r n p g _ l a s t _ e r r o r ( $ t h i s−>connexion ) ; }
/ / D e s t r u c t e u r d e l a c l a s s e : on s e d é c o n n e c t e
Trang 5f u n c t i o n _ _ d e s t r u c t ( )
{ @ p g _ c l o s e ( $ t h i s−>connexion ) ; }
/ / F i n d e l a c l a s s e
}
? >
On retrouve la même structure que pour BDMySQL, avec l’appel aux fonctions cor-respondantes de PostgreSQL, et la prise en compte de quelques spécificités Caracté-ristique (assez désagréable ) de l’interface PHP/PostgreSQL : tous les identificateurs (noms de tables, d’attributs, de base, etc.) sont systématiquement traduits en minus-cules, ce qui impose quelques conversions avec la fonction PHP strToLower() (voir
la méthode connect() ci-dessus) De plus, pour la connexion au serveur localhost,
PostgreSQL demande que le nom du serveur soit la chaîne vide Ces particularités peuvent être prises en compte au moment de l’implantation des méthodes abstraites
On peut maintenant considérer qu’un objet instance de la classe BDMySQL ou un objet instance de la classe BDPostgreSQL sont tous deux conformes au
comporte-ment décrit dans la super-classe commune, BD On peut donc les utiliser exactecomporte-ment
de la même manière si on se limite au comportement commun défini dans cette super-classe Le script suivant montre un code qui, hormis le choix initial de la classe à instancier, fonctionne aussi bien pour accéder à MySQL que pour accéder à PostgreSQL (ou SQLite, ou ORACLE, ou tout autre système pour lequel on définira une sous-classe de BD)
Exemple 3.6 exemples/ApplClasseBD.php:Accès générique à un SGBD.
<? 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 ">
<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 > A p p l i c a t i o n de l a c l a s s e BD< / 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> A p p l i c a t i o n de l a c l a s s e BD< / h1>
<? php
r e q u i r e _ o n c e ( " Connect php " ) ;
/ / La s o u s −c l a s s e p o u r MySQL
r e q u i r e _ o n c e ( "BDMySQL c l a s s php " ) ;
/ / La s o u s −c l a s s e p o u r Po s t gr eSQ L
r e q u i r e _ o n c e ( " BDPostgreSQL c l a s s php " ) ;
/ / La s o u s −c l a s s e p o u r SQLite
r e q u i r e _ o n c e ( " BDSQLite c l a s s php " ) ;