3.2.3 ImplantationIl reste à regarder le code de la classe pour voir comment les différentes méthodes sont implantées.. Une nouveauté syntaxique, non rencon-trée jusqu’à présent, est la
Trang 13.2.3 Implantation
Il reste à regarder le code de la classe pour voir comment les différentes méthodes
sont implantées Rappelons que la consultation du code est inutile si on souhaite seulement utiliser la classe D’ailleurs dans des langages compilés comme C++ et Java,
le code n’est pas disponible ; seules les spécifications de l’interface sont fournies aux utilisateurs
Le code de la classe tableau est bien entendu disponible sur le site de ce livre Nous allons présenter les parties les plus importantes, en les commentant à chaque fois Pour commencer, on trouve les propriétés, toutes privées
c l a s s T a b l e a u
{
/ / −−−− P a r t i e p r i v é e : l e s c o n s t a n t e s e t l e s v a r i a b l e s
p r i v a t e $ n b _ d i m e n s i o n s ;
/ / T a b l e a u d e s v a l e u r s à a f f i c h e r
p r i v a t e $ t a b l e a u _ v a l e u r s ;
/ / T a b l e a u x d e s en −t ê t e s
p r i v a t e $ e n t e t e s , $ o p t i o n s _ l i g , $ o p t i o n s _ c o l ;
/ / O p t i o n s d e p r é s e n t a t i o n p o u r l a t a b l e A c o m p l é t e r
p r i v a t e $ o p t i o n s _ t a b l e s , $ c o u l e u r _ p a i r e , $ c o u l e u r _ i m p a i r e ,
$ c s g , $ a f f i c h e _ e n t e t e , $ r e p e t i t i o n _ l i g n e = a r r a y ( ) ,
$ o p t i o n _ d i m = a r r a y ( ) ;
/ / C o n s t a n t e p o u r r e m p l i r l e s c e l l u l e s v i d e s
c o n s t VAL_DEFAUT= "&n b s p ; " ;
On trouve la dimension du tableau, le tableau des valeurs (M[c1][c2] dans la
modé-lisation) et le tableau des en-têtes (e[d, c] dans la modémodé-lisation) Les autres attributs
sont tous destinés à la présentation HTML Une nouveauté syntaxique, non rencon-trée jusqu’à présent, est la définition d’une constante locale à la classe, qui peut être référencée avec la syntaxe self::VAL_DEFAUT ou Tableau::VAL_DEFAUT
Le constructeur, donné ci-dessous, effectue essentiellement des initialisations Il manque de nombreux tests pour améliorer la robustesse de la classe Je vous invite
à y réfléchir et ajouter les contrôles et levées d’exceptions nécessaires (ne faudrait-il pas par exemple s’inquiéter des valeurs possibles de la dimension ?)
f u n c t i o n _ _ c o n s t r u c t ( $ n b _ d i m e n s i o n s =2 , $ t a b _ a t t r s = a r r a y ( ) )
{
/ / I n i t i a l i s a t i o n d e s v a r i a b l e s p r i v é e s
$ t h i s−>t a b l e a u _ v a l e u r s = a r r a y ( ) ;
$ t h i s−>o p t i o n s _ t a b l e s = $ t h i s −>c o u l e u r _ p a i r e = $ t h i s −>
c o u l e u r _ i m p a i r e = " " ;
/ / I n i t i a l i s a t i o n d e l a d i m e n s i o n Q u e l q u e s t e s t s s ’ i m p o s e n t / /
$ t h i s−>nb_dimensions=$nb_dimensions ;
/ / I n i t i a l i s a t i o n d e s t a b l e a u x d ’ en−t ê t e s p o u r c h a q u e
d i m e n s i o n
f o r ( $dim = 1 ; $dim <= $ t h i s−>nb_dimensions ; $dim++) {
Trang 2$ t h i s−>e n t e t e s [ $dim ] = a r r a y ( ) ;
$ t h i s−>a f f i c h e _ e n t e t e [ $dim ] = TRUE;
}
/ / A t t r i b u t s d e l a b a l i s e < t a b l e >
$ t h i s−>a j o u t A t t r i b u t s T a b l e ( $ t a b _ a t t r s ) ;
}
Les méthodes commençant set ou get, traditionnelles en programmation objet,
ne servent à rien d’autre le plus souvent qu’à accéder, en écriture ou en lecture, aux propriétés de la classe (on parle parfois d’« accesseurs ») En voici un exemple avec la méthode setCouleurImpaire() qui affecte la couleur de fond des lignes impaires
p u b l i c f u n c t i o n s e t C o u l e u r I m p a i r e ( $ c o u l e u r ) {
$ t h i s−>c o u l e u r I m p a i r e = $ c o u l e u r ;
}
Bien entendu, il suffirait de rendre publique la propriété couleur_impaire pour éviter d’écrire une méthode spéciale Les scripts pourraient alors directement la modifier Cela rendrait malheureusement définitivement impossible toute évolution ultérieure pour contrôler la valeur affectée à couleur_impaire Plus généralement, rendre publique une propriété empêche toute modification ultérieure apportée à l’organisation interne d’une classe
REMARQUE –PHP 5 fournit des méthodes dites « magiques » pour éviter la programmation systématique des accesseurs La méthode get(nom )est appelée chaque fois que l’on utilise la syntaxe$o->nom pour lire une propriété qui n’existe pas explicitement dans la
classe ; set(nom, valeur )est appelée quand on utilise la même syntaxe pour faire une affectation Enfin, call(nom, params )intercepte tous les appels à une méthode qui n’existe pas Des exemples de ces méthodes sont donnés page 267.
La méthode ajoutValeur() insère une nouvelle valeur dans une cellule dont les coordonnées sont données par les deux premiers paramètres Voici son code Notez qu’on en profite pour affecter une valeur par défaut (la valeur de la clé elle-même) à l’en-tête de la ligne et de la colonne correspondante Ici encore quelques contrôles (par exemple sur les paramètres en entrée) seraient les bienvenus
p u b l i c f u n c t i o n a j o u t V a l e u r ( $ c l e _ l i g n e , $ c l e _ c o l o n n e , $ v a l e u r ) {
/ / M a i n t e n a n c e d e s en−t ê t e s
i f ( ! a r r a y _ k e y _ e x i s t s ( $ c l e _ l i g n e , $ t h i s−>e n t e t e s [ 1 ] ) )
$ t h i s−>e n t e t e s [ 1 ] [ $ c l e _ l i g n e ] = $ c l e _ l i g n e ;
i f ( ! a r r a y _ k e y _ e x i s t s ( $ c l e _ c o l o n n e , $ t h i s−>e n t e t e s [ 2 ] ) )
$ t h i s−>e n t e t e s [ 2 ] [ $ c l e _ c o l o n n e ] = $ c l e _ c o l o n n e ;
/ / S t o c k a g e d e l a v a l e u r
$ t h i s−>t a b l e a u _ v a l e u r s [ $ c l e _ l i g n e ] [ $ c l e _ c o l o n n e ] = $ v a l e u r ;
}
Le code donné ci-dessus fonctionne pour les tableaux à deux dimensions Pour les tableaux de dimension quelconque, l’implantation est un peu plus compliquée, mais figure dans le code fourni sur le site
Trang 3Troisième méthode importante, ajoutEntete() se contente d’affecter un texte
à l’en-tête d’une ligne ou d’une colonne (selon la dimension passée en paramètre) pour une valeur de clé donnée Comme on l’a vu ci-dessus, par défaut cet en-tête sera la clé elle-même, ce qui peut convenir dans beaucoup de cas
p u b l i c f u n c t i o n a j o u t E n t e t e ( $ d i m e n s i o n , $ c l e , $ t e x t e )
{
/ / S t o c k a g e d e l a c h a î n e s e r v a n t d ’ en−t ê t e
$ t h i s−>e n t e t e s [ $dimension ] [ $ c l e ] = $ t e x t e ;
}
Il reste finalement (en ignorant d’autres méthodes annexes que je vous laisse consulter directement dans le code) la méthode produisant le tableau HTML Par-tant de toutes les mesures reçues au fur et à mesure et stockées dans les propriétés d’un objet, cette méthode construit une chaîne de caractères contenant les balises HTML appropriées Le code ci-dessous est une version légèrement simplifiée de la méthode complète
f u n c t i o n tableauHTML ( )
{
$ c h a i n e = $ l i g n e = " " ;
/ / A f f i c h e −t ’ on l e c o i n s u p é r i e u r g a u c h e ?
i f ( $ t h i s−>a f f i c h e _ e n t e t e [ 1 ] ) $ l i g n e = "<th > $ t h i s −>csg </ th >" ;
i f ( ! empty ( $ t h i s−>l e g e n d e ) ) {
$ n b _ c o l s = c o u n t ( $ t h i s−>e n t e t e s [ 2 ] ) ;
$ c h a i n e = " < t r c l a s s = ’ h e a d e r ’ >\n< t h c o l s p a n = $ n b _ c o l s >
$ t h i s−>l e g e n d e "
" </ th >\n < / t r >\n " ; }
/ / C r é a t i o n d e s e n t −ê t e s de c o l o n n e s ( d i m e n s i o n 2)
i f ( $ t h i s−>a f f i c h e _ e n t e t e [ 2 ] ) {
f o r e a c h ( $ t h i s−>e n t e t e s [ 2 ] a s $ c l e => $ t e x t e )
$ l i g n e = " <th > $ t e x t e < / th >\n " ;
/ / L i g n e d e s en−t ê t e s
$ c h a i n e = " < t r c l a s s = ’ h e a d e r ’ > $ l i g n e < / t r >\n " ; }
$ i = 0 ;
/ / B o u c l e s i m b r i q u é e s s u r l e s d e u x t a b l e a u x d e c l é s
f o r e a c h ( $ t h i s−>e n t e t e s [ 1 ] a s $ c l e _ l i g => $ e n t e t e L i g ) / /
L i g n e s
{
i f ( $ t h i s−>a f f i c h e _ e n t e t e [ 1 ] )
$ l i g n e = " <th > $ e n t e t e L i g < / th >\n " ;
e l s e
$ l i g n e = " " ;
$ i ++;
Trang 4f o r e a c h ( $ t h i s−>e n t e t e s [ 2 ] a s $ c l e _ c o l => $e n t e t e C ol ) / /
C o l o n n e s
{
/ / On p r e n d l a v a l e u r s i e l l e e x i s t e , s i n o n l e d é f a u t
i f ( i s S e t ( $ t h i s−>t a b l e a u _ v a l e u r s [ $ c l e _ l i g ] [ $ c l e _ c o l ] )
)
$ v a l e u r = $ t h i s−>t a b l e a u _ v a l e u r s [ $ c l e _ l i g ] [ $ c l e _ c o l ] ;
e l s e
$ v a l e u r = s e l f : : VAL_DEFAUT ;
/ / On p l a c e l a v a l e u r d a n s u n e c e l l u l e
$ l i g n e = " <td > $ v a l e u r < / td >\n " ; }
/ / E v e n t u e l l e m e n t on t i e n t c o m p t e d e l a c o u l e u r
i f ( $ i % 2 == 0 ) {
$ o p t i o n s _ l i g = " c l a s s = ’ even ’ " ;
i f ( ! empty ( $ t h i s−>c o u l e u r _ p a i r e ) )
$ o p t i o n s _ l i g = " b g c o l o r = ’ $ t h i s−>c o u l e u r _ p a i r e ’ " ;
}
e l s e i f ( $ i % 2 == 1 ) {
$ o p t i o n s _ l i g = " c l a s s = ’ odd ’ " ;
i f ( ! empty ( $ t h i s−>c o u l e u r _ i m p a i r e ) )
$ o p t i o n s _ l i g = " b g c o l o r = ’ $ t h i s−>c o u l e u r _ i m p a i r e ’ " ;
}
e l s e $ o p t i o n s _ l i g = " " ;
/ / D o i t −on a p p l i q u e r une o p t i o n ?
i f ( i s S e t ( $ t h i s−>o p t i o n s [ 1 ] [ $ c l e _ l i g ] ) )
f o r e a c h ( $ t h i s−>o p t i o n s [ 1 ] [ $ c l e _ l i g ] a s $option =>
$ v a l e u r )
$ o p t i o n s _ l i g = " $ o p t i o n = ’ $ v a l e u r ’ " ;
$ l i g n e = " < t r $ o p t i o n s _ l i g >\ n $ l i g n e \n < / t r >\n " ;
/ / P r i s e e n c o m p t e d e l a d e m a n d e d e r é p é t i t i o n d ’ u n e / / l i g n e
i f ( i s S e t ( $ t h i s−> r e p e t i t i o n _ l i g n e [ 1 ] [ $ c l e _ l i g ] ) ) {
$ r l i g n e = " " ;
f o r ( $ i = 0 ; $ i < $ t h i s−> r e p e t i t i o n _ l i g n e [ 1 ] [ $ c l e _ l i g ] ;
$ i ++)
$ r l i g n e = $ l i g n e ;
$ l i g n e = $ r l i g n e ; }
/ / On a j o u t e l a l i g n e à l a c h a î n e
$ c h a i n e = $ l i g n e ; }
/ / P l a c e m e n t d a n s l a b a l i s e TABLE, e t r e t o u r
r e t u r n " < t a b l e $ t h i s−>o p t i o n s _ t a b l e s >\n$chaine </ t a b l e >\n " ;
}
Trang 5Le tableau associatif entetes contient toutes les clés permettant d’accéder aux cellules stockées dans le tableau tableau_valeurs, ainsi que les libellés associés à ces clés et utilisés pour les en-têtes Il suffit donc d’une boucle sur chaque dimension pour récupérer les coordonnées d’accès à la cellule, que l’on peut alors insérer dans des balises HTML Pour le tableau B par exemple, le contenu du tableau entetes, tel qu’on peut le récupérer avec la fonction PHP print_r() qui affiche tous les éléments d’un tableau, est le suivant :
• dimension 1 :
Array ( [Matrix] => Matrix [Spiderman] => Spiderman )
• dimension 2 :
Array ( [1] => Semaine 1 [2] => Semaine 2 [3] => Semaine 3 )
En parcourant les clés à l’aide des boucles imbriquées de la méthode
tableauHTML(), on obtient les paires (Matrix, 1), (Matrix, 2), (Matrix, 3), puis (Spiderman, 1), (Spiderman, 2), (Spiderman, 3) Chaque paire (cl´e1, cl´e2) définit une entrée tableauValeurs[cle1][cle2]
Voici un deuxième exemple de classe « utilitaire » visant à produire du code HTML complexe, en l’occurrence une classe Formulaire pour générer des formulaires HTML Outre la création des champs de saisie, cette classe permet de soigner
la présentation des formulaires en alignant les champs et les textes explicatifs à l’aide de tableaux HTML3 Comme précédemment, nous cherchons à obtenir des fonctionnalités puissantes par l’intermédiaire d’une interface la plus simple possible,
en cachant donc au maximum la complexité du code
3.3.1 Conception
Comme pour la classe Tableau, il faut fixer précisément le type de service qui sera fourni par la classe en cherchant un bon compromis entre les fonctionnalités, et la complexité de leur utilisation
Le premier rôle de la classe est de permettre la création de champs de saisie, conformes à la spécification HTML, avec toutes les options possibles : taille affichée, taille maximale, valeur par défaut et même contrôles Javascript Un objet de la classe devra donc servir « d’usine » à fabriquer ces champs en utilisant des méthodes dédiées auxquelles on passe les paramètres appropriés De plus chaque champ doit pouvoir être accompagné d’un libellé indiquant sa destination On pourra par exemple disposer d’une méthode de création d’un champ de saisie de texte :
champTexte (libell´ e, nomChamp, valeurD´ efaut, tailleAffich´ ee, tailleMax )
3 Il est également possible d’obtenir cet alignement avec des feuilles de style CSS.