Commencer à coder en PHP, épisode 2 : les bases

Faites connaître ce billet :

Après un premier épisode dans lequel je vous expliquais quels sont les outils indispensables pour commencer à coder « sérieusement »… J’évoque dans ce billet les bases du langage de programmation PHP.

J’espère parvenir à vous convaincre que la programmation n’est pas un exercice très compliqué, puisqu’elle est toujours au final l’application d’un principe de base : tout problème compliqué peut se découper en petites opérations très simples qui ne font appel qu’à des commandes « de base ».

Dans la suite de ce billet, le second épisode donc, pour commencer à coder en PHP, vous trouverez l’anatomie minimale d’un script PHP, les commandes les plus élémentaires pour débuter, ainsi que quelques recommandations générales qui pourront vous servir tout au long de vos expérimentations… C’est parti !

Anatomie minimale d’un script PHP

Comme on l’a vu dans le premier épisode, grâce à votre premier « Hello World ! », un script PHP c’est avant tout un simple fichier de texte que l’on dépose sur son serveur web, qui comporte un nom de fichier, une extension en .php, et qui indique à chaque fois que des instructions PHP sont utilisées un début grâce à la balise <?php ou de manière raccourcie (déconseillée) <? et une balise de fin qui est dans l’autre sens avec ?>.

Même si c’est plutôt déconseillé, il faut savoir que les fichiers PHP acceptent autre chose que du PHP dans leur contenu… ce qui explique l’utilisation des balises <?php et ?> pour les passages qui contiennent les instructions PHP. Tout ce qui est en dehors de ces deux balises sera envoyé tel quel au navigateur internet du client, qui se comportera donc comme avec n’importe quel autre contenu. S’il s’agit de HTML, le HTML sera donc interprété et affiché normalement par le navigateur. Pour débuter, il peut être assez pratique de construire des pages en HTML, et d’ajouter ponctuellement, là où on souhaite avoir accès à des fonctionnalités que le HTML ne permet pas, le code PHP qui correspond et qui viendra compléter la page aux bons endroits.

Nous avons également vu qu’un nom spécifique de script existait : index.php, qui aura pour action de charger automatiquement le script si le nom du dossier qui le contient est appelé dans un navigateur internet. On peut d’ores et déjà parier que tout projet PHP comportera donc un index.php qui, en toute logique, sera chargé en premier pour initialiser ce qui doit l’être et donner ensuite accès aux autres parties de l’application web que l’on construit, agissant ainsi comme une sorte de « menu général ».

Dans tous les autres cas, il faudra écrire l’adresse complète dans la barre d’adresse du navigateur : www.mondomaine.fr/projet1/mon-script.php ou bien évidemment proposer un lien HTML qui pointera directement sur l’adresse du script… Lien qui pourrait se trouver dans le fichier index.php.

Une langue : un alphabet et des mots…

Ceci étant précisé, vous savez donc que dans votre dossier projet, vous allez pouvoir créer autant de fichiers PHP que vous le voulez… Encore faut-il savoir quoi mettre à l’intérieur. Cela nécessite donc de faire un tour rapide des principales notions indispensables pour réaliser vos premiers essais.

Le premier point est d’intégrer l’alphabet du langage PHP, avec quelques conventions qu’il faut obligatoirement respecter quel que soit la situation ou ce que l’on essaye de faire.

Ce premier bloc permet d’aborder plusieurs notions fondamentales…

  • Tout bloc d’instructions PHP commence obligatoirement par <?php et se termine par ?>. On peut aussi commencer plus simplement par <? et terminer par ?> mais il ne s’agit pas d’une pratique recommandée ;
  • Toute ligne précédée par // (deux slashes) est neutralisée, elle ne sera pas interprétée par le serveur qui se contentera de les sauter. Il s’agit de commentaires, que l’on peut écrire pour mémoire. Le programme reprend alors dès la ligne suivante. Ils vous seront très utiles pour savoir où vous en êtes quand vous programmez des actions qui s’effectuent en plusieurs étapes… Il est fréquent qu’on oublie « pourquoi on a fait comme ça » quelques semaines plus tard…
  • Tout bloc débutant par /* est considéré comme des commentaires, jusqu’à ce que la balise fermante */ apparaisse. Ne l’oubliez pas… Car en son absence tout ce qui suit est considéré comme du commentaire dont il ne faut pas tenir compte.

Viennent ensuite dans l’exemple de code ci-dessus une succession de définition de variables. La variable est une notion très importante car c’est la « boite » qui permet de stocker quelque chose dans le programme, et qui va ainsi rester en mémoire jusqu’à ce que le programme ait fini de s’exécuter.

  • Définir une variable, c’est à dire ranger quelque chose en mémoire jusqu’à ce que le programme se termine, on utilise le symbole $ (dollar) suivi d’un nom de variable, puis du symbole = (égal) puis de la valeur à stocker.
  • Le nom doit toujours commencer par une lettre, peut comporter des chiffres et des lettres, ainsi que des – (tirets) et des _ (underscores). Il ne faut pas utiliser de caractères spéciaux (accents, symboles…). On évite les majuscules, réservées aux valeurs constantes qui ne changent pas tout au long du programme.
  • Seuls les booléens (une variable qui ne peut être que « vraie » (TRUE) ou « fausse » (FALSE) ainsi que les nombres (entiers ou à virgules) peuvent être écrits directement, sans utiliser de guillemets. Les virgules en PHP sont des . (points) comme par exemple 125.58998
  • Toute autre valeur doit être entourée de  » (guillemets doubles) ou de ‘ (guillemets simples). Les deux fonctionnent indifféremment, l’interprétation des guillemets simples est légèrement plus rapides que les guillemets doubles. Etant donné qu’on utilise beaucoup de guillemets doubles dans le code HTML, une variable qui contiendrait du code HTML aurait tout intérêt à être entourée de ‘ (guillemets simples) ce qui évite d’avoir à « échapper » chaque caractère  » qui serait présent dans le code HTML stocké. Il faut alors prendre garde au texte, dans le code HTML, qui contiendrait des apostrophes :)
  • Si on est obligé d’utiliser un caractère spécifiquement utilisé en PHP, qui conduirait à un problème lors de l’exécution du programme, on doit l’échapper en le faisant précéder d’un \ (antislash) ce qui aura pour effet de l’ignorer. Pour enregistrer dans une variable L’école est finie, je peux ainsi écrire… $variable = « L’école est finie »; mais aussi $variable = ‘L\’école est finie’; ce qui aura le même résultat final. Dans le second cas il faut échapper l’apostrophe.
  • Écrire simplement $variable = ‘L’école est finie’; n’est pas possible car cela va provoquer une erreur. Le programme va penser que $variable = ‘L’ puis va essayer de comprendre l’instruction « école est finie » qui évidemment n’existe pas, et en plus n’a pas été séparée de l’instruction précédente par un ;

Le PHP est un langage de programmation plutôt souple, car on n’est pas obligé d’indiquer au programme quel est le type de la variable que l’on définit au moment où on la définit, alors que certains autres langages l’obligent. PHP va détecter automatiquement le type de la donnée qu’on lui soumet, pour peu qu’on l’y aide. Si l’on écrit un nombre $variable = « 123 »; PHP va considérer qu’il s’agit d’une chaîne de caractères, autrement dit d’une string et non d’un nombre entier, appelé integrer. Cela pourrait poser parfois des difficultés si l’on cherche à faire des calculs avec par la suite…

Notons à ce stade, sans vouloir trop compliquer les choses, qu’il existe tout un ensemble de variables dite « prédéfinies » qui sont accessibles à la demande, il suffit de les « appeler ». On les reconnaît facilement car, par convention, elles commencent par $_ (dollar underscore) et sont écrites en MAJUSCULES. Pour ne donner qu’un exemple, la variable $_SERVER[‘REMOTE_ADDR’] contient l’adresse IP de la personne qui a demandé dans son navigateur l’exécution de votre script PHP. Nous verrons plus tard qu’il en existe de différentes sortes, dont certaines $_GET, $_POST, $_COOKIE sont très utiles pour récupérer des données en provenance de la barre d’adresse du navigateur, d’un formulaire rempli par votre utilisateur ou encore des cookies. Les plus curieux trouveront la liste des variables prédéfinies ici.

Notons également que toutes les variables qui sont définies dans un script PHP ne sont « valables » que pour le script PHP en cours. Une fois le programme arrivé à son terme, les variables seront « perdues », supprimées de la mémoire. Nous verrons plus tard plusieurs techniques qui permettent de les « conserver » ou de les « transférer » d’un script à l’autre. Indiquons enfin une évidence : si vous définissez à nouveau, quelques lignes plus loin, une variable déjà définie… le contenu en sera immédiatement écrasé et remplacé par le nouveau contenu qui sera désormais utilisé jusqu’à ce que le programme croise une nouvelle instruction contraire qui viendrait la modifier.

Dans la suite du code exemple apparaît une suite d’instructions dont on a déjà vu le principe dans le premier épisode, s’appuyant sur la fonction echo. Cela permet d’aborder de nouvelles notions liées aux chaînes de caractères, comme la différence entre l’utilisation des  » (guillemets doubles) et des ‘ (guillemets simples).

  • Dans le premier cas « Bonjour $unmot ! » on a utilisé des guillemets doubles. Cela signifie que si le programme rencontre, à l’intérieur, une variable… Celui-ci va automatiquement remplacer la variable par sa valeur. Concrètement, dans notre exemple, cette ligne va afficher « Bonjour Ouistiti ! » et non « Bonjour $unmot ! ».
  • Tel n’est pas le cas quand on utilise des guillemets simples. En effet, si l’on avait écrit ‘Bonjour $unmot !’ le serveur aurait envoyé au navigateur la phrase ‘Bonjour $unmot !’ sans toucher à la variable mentionnée, qu’il aurait considérée comme du simple texte.
  • La seconde ligne illustre le principe de l’échappement tel que déjà évoqué. En effet, il faut se méfier tout particulièrement des phrases et expressions qui comprennent des apostrophes… qui n’en sont pas vraiment quand on tape sur un clavier traditionnel en dehors d’un logiciel de traitement de texte. En effet, nous utilisons le caractère ‘ qui n’est autre qu’une guillemet simple… ce qui n’est pas sans poser problème quand on se trouve dans une chaîne de caractères délimitée par des ‘ justement. Une seule solution : échapper les ‘ qui ne servent pas de délimitation à l’aide d’un antislash… ce qui donne ‘Le soleil brille aujourd\’hui’
  • La troisième ligne illustre le fait que l’instruction echo peut servir à afficher le contenu d’une variable. Dans ce cas, nul besoin de guillemets, il suffit de mentionner la variable en question.
  • La quatrième ligne enfin illustre une nouvelle possibilité appelée concaténation. Il s’agit simplement de mettre « bout à bout » deux éléments, ici une chaîne de caractères que l’on a indiquée entre guillemets simples, et une variable que l’on a précédemment définie. Pour « coller » les deux morceaux, on utilise le caractère . (point) entre les deux éléments. Cela fonctionne entre une chaîne de caractère et une variable, entre deux variables, entre deux chaînes de caractères…

Enfin, on a utilisé dans la dernière ligne une nouvelle instruction dont on n’avait pas encore parlé, var_dump( $variable ); qui permet non seulement d’afficher le contenu de la variable qu’on donne à la fonction comme paramètre, mais aussi d’afficher des informations sur cette variable, et en particulier son type et sa longueur. C’est évidemment particulièrement utile quand on débute, et qu’on veut « ausculter » une variable que l’on va utiliser (ou que l’on vient de fabriquer) pour être sûr qu’elle correspond bien à ce que l’on souhaite. On verra un peu plus loin que c’est particulièrement utile pour consulter le détail d’une variable un peu spéciale, un array (tableau).

Notons que pour des raisons de lisibilité, il peut être pratique de demander l’affichage d’une balise HTML <pre> avant de lancer cette fonction, et de demander la fermeture de la balise HTML </pre> après avoir lancé cette fonction… afin que le navigateur affiche le résultat de cette commande de manière lisible et claire. C’est ce qui est fait dans l’exemple qui est donné.

On remarque l’intérêt d’utiliser un IDE, un éditeur de code spécialisé dans la programmation quand on débute (et même ensuite…) En effet le code est automatiquement coloré en fonction de ce qui est utilisé, ce qui permet de se repérer facilement et de bien voir que chaque composant de base du langage est colorié différemment. C’est un peu comme si un outil coloriait dans vos phrases tous les sujets, les verbes, les compléments… ce qui aide grandement à la compréhension.

Cela permet également d’alerter automatiquement suite aux erreurs les plus fréquentes que l’on commet, que l’on soit débutant ou confirmé… En effet, on a vite fait d’oublier de fermer une parenthèse ouverte un peu plus tôt, d’oublier un ; en fin d’instruction (cas le plus courant qui provoque pour résultat un écran totalement blanc…) ou encore l’oubli d’un échappement que l’on repère immédiatement en raison d’un défaut dans la couleur…

Un exemple classique… L’oubli d’un échappement qui se voit rapidement grâce aux couleurs

Le plus souvent c’est catastrophique, avec un programme qui s’arrête net à l’endroit où il se trouve, ou dans le pire des cas l’apparition d’une inquiétante erreur 500 « Erreur interne du serveur », mais heureusement après une petite relecture, on trouve assez rapidement la ligne coupable ;)

Notons également que l’IDE aide à taper le code, en prévoyant la fermeture d’un bloc dès qu’on écrit un {, en proposant un ‘ ou un  » dès qu’on en ouvre une, etc. Enfin, notons que des suggestions sont faites à chaque fois que l’on commence à taper le nom d’une fonction, ce qui permet d’éviter les coquilles et de se rappeler comment la fonction se construit grâce à des indications fournies… avec y compris un lien rapide directement sur la bonne page de la documentation PHP pour se rafraîchir la mémoire à l’aide d’exemples.

L’IDE va compléter automatiquement une commande que l’on commence à taper…

Une langue : des phrases…

La programmation devient intéressante à partir du moment où elle ne se contente pas d’enregistrer des données, ou de les afficher… Ce qu’un simple post-it ou une simple ardoise pourrait faire. Tout l’intérêt commence à apparaître quand on peut demander à un programme de se comporter différemment en fonction de paramètres, en répondant à des conditions. Pour poursuivre la métaphore, c’est précisément ce qui permet de passer des mots aux phrases, et même aux paragraphes.

En effet, il va être possible de créer des blocs d’instructions qui vont réagir à une condition. Si la condition est remplie (elle vaudra vrai, soit « TRUE » ou autre chose que « FALSE » ou 0), alors le contenu du bloc va être exécuté. Si la condition n’est pas remplie (elle vaudra faux, soit « FALSE« ), alors le bloc sera tout simplement ignoré et le programme passera donc à la suite.

 

Intérêt de l’indentation (décalage) : on s’y retrouve même avec des conditions emboitées !

L’exemple ci-dessus permet de comprendre comment on écrit une condition. Une condition commence par le mot clé « if » (qui se traduit en français par « si ») immédiatement suivi d’une parenthèse qui va contenir le test logique que le programme va effectuer. Par la suite, un bloc d’instructions (une ou plusieurs) est enfermé entre une { (accolade ouvrante) et une } (accolade fermante). Pour des raisons de lisibilité, je vous recommande d’écrire le { à la ligne, aligné avec le if, puis d’aligner le } avec le premier {. Enfin, je vous recommande de faire un petit décalage à l’intérieur du bloc, qui vous sera normalement proposé automatiquement par l’IDE. Cela peut paraître anecdotique mais cela sera très utile quand nous serons face à des programmes complexes dans lesquels plusieurs conditions sont écrites l’une dans l’autre… D’ailleurs les IDE permettent souvent de « replier » des conditions, c’est à dire de n’afficher que la condition (en « cachant » ce qui est exécuté) ce qui permet de s’y retrouver quand on écrit plusieurs dizaines de lignes par condition et que celles-ci s’enchaînent.

Comme expliqué précédemment, le test logique peut réussir (le résultat à l’intérieur de la parenthèse sera un « TRUE ») ce qui va délencher l’exécution de ce qui se trouve entre { et }… Mais le test logique peut aussi échouer et le bloc { d’instructions } va être tout simplement « sauté » par le programme.

Il est tout à fait possible de prévoir une situation « par défaut » qui sera exécutée par le programme si la condition précédente n’est pas réunie. Le fonctionnement est le même, un { bloc d’instructions } enfermé entre accolade, précédé du mot clé « else » (ce qui se traduit en français par « sinon »).

Pour écrire des conditions, encore faut il savoir ce que l’on peut mettre dans la parenthèse…Voici les exemples les plus fréquents pour commencer :

  • On peut comparer deux variables, ou une variable avec une valeur fournie. Cette comparaison s’effectue à l’aide d’un des 11 opérateurs de comparaison qui sont à votre disposition dans PHP. Les plus fréquents sont == (égal), != (différent), > (terme de gauche plus grand que terme de droite) et < (terme de gauche plus petit que terme de droite).
  • On peut effectuer une opération avec deux variables et comparer le résultat à une référence donnée (c’est ce qui est montré dans le code fourni en exemple). Les opérateurs arithmétiques disponibles dans PHP sont les opérateurs classiques dont les plus courants sont évidemment l’addition +, la soustraction , la multiplication *, la division / et le modulo % qui rappelons le est le reste de la division de $a par $b quand on écrit $a % $b.
  • On peut utiliser une fonction et observer sa réponse. C’est un cas typique lorsqu’on veut contrôler que l’exécution d’une fonction ne s’est pas terminée par une erreur. En effet, la plupart des fonctions PHP sont conçues pour renvoyer le résultat qu’elles sont censées donner lorsqu’elles fonctionnent, et pour renvoyer 0 ou FALSE quand un problème survient. On peut aussi procéder à une comparaison entre le résultat de la fonction et un paramètre fourni dans la condition. Par exemple, on pourrait avoir une condition de la forme if ( strlen($variable) < 10 ) dont la traduction en mots serait : si la longueur de la variable « variable » est strictement inférieure à 10 caractères… (la condition est exécutée).

ATTENTION, il existe un piège classique. Si vous devez faire une opération dont le résultat final peut être 0, cela pourrait causer la non exécution de votre fonction car PHP considère que 0 = FALSE. C’est pourquoi il existe l’opérateur de comparaison === (3 caractères = au lieu de deux) qui non seulement constate une égalité, mais vérifie en plus que le type de la variable est correct. Ainsi, avec une condition qui serait if ( $maviarable === FALSE ), la condition serait exécutée avec $mavariable = FALSE mais ne sera pas exécutée avec $mavariable = 0. On peut également inverser la logique avec l’opérateur !== (au lieu de !=). Dans ce cas la condition sera exécutée dans tous les cas où la variable sera différente de FALSE. Si elle valait 0, la condition serait vraie car 0 n’est pas === à FALSE.

Autre piège classique, écrire un seul = entre deux variables à tester au lieu de deux == En effet, la condition if ( $variable1 = $variable2 ) sera toujours vraie, car il ne s’agit alors pas d’une comparaison mais d’une instruction demandant à ranger dans la $variable1 la valeur de la $variable2. Sauf cas extraordinaire cette instruction réussira toujours et la condition sera donc toujours considérée comme TRUE.

ASTUCE : il existe un « raccourci ». On peut se contenter d’utiliser une condition de la forme if ( $variable ) si on sait que la variable en question est soit 0 / FALSE soit autre chose. C’est une astuce très fréquemment utilisée dans le cadre d’un contrôle d’erreur, ou quand une condition suit la définition d’une variable qui dépend elle-même d’une condition quelques lignes plus tôt.

Il faut faire bien attention aux parenthèses dans les conditions. En effet…

  • PHP exécute les termes présents dans une parenthèse dans l’ordre où il les trouve, sachant qu’on peut en enchaîner plusieurs à l’aide d’opérateurs logiques. La condition globale se comporte alors comme l’ensemble de ses conditions intérieures, en suivant la logique des opérateurs utilisés. Il faut alors faire particulièrement attention aux ouvertures et fermetures de parenthèses.
  • C’est particulièrement vrai pour les conditions de la forme ( ( ( condition1 ) AND (condition2) ) OR ( ( condition3 ) AND ( condition4 ) ) ) qui n’aura par exemple pas du tout le même effet que ( ( condition1 ) AND ( ( condition2 )  OR  ( condition3 ) ) AND ( condition4 ) ). Dans le premier cas il faut que 1 ET 2 soient vraies ou que 3 ET 4 soient vraies pour que la condition soit déclenchée (au moins 2 vrais du même côté), alors que dans le second cas il faut obligatoirement que 1 ET 4 soient vraies, ainsi que 2 OU 3 pour que la condition soit déclenchée (minimum 3 vrais dont obligatoirement 1 et 4 pour que ça fonctionne).
  • Évidemment ces différents exemples peuvent paraître très abstraits pour l’instant mais ils prendront tout leur sens quand vous souhaiterez faire des tests multiples, avant d’autoriser une action spécifique. Pour autoriser la modification du mot de passe d’un utilisateur par exemple, vous pouvez très bien vouloir vérifier que ( ( nom d’utilisateur existe ) ET ( son ancien mot de passe est correct ) ) OU ( ( adresse courriel correcte ) ET ( code à usage unique fourni par courriel suite à un oubli est valide ) ) ).

Enfin pour terminer il faut savoir qu’il existe plusieurs types d’enchaînements de conditions :

  • If ( condition ) seul… le bloc de code ne sera exécutée que si la condition est vraie.
  • Else ( condition ) suivant un If… le bloc de code ne sera exécuté que si la dernière condition If qui précède est fausse.
  • Elseif suivant un If… la condition ne sera testée que si la dernière condition If (ou Elseif) qui précède a échouée.
  • Dans le cas (recommandé) où on souhaite obligatoirement produire un résultat, il est donc nécessaire de faire d’abord un If, puis un Else pour gérer toutes les autres situations. On peut également choisir de faire un ensemble de If, Elseif, Elseif, Elseif (…), Else quand une seule des conditions doit au final être exécutée (la première rencontrée qui sera vraie), tout en gardant la possibilité d’un « cas par défaut » dans le dernier Else.
  • Si l’on doit faire un test avec plusieurs valeurs (ou intervalles) à partir d’un élément unique, on peut opter pour d’autres structures de test comme par exemple le bloc « switch / case / default » dont le détail se trouve ici. C’est particulièrement utile dans les cas où par exemple on lancerait un dé, et on cherche à effectuer des actions différentes selon la valeur obtenue… On évite ainsi d’enchaîner 6 elseif de suite…

Pour être parfaitement complet, il faut également indiquer qu’il existe plusieurs types de boucles qui sont une combinaison entre une condition et une répétition (le bloc d’instructions écrites entre { accolades } sera alors répété autant de fois que nécessaire, tant que la fonction de la condition indiquée sera vraie. C’est l’objet du prochain point, qui mérite des explications complémentaires en raison de l’apparition d’un nouvel « objet » : les tableaux.

Une langue : des paragraphes…

Pour évoquer les boucles, il est nécessaire de parler des « tableaux » (array en langue PHP) car il s’agit de variables spéciales qui sont bien pratiques, on va bientôt voir pourquoi. Les tableaux sont notamment utilisées par une boucle spécifique : foreach (pour chaque…) qui se répétera tant qu’un tableau comportera des éléments disponibles.

Un tableau, vous en avez déjà vu un lorsque je vous ai parlé de la variable globale $_SERVER… en effet cette variable est en fait un tableau qui contient plusieurs lignes, dont celle que je vous ai citée, $_SERVER[‘REMOTE_ADDR’]. Je pense donc que vous avez compris le principe : un tableau s’écrit $tableau et chaque ligne s’écrit $tableau[‘ligne’] sachant que le nom de la ligne répond aux mêmes exigences que les variables, à la différence près qu’il peut s’agir de nombres. Quand on créé un tableau avec la syntaxe $tableau[] = « valeur », PHP sait même créer un numéro automatiquement, en commençant par 0 et en ajoutant 1 à chaque fois qu’une nouvelle ligne $tableau[] = « élément » sera trouvée.

Ce qui rend les tableaux si intéressants, c’est qu’il faut les voir non comme des colonnes Excel (qu’on pourrait traduire par $A[1], $A[2], $A[3], … puis $B[1], $B[2], $B[3], …) mais plutôt comme des arborescences qui peuvent très bien s’enchaîner et être imbriquée. Un tableau peut ainsi très bien contenir un autre tableau, ce qui aboutit à des notations avec plusieurs crochets enchaînés. On pourrait par exemple imaginer…

  • $livres[‘romans’][‘titre’][0] = « Le petit poucet »;
  • $livres[‘romans’][‘auteur’][0] = « Charles Perrault »;
  • $livres[‘romans’][‘titre’][1] = « Croc blanc »;
  • $livres[‘romans’][‘auteur’][1] = « Jack London »;
  • $livres[‘autobiographie’][‘titre’][0] = « Mémoire »;
  • $livres[‘autobiographie’][‘auteur’][0] = « Jacques Chirac »;
  • etc.

On pourrait ainsi ranger toute une collection de livres de manière logique, puis utiliser les fonctions de PHP relatives aux tableaux pour manipuler toute cette collection : effectuer des tris, des recherches, etc. Ce n’est pas forcément ce qu’on fait tous les jours mais il est toujours difficile de trouver un élément concret pour illustrer une possibilité technique abstraite.

Exemple de constitution d’arrays imbriqués ($livres) et var_dump de la variable pour voir ce qu’elle contient

On voit bien avec cet exemple que le navigateur met en évidence une arborescence, ce que montre l’indentation (le décalage de chaque ligne par rapport à la marge de gauche). Il faut noter que ce décalage n’apparaît concrètement que si le var_dump précédemment expliqué est effectué entre deux balises <pre> et </pre>.

Imaginez bien que nombre de fonctions PHP ont pour résultat un tableau, que vous pouvez ensuite « manipuler » avec les fonctions spécifiquement prévues pour gérer les tableaux. Ce sera particulièrement le cas lorsque nous interrogerons une base de données qui renverra plusieurs lignes de résultat, ou lorsque nous réaliseront un import de données (à partir de CSV, de XML ou de toute autre sorte de données organisées).

Mais ne nous écartons pas du sujet initial qui était la panoplie des différentes « boucles » qui existent. Elles sont particulièrement utiles quand vous devez faire plusieurs fois la même chose, quand il est nécessaire de répéter la même chose jusqu’à ce qu’un résultat précis survienne, ou encore quand il faut répéter la même opération sur les différents éléments d’un tableau, un par un. On parle de structures de contrôle, tout comme en sont les conditions simples.

Le premier exemple est une boucle while (tant que…) qui permet de compter de 1 jusqu’à 10. Il s’agit d’une boucle qui sera répétée tant que la condition qu’elle contient est vraie. Dans cet exemple, on décide que $i vaut 1, et on lance une boucle à laquelle on demande d’afficher $i, puis on décide de l’incrémenter (on ajoute 1 à lui-même). On recommence alors l’opération tant que la variable $i reste inférieure ou égale à 10. Une fois que l’on atteint 10, la boucle est exécutée une dernière fois, puis on passe à la suite. On découvre au passage l’incrémentation, $i++ étant une manière plus simple d’écrire $i = $i + 1; Il faut savoir que la commande permettant de retirer 1 existe également, on parle alors de décrémentation, notée $i–;

ATTENTION si vous utilisez un tableau, car il faut vous souvenir que le premier élément est dans $tableau[0] et non pas dans $tableau[1] ! Si vous utilisez $tableau[$i], il faudra donc penser à commencer à $i = 0 et surtout pas à $i = 1 qui vous ferait louper une ligne. De plus, le $i maximum doit correspondre au nombre total de lignes du tableau – 1… justement car la numérotation commence à 0. Un tableau de 10 lignes n’aura PAS de valeur $tableau[10] ! Bien évidemment, nous verrons plus tard que des fonctions existent pour vous indiquer combien de lignes comporte un tableau.

Notons qu’il faut faire attention à une chose avec les boucles… C’est qu’elles ouvrent le risque de se prendre les pieds dans une condition infinie, c’est à dire qui est toujours vraie.

C’est un cas de figure qu’il faut impérativement éviter, car cela signifierait que le programme resterait « coincé » dans la boucle qui ne cesserait donc de s’exécuter qu’une fois une erreur rencontrée (mémoire saturée, durée maximale d’exécution d’un script atteinte, etc). Cela arrive assez vite quand on se trompe de sens pour l’écriture du < ou >, de même qu’on peut se trouver assez vite dans le cas où une boucle n’est jamais exécutée (ou ne l’est qu’une seule fois) quand on enchaîne plusieurs boucles de suite testant la valeur de $i et qu’on « oublie » de remettre $i à sa valeur initiale. En effet une fois la boucle achevée, dans l’exemple montré ci-dessus, $i vaudra 10 et restera à 10 tant qu’on n’aura pas indiqué une nouvelle fois que $i = 1…

Voici un exemple très proche de boucle, do … while (faire… tant que). Le fonctionnement est le même que l’exemple précédent, à une différence près : la condition est testée après la première exécution de la boucle et non avant. Cela veut dire que dans tous les cas cette boucle sera exécutée au moins une fois. Attention à ne pas oublier le ; à la fin de la ligne de condition « while », c’est l’un des rares cas où on doit terminer une ligne de condition d’un ;

Nous arrivons à la boucle la plus utile avec les tableaux… foreach (pour chaque).

Cet exemple de boucle foreach est d’ailleurs l’occasion de vous montrer une nouvelle façon de créer un tableau, grâce à la fonction array à laquelle on donne comme paramètre les différentes valeurs du tableau. Ce qui est important dans cette boucle, c’est bien sûr le mot-clé foreach mais aussi le contenu de la parenthèse qui sera effectué à chaque tour de boucle. On demande que chaque exemplaire de $fruits soit envoyé un par un dans la variable $fruit, que l’on peut alors utiliser à l’intérieur de la boucle.

C’est l’occasion pour moi de vous indiquer qu’il est tout à fait possible de récupérer à la fois la valeur de la ligne du tableau en cours de traitement, mais également son index. L’index est l’étiquette que l’on a utilisée pour ranger l’information à l’intérieur du tableau. $tableau[‘index’] = « valeur ». Ci-dessous un nouvel exemple pour vous permettre de voir la syntaxe à utiliser, mais aussi l’intérêt d’une telle possibilité…

Cet exemple est l’occasion d’indiquer que l’on peut définir les index de tableau directement à l’intérieur de la fonction array, en utilisant =>, ce que l’on va également utiliser à l’intérieur de la parenthèse du foreach. Cela permet de remplir le tableau en une seule ligne, ce qui évite d’avoir à écrire une succession de $nourriture[‘légumes’] = « haricots »; puis $nourriture[‘fromages’] = « boursins »; etc. Mais l’essentiel est, vous l’aurez compris, que la boucle foreach peut à la fois récupérer la valeur de la ligne en cours, et aussi l’index qui n’est pas forcément un numéro… car on peut très bien décider d’un index spécifique.

Notons enfin qu’il est tout à fait possible d’emboiter plusieurs boucles foreach l’une dans l’autre, afin de parcourir chacune des lignes d’un tableau qui serait complexe. En effet, si un index comporte plusieurs lignes, une simple boucle foreach ne permettra pas d’en extraire toutes les lignes. Imaginons dans l’exemple ci-dessus qu’il y ait eu plusieurs légumes… il y aurait alors eu un problème pour pouvoir obtenir le même résultat.

Voilà… avec ces quelques indications, vous êtes en capacité de faire quasiment n’importe quoi en termes de logique et d’enchaînements d’instructions. Bien sûr, vous manquez à ce stade de « fonctions » car créer des variables et les afficher est plutôt limité comme activité, même si vous savez déjà compter, tester, y compris enchaîner des opérations un grand nombre de fois sans effort grâce aux boucles.

Il vous manque encore deux éléments importants avant d’aller plus loin… et vous pourrez partir dans les profondeurs du manuel PHP à la recherche des fonctions les plus intéressantes, même si je vous proposerai évidemment une petite sélection des fonctions les plus utiles.

Fonctions personnalisées et include

Les deux éléments importants qui vous manquent pour pouvoir vraiment avancer sont sans doute les « include » et les fonctions personnalisées. En effet, coder en PHP nécessite fréquemment de répéter plusieurs fois la même opération, mais pas forcément au même moment (donc les boucles ne seront pas adaptées), et pas forcément à partir de la même donnée de départ (donc les conditions ne seront pas suffisantes). En fait, il faut vous dire qu’à chaque fois que vous serez tenté de faire un « copier/coller » dans votre code, il existera une solution alternative qui sera bien plus efficace.

Les include / require

Si vous concevez une jolie page HTML pour afficher le résultat de votre script PHP, vous vous rendrez vite compte que de larges partie de cette page seront communes à toutes vos pages… toute la partie « <head> » du code HTML qui vous permettra notamment de charger le fichier CSS qui vous aide à rendre l’ensemble joli et fonctionnel, ainsi que, pourquoi pas, un menu de navigation en haut de toutes les pages, pourquoi pas un pied de page commun à toutes vos pages… Si vous voulez ajouter un lien dans votre menu, croyez-vous qu’il sera amusant de devoir l’ajouter dans chacune des pages PHP que vous aurez déjà faites ?

Au-delà du HTML, il peut s’agit de fonctions PHP… si l’exécution d’une fonction nécessite de commencer toujours par une étape préalable toujours identique… vous n’allez pas copier/coller toujours les mêmes lignes. Surtout que si vous avez une seule petite chose à changer, vous avez devoir le faire partout ou vous avez fait un copier/coller avec le risque évident d’en oublier au passage. C’est une situation que vous allez rencontrer, par exemple, à chaque fois que vous voudrez écrire dans une base de données… car il vous faudra alors commencer par initialiser une connexion, indiquer un nom d’utilisateur et un mot de passe, etc. Imaginez que vous décidez de changer votre mot de passe… allez-vous devoir l’afficher partout dans votre code et le modifier à chaque fois que vous aurez programmé la consultation de la base ou une écriture ? C’est également quelque chose de fréquent en matière de contrôle d’accès… Le code qui vous permettra de vérifier qu’un utilisateur est bien enregistré, par exemple, avant d’aller plus loin dans l’exécution du reste du code… sera le même pour toutes les pages protégées…

C’est pourquoi la fonction include (et sa cousine require) permet d’intégrer à un fichier PHP un autre fichier PHP déjà existant, à l’endroit où la fonction est appelée. Admettons par exemple que vous travaillez actuellement dans le fichier index.php. Rien ne vous empêche de créer un autre fichier, par exemple securite.php qui n’aura qu’un seul but : vérifier si votre utilisateur est bien connecté, et afficher l’erreur « Vous devez être connecté-e pour continuer » si tel n’est pas le cas avant de bloquer l’exécution du programme grâce à la fonction exit qui arrête tout et empêche d’aller plus loin. A chaque fois que vous aurez besoin de protéger l’accès à une page spécifique, vous pourrez au début demander include ( « securite.php » ); ce qui aura pour effet d’ajouter tout le code contenu dans le fichier securite.php à l’endroit même où cette include est appelée. Il s’agit vraiment d’une récupération dans le script qui est en cours. Si vous avez suivi ce qui concerne les variables, cela veut dire que toute variable qui a été définie avant d’appeler include seront disponibles à l’intérieur du script qui est ainsi intégré au code. De même, toute variable qui sera créée à l’intérieur du fichier PHP ainsi intégré sera disponible dans la suite du code « principal » dans lequel on a réalisé l’include.

Différence avec require ? L’effet est le même avec une grosse différence. Si include ne trouve pas le fichier PHP indiqué, elle l’ignore tout simplement et continue la suite du code. Require quant à elle génère une erreur si elle ne trouve pas le fichier PHP demandé, et le programme s’arrête net sans aller plus loin.

Le fichier PHP appelé peut contenir autre chose que du PHP, par exemple du HTML uniquement, ou du HTML et du PHP mélangés (à condition de bien utiliser les balises <? et ?> évidemment. Si vous écrivez uniquement du HTML dans un fichier PHP destiné à être « intégré », n’oubliez pas de commencer par ?> car le contenu va être « injecté » au milieu d’un code PHP en cours d’utilisation… et de terminer par <? pour que la suite du script puisse continuer en mode PHP. En effet, gardez en tête que tout le contenu de ce que vous allez appeler avec include ou require va être injecté tel quel à l’endroit où vous avez mis la fonction, comme si vous faisiez un copier/coller. Mélanger du PHP et du HTML sans prendre garde aux balises PHP aurait donc un effet catastrophique…

Voici une illustration… Imaginons qu’au beau milieu de mon script index.php je décide de commencer à envoyer au navigateur un entête HTML classique pour pouvoir ensuite envoyer du contenu à afficher.

Comme supposé, mon fichier header.php sera du code HTML, il contiendra donc ceci…

Vous l’aurez compris, cela va poser un énorme problème… Car du code HTML va se retrouver directement au milieu du code PHP ! Voici ce que le serveur va « obtenir » une fois le contenu de header.php « importé » dans le code…

C’est pourquoi à l’intérieur du fichier header.php il ne faudra pas oublier de commencer par interrompre le PHP, puis à la reprendre en fin de fichier pour lui permettre de continuer dans le « script principal ».

En procédant ainsi, le résultat final ne posera aucune difficulté…

De même, quand vous préparez un fichier qui sera utilisé ensuite pour un include ou un require… il est recommandé de toujours commencer par une balise ouvrante <? (ce qui ne posera aucun problème si cette balise est utilisée alors qu’on se trouve déjà dans du code PHP), et de ne jamais mettre de balise fermante en fin de fichier (ce qui risque d’interrompre brusquement l’interprétation des commandes PHP juste après l’include).

Les fonctions personnalisées

Avec les fonctions personnalisées, on est dans une démarche très proche. Ces fonctions sont en fait une sorte de raccourci qui vous permet d’appeler un bloc de code que vous avez précédemment défini grâce à un nom personnalisé que vous avez choisi. Intérêt majeur : vous pouvez indiquer des paramètres lorsque vous appelez la fonction, ce qui vous permet d’obtenir des résultats différents sans avoir à changer une seule ligne de code. C’est une sorte de mini-script intégré à votre script.

Dans cet exemple, on créé la fonction suisjepair() qui fonctionne avec un paramètre appelé ici $nombre. On écrit donc suisjepair($nombre). Le but de la fonction est de nous dire si le nombre qu’on lui donne est pair ou impair. Évidemment, on prendra soin de ne pas donner à la fonction le nom d’une fonction qui existe déjà dans PHP…

La fonction prend la valeur que l’on indique avec le mot « return« . Si on souhaite que la fonction fasse directement quelque chose, il suffit de lui demander et de ne pas utiliser le mot return. Il aurait été ainsi tout à fait possible d’écrire…

Il est toutefois préférable de procéder par étape pour des raisons de clarté du code, car les fonctions ont généralement pour but d’effectuer un « traitement » sur un ou des paramètres qu’on leur indique en entrée. Si on voit dans le code unefonctionpersonnalisee(); on ne sait pas trop ce qu’il va se passer (à moins d’aller voir dans la fonction ce qu’elle contient). Si on voit echo unefonctionpersonnalisee(); on se doute qu’il va s’agir d’afficher un résultat.

Une fois créée, la fonction peut être utilisée en l’appelant simplement par son nom, suivie du paramètre soit sous la forme d’une variable, soit directement. Il n’est pas obligatoire d’avoir un paramètre, dans ce cas on laisse () vide. Il est également possible d’avoir plusieurs paramètres, qui sont alors pris dans l’ordre.

Dans l’exemple ci-dessus, on voit que mabellefonction() peut prendre en compte 3 paramètres. Seul le premier est obligatoire (son absence provoquera une erreur et l’arrêt du code) car on n’a pas indiqué de valeur par défaut qui pourrait être utilisée par la fonction en cas d’absence. Les paramètres 2 et 3 sont eux facultatifs, car en leur absence dans l’appel de la fonction, les valeurs par défaut 0 et « Toto » sera utilisée.

Il n’est pas nécessaire que le nom des variables corresponde quand on appelle une fonction. Seul l’ordre est important. Ainsi, si je définis $i = 12 puis que j’appelle mabellefonction(« Coucou », $i); la fonction va être exécutée avec $param1 = « Coucou », $param2 = 12 et $param3 = « Toto ». C’est pourquoi il est évident que l’on commence toujours par les paramètres obligatoires, puis seulement viennent les paramètres optionnels. Attention, on ne peut pas sauter de paramètre optionnel. On ne pourra pas changer le 3e paramètre sans indiquer de 2e paramètre, en laissant un « trou ». mabellefonction(« Coucou », , »Robert »); C’est une situation impossible qu’on essaye d’éviter en mettant les paramètres optionnels dans l’ordre de leur « utilité », les plus sollicités en premier, les plus occasionnels en dernier.

Comme dans plusieurs cas, vous trouvez sans doute cela très abstrait, mais vous comprendrez vite l’utilité des fonctions quand vous essayerez de vous fabriquer des petits « utilitaires » qui viendront simplifier votre code quand vous en éprouverez le besoin. Je vous mets un exemple de fonction personnalisée ci-dessous, issue d’un des programmes que j’ai déjà fait…

Cet exemple est l’occasion de vous inviter à être particulièrement bavard dans vos commentaires… car non seulement on peut avoir du mal à se souvenir de ce à quoi les données fournies en paramètre doivent ressembler une fois qu’on a fabriqué des dizaines de fonctions, mais en plus il peut être pratique de retrouver les différentes étapes suivies quand celles-ci sont complexes. Dites-vous que vous reviendrez peut-être sur des morceaux de code plusieurs semaines ou mois plus tard…

Quelques explications sur cette fonction… Il s’agit d’un petit outil que j’utilise en lien avec une base de données dans laquelle je stocke une liste d’utilisateurs. Chaque utilisateur est référencé par un numéro unique, un ID, qui a été décidé au moment de son inscription. A chaque fois que mon programme réalise quelque chose qui est reliée à un utilisateur, son seul ID est stocké. Quand j’ai besoin de récupérer une information liée à cet ID, j’ai simplement à la demander grâce à la fonction ci-dessus.

Si je veux le nom de l’utilisateur ayant l’ID n°3, j’ai simplement à écrire infoutilisateur( 3 , « nom » ); et c’est chose faite. Cela remplace en une seule ligne minimaliste la nécessité de faire…

Au passage, notez l’utilisation d’un include (qui fonctionne aussi à l’intérieur d’une fonction). En l’occurrence cet include m’évite d’avoir à répéter toujours les quelques lignes nécessaires à la connexion à la base de données, et me permet d’éventuellement changer nom d’utilisateur et mot de passe à un seul endroit si c’était nécessaire.

En voici ci-dessous pour information le contenu… C’est également l’occasion de vous montrer qu’on peut prévoir plusieurs versions d’un même include, adaptée aux besoins. Je peux ainsi me connecter à la base de données en mode lecture uniquement, ou en mode lecture/écriture en fonction des besoins. Une solution plus élégante aurait pu être de concevoir une fonction personnalisée avec un paramètre qui aurait correspondu au mode de connexion souhaitée. Notez également que ce petit morceau de code est écrit en « orienté objet » (ce que l’on reconnaît par le mot clé new, et par l’usage de ->) mais nous en reparlerons plus tard, c’est ici juste une illustration.

Argument supplémentaire : imaginons qu’un jour je décide de changer le nom de la table qui contient les utilisateurs… il faudrait que je la change partout dans mon code, dans tous les scripts où j’aurais demandé des informations avec ces quelques lignes. Alors qu’en utilisant une fonction, j’aurais simplement à mettre à jour la fonction, une seule fois. Elle serait ainsi mise à jour partout où elle est utilisée !

Il faut noter que des fonctions très spéciales existent : les classes, les méthodes… Elles permettent avec un niveau beaucoup plus avancé de créer des objets ayant certaines caractéristiques, puis d’appeler des fonctions qui vont interagir avec cet objet jusqu’à aboutir à un résultat final. On parle de programmation orientée objet, mais là n’est pas le sujet de ce billet introductif pour ceux qui démarrent tout juste. Il s’agit d’une méthode très intéressante de programmation qui nécessite beaucoup plus de travail au niveau de la conception, mais qui ensuite se montre redoutablement efficace puisque deux ou trois lignes peuvent remplacer par la suite plusieurs centaines ou milliers de lignes de code ! Pour l’instant, nous restons en mode « procédural », ce qui est la base pour apprendre.

Conclusion

Je pense que ce billet est encore un peu frustrant, car s’il vous donne beaucoup d’informations, il me semble clair qu’il ne permet pas encore de « faire grand chose ». C’est un peu comme apprendre le code de la route avec la forme des panneaux et leur couleur, mais sans savoir encore quels symboles peuvent apparaître à l’intérieur.

Ne vous inquiétez pas, dans le prochain épisode nous passons au concret avec de nombreux exemples de type « comment faire pour… » :) Vous apprendrez ainsi comment récupérer des données de l’utilisateur, comment les manipuler, et comment réaliser la plupart des opérations les plus courantes. Ce sera l’occasion pour moi de vous montrer un grand nombre de fonctions PHP très utiles, parmi les plus fréquemment utilisées dans les différents programmes que j’ai pu concevoir jusque là.

J’espère que toutes les informations de ce billet vous ont été utiles… A bientôt pour le prochain épisode !

One thought on “Commencer à coder en PHP, épisode 2 : les bases”

Laisser un commentaire