2.6 SQL dynamique et affichage multi-pages 113 } else { $position = $_GET[ ’position ’ ]; } // Affichage des ancres pour les groupes qui suivent et /ou // précèdent if ($position > TAILLE_GROUPE) { // Il y a des lignes à voir avant $avant = $position − TAILLE_GROUPE ; echo "<a href=’ExecSQL.php? position=$avant&requete= $requeteCodee ’>" . " Voir l e s " . TAILLE_GROUPE . " l i g n e s p récédentes </a><br/>\n"; } if ($position + TAILLE_GROUPE − 1<mysql_num_rows($resultat)) { // Il y a des lignes à voir après $apres = $position + TAILLE_GROUPE ; echo "<a href=’ExecSQL.php? position=$apres&requete= $requeteCodee ’>" . " Voir l e s " . TAILLE_GROUPE . " l i g n e s s u i v an t es </ a>< b r />\n " ; } // Affichage du résultat AfficheResultat ($resultat , $position , TAILLE_GROUPE ) ; } ?> </body> </html> Le script comprend deux parties. Dans la première on présente un simple for- mulaire permettant de saisir une requête SQL (on réaffiche comme texte par défaut la requête saisie précédemment le cas échéant). La seconde partie, en PHP, est plus intéressante. Tout d’abord, on commence par récupérer la requête transmise par post ou get (on utilise donc le tableau $_REQUEST qui contient les deux, voir page 22), et on l’exécute. Notez qu’aucun traitement n’est appliqué à la requête car on suppose que l’utilisateur entre une syntaxe correcte, y compris l’échappement pour les « ’ » dans les critères de sélection. Ensuite, on regarde quelle est la partie du résultat à afficher. Si l’on vient du formulaire, la variable $submit est définie, et la position de départ est toujours 1. Sinon, la position est transmise dans l’URL (méthode get) et on la récupère. On peut alors créer une ou deux ancres, selon le cas, pour accéder aux 10 lignes précédentes et/ou aux 10 lignes suivantes. Bien entendu, cela n’a pas de sens de proposer les lignes précédentes si l’on est en train d’afficher la première, ni d’afficher les 10 suivantes si l’on affiche la dernière. La fonction mysql_num_rows() donne la position de la dernière ligne. L’URL contient les deux paramètres indispensables au bon fonctionnement du script, à savoir la position et la requête (traitée avec urlEncode()). Remarquez qu’il serait possible dès le départ d’afficher une ancre pour chacun des groupes de lignes constituant le résultat de la requête (« les dix premiers », « les dix suivants », etc.). 114 Chapitre 2. Techniques de base Finalement, l’appel à la fonction AfficheResultat() avec les paramètres appropriés se charge de l’affichage (figure 2.9). Figure 2.9 — Le formulaire d’interrogation, avec affichage multi-pages Cette technique « simule » une interactivité avec l’utilisateur par réaffichage d’un contenu modifié en fonction du contexte (ici la position courante), contenu lui-même obtenu par une opération (la saisie d’une requête) qui a pu s’effectuer long- temps auparavant. En d’autres termes, comme dans le cas des sessions, on établit une continuité de dialogue avec l’internaute en palliant les faiblesses de HTTP/HTML : • l’absence d’interactivité d’une page HTML (sauf à recourir à des techniques sophistiquées comme JavaScript ou Flash) est compensée par des appels répé- tés au serveur ; • HTTP ne gardant aucune mémoire des accès précédents, on prend soin de fournir les informations cruciales décrivant le contexte dans les messages (ici, la requête et la position courante) à chaque accès. Les URL incluses dans une page sont donc codées de manière à transmettre ces informations. Ce script mérite quelques améliorations, omises pour en faciliter la lecture. Il faudrait effectuer des contrôles et prévoir des situations comme l’absence de résultat pour une requête. Par ailleurs, le choix de réexécuter systématiquement la requête n’est pas toujours le meilleur. Si elle est complexe à évaluer, cela pénalise le client (qui attend) et le serveur (qui travaille). D’autre part, si quelqu’un ajoute ou supprime en parallèle des lignes dans les tables concernées (voire supprime toutes les lignes) l’affichage sera décalé. Si ces problèmes se posent, une autre solution est d’exécuter la requête la première fois, de stocker le résultat dans une table ou un fichier temporaire, et de travailler ensuite sur ce dernier. Ces améliorations sont laissées au lecteur à titre d’exercice. Programmation objet 3 Ce chapitre est entièrement consacré à la programmation objet avec PHP. D’un point de vue technique et conceptuel, son contenu est certainement l’un des plus avancés de ce livre, mais sa lecture n’est pas indispensable à la compréhension des chapitres qui suivent. Il est tout à fait possible de se contenter d’un premier survol consacré à l’utilisation de modules objet prêts à l’emploi, et de poursuivre la lecture avant d’y revenir éventuellement par la suite pour explorer la conception et l’implantation orientée-objet. Comme l’ensemble du livre, ce chapitre est basé sur une approche concrète, avec comme souci constant de présenter les concepts à l’aide d’exemples réalistes et utili- sables en pratique dans de véritables applications. Bien entendu la clarté recherchée impose certaines limitations sur les contrôles ou sur certaines fonctionnalités, mais l’une des caractéristiques de la programmation objet est de permettre des extensions qui ne remettent pas en cause le cœur de l’implantation, fournissant par là-même de bons sujets d’approfondissement. Rappelons que le site associé à ce livre propose un document énumérant des exercices d’application à partir des exemples donnés. Par ailleurs, le chapitre peut se lire selon deux optiques : celle des « utilisateurs » qui exploitent des fonctionnalités orientées-objet, et celle des concepteurs et réali- sateurs. Il semble indispensable de maîtriser la première optique puisque l’on trouve maintenant de très nombreuses fonctionnalités réalisées en suivant une approche orientée-objet, dont l’intégration, qui peut permettre d’économiser beaucoup de temps, suppose une connaissance des principes de base de cette approche. La seconde optique, celle du développeur, demande une conception de la programmation qui constitue un débouché naturel de celle basée sur des fonctions ou des modules, déjà explorée dans les chapitres précédents. On peut tout à fait se passer de la programmation objet pour réaliser une application, mais cette technique apporte inconstestablement un plus en termes de maîtrise de la complexité et de la taille du code, ainsi (mais c’est une question de goût) qu’un certain plaisir intellectuel à 116 Chapitre 3. Programmation objet produire des solutions simples et élégantes à des problèmes qui ne le sont pas toujours. Le contenu de ce chapitre est une tentative de vous convaincre sur ce point. Depuis sa version 5, PHP est devenu un langage orienté-objet tout à fait respec- table, même s’il n’atteint pas encore le niveau de complexité d’une référence comme le C++. La première section de ce chapitre est une présentation générale des concepts de la programmation orientée-objet, tels qu’ils sont proposés par PHP. Cette présen- tation est illustrée par une interface d’accès à un SGBD en général, et à MySQL en particulier. La syntaxe de la partie objet de PHP 5 est présentée successivement par les exemples, mais on peut également la trouver, sous une forme concise et structurée, dans le chapitre récapitulatif sur le langage (page 419). La programmation objet s’appuie sur un ensemble riche et souvent assez abstrait de concepts, ce qui impose probablement aux néophytes plusieurs lectures, en intercalant l’étude des exemples concrets qui suivent, pour bien les assimiler. La suite du chapitre consiste, pour l’essentiel, en plusieurs exemples concrets de programmation objet visant à réaliser les fonctionnalités de base d’une application PHP/MySQL : outre l’accès à la base de données, on trouve donc la mise en forme des données avec des tableaux HTML, la production de formulaires, et enfin un « squelette » d’application, à la fois prêt à l’emploi et reconfigurable, permettant d’effectuer des opérations de mise à jour sur le contenu d’une table MySQL grâce à une interface HTML. Le niveau de difficulté va croissant, le dernier exemple exploitant de manière poussée la capacité de la programmation objet à réaliser des solutions « génériques », le moins dépendantes possibles d’un contexte particulier. À chaque fois, les deux optiques mentionnées précédemment sont successivement présentées : • l’optique utilisateur : comment exploiter et faire appel aux fonctionnalités des objets ; • l’optique développeur : comment elles sont conçues et réalisées. Un des buts de la programmation objet est d’obtenir des modules fonctionnels (des « objets ») de conception et développement parfois très complexes, mais dont l’utilisation peut rester extrêmement simple. Tous les exemples décrits dans ce cha- pitre seront repris pour la réalisation de l’application décrite dans la partie suivante. Il suffira alors de bénéficier de la simplicité d’utilisation, en oubliant la complexité de la réalisation. Vous pourrez appliquer ce principe de réutilisation à vos propres développements, soit en y incluant les fonctionnalités décrites dans ce chapitre (et fournies sur le site), soit en récupérant les innombrables solutions fournies sur les sites de développement PHP (voir notamment le site www.developpez.com). 3.1 TOUR D’HORIZON DE LA PROGRAMMATION OBJET Programmer, c’est spécifier des actions à exécuter au moyen d’un langage qui fournit des outils à la fois pour concevoir et pour décrire ces actions. On distingue classi- quement, parmi ces outils, les structures de données qui permettent de représenter l’information à manipuler, et les algorithmes qui décrivent la séquence d’instructions 3.1 Tour d’horizon de la programmation objet 117 nécessaires pour effectuer l’opération souhaitée. Dans les chapitres précédents, les principales structures manipulées sont les variables et parfois des tableaux, et les algorithmes ont été implantés soit directement dans des scripts, soit sous forme de fonctions. Il y a donc, dans l’approche suivie jusqu’à présent, une séparation nette entre les traitements (les fonctions) et les données (variables, tableaux), considérées comme des informations transitoires échangées entre les fonctions. 3.1.1 Principes de la programmation objet La programmation orientée-objet propose une intégration plus poussée des données et des traitements qui leur sont appliqués. Elle permet de masquer les informations qui ne servent qu’à une partie bien spécifique de l’application (par exemple la gestion des échanges avec la base de données) et de regrouper dans un module cohérent ces informations et les opérations qui portent sur elles. L’ensemble obtenu, données et traitement, constitue un objet, simplement défini comme un sous-système chargé de fournir des services au reste de l’application. Les langages objets fournissent des outils très puissants pour la conception et la description des actions constituant une application. Concevoir une application objet, c’est d’abord imaginer un espace où des objets coopèrent en assumant chacun une tâche spécialisée. Cette approche permet de penser en termes de communica- tions, d’interactions entre sous-systèmes, ce qui est souvent plus naturel que d’utiliser des outils conceptuels plus techniques comme les structures de données ou les fonctions. Dans une perspective classique, non orientée-objet, on considère une application PHP comme un outil généraliste qui doit savoir tout faire, depuis la production de code HTML jusqu’à l’interrogation d’une base de données, en passant par les échanges avec des formulaires, la production de tableaux, etc. Cette approche pré- sente des limites déjà soulignées pour la maîtrise des évolutions et de la maintenance quand le code atteint une certaine taille (quelques milliers de lignes). En introduisant des objets dans l’application, on obtient des « boîtes noires » dont le fonctionnement interne est inconnu du reste de l’application, mais capables de réaliser certaines tâches en fonction de quelques demandes très simples. Prenons un cas concret correspondant aux objets que nous allons développer dans le cadre de ce chapitre. La figure 3.1 montre une application PHP classique (un moteur de recherche par exemple) constituée d’un formulaire pour saisir des critères, d’un accès à une base de données pour rechercher les informations satisfaisant les critères, et enfin d’un tableau pour afficher le résultat. Cette application s’appuie sur trois objets : 1. un objet Formulaire chargé de produire la description HTML du formulaire ; 2. un objet BD qui communique avec la base de données ; 3. un objet Tableau qui effectue la mise en forme du résultat en HTML. Chaque objet est doté d’un état constitué des données – ou propriétés – qui lui sont nécessaires pour l’accomplissement de ses tâches et d’un comportement constitué de . approche orientée-objet, dont l’intégration, qui peut permettre d’économiser beaucoup de temps, suppose une connaissance des principes de base de cette approche. La seconde optique, celle du développeur, demande. des caractéristiques de la programmation objet est de permettre des extensions qui ne remettent pas en cause le cœur de l’implantation, fournissant par là-même de bons sujets d’approfondissement (méthode get) et on la récupère. On peut alors créer une ou deux ancres, selon le cas, pour accéder aux 10 lignes précédentes et/ ou aux 10 lignes suivantes. Bien entendu, cela n’a pas de sens de proposer