Dans cette partie, nous allons étudier comment créer un Serveur Web Dynamique en utilisant le langage PHP.
PHP est un langage de scripts généraliste qui, lorsqu'il est intégré à un serveur Web (comme Apache),
permet de générer dynamiquement des pages web (contenant potentiellement du HTML, CSS et Javascript).
NB: PHP peut aussi être utilisé pour créer une API REST qui génère du JSON.
Environnement de Travail
Pour créer notre serveur web en php, il nous faut un serveur web capable d'exécuter les scripts
PHP...
De plus, un serveur PHP est généralement couplé à un serveur de base de données comme MySQL.
Pour toutes ces raisons, nous allons utiliser une solution "classique" qui fournit à la fois un serveur
Apache, un serveur MysSQL, et divers outils d'administration tels que phpMyAdmin :
XAMPP.
Votre premier travail consiste donc à télécharger et installer la (dernière) version de
XAMPP qui correspond à votre
système d'exploitation.
Pour vérifier que tout est ok, utilisez l'interface de XAMPP pour démarrer les serveurs Apache et MySQL
(si ce n'est pas déjà fait). Dans le menu d'administration (Dashboard) vous pouvez cliquer sur le
lien PHPInfo (en haut à droite de la page web) et admirer les informations de configuration du
serveur Apache, ainsi que sur phpMyAdmin pour accéder au contenu du serveur MySQL.
NB: sous Windows, il faut lancer le programme en tant qu'Administrateur.
Premier Script PHP
Les serveurs Apache vont chercher les fichiers demandés par l'utilisateur dans un dossier qu'on appelle
DocumentRoot.
Vous pouvez voir la valeur de DocumentRoot en cliquant PHPInfo dans le DashBoard.
Trouvez le dossier correspondant à DocumentRoot (a priori C:/xampp/htdocs/ sous Windows),
et créez un sous dossier nommé web3.
Dans web3 utilisez un éditeur de code (par exemple
Atom)
et créez le fichier index.php, avec pour contenu :
NB: lorsque seul le nom du dossier est indiqué (ex. http://localhost/web3/), le serveur web
renverra automatiquement le fichier nommé index.html, et s'il ne le trouve pas,
il cherchera index.php
C'est ce que nous faisons ici : demander http://localhost/web3/ revient en réalité à
obtenir la page http://localhost/web3/index.php .
Vous devriez obtenir le résultat suivant :
Résultat
PHP dit Hello World
NB: Si cela ne fonctionne pas, il est possible que votre serveur ait été démarré sur un port non standard.
Pour le vérifier, regardez l'adresse à laquelle vous aviez ouvert le DashBoard. Si l'adresse contient
un chiffre comme dans http://localhost:8080/dashboard, cela signifie que votre serveur sert les pages web
sur le port 8080. Vous devez alors aussi indiquer ce port particulier pour consulter vos propres
pages (ex. http://localhost:8080/web3/)
Affichage des erreurs
Lorsque vous développez en PHP, il est possible que le serveur Web qui exécute vos pages
n'indique pas les erreurs d'exécutions. Dans ce cas, si une erreur survient, le script
s'arrête (plante), mais vous n'avez aucune information vous permettant de savoir ce qui
s'est passé.
Ce fonctionnement est tout à fait logique lorsque votre site Web est en production :
il serait malvenu qu'un site Web affiche des messages d'erreurs incompréhensibles
(ou contenant des données sensibles) aux utilisateurs.
Par contre, pendant le développement, avoir le détail de ce qui a mal fonctionné peut
largement vous aider dans le but de corriger le problème.
D'une manière générale :
En développmement : on laisse PHP afficher les erreurs dans la page.
En production : on empêche PHP d'envoyer ses messages d'erreur à l'utilisateur.
Dans ce cours nous serons en mode développement : si le PHP de votre serveur Web n'affiche
pas les erreurs d'un de vos scripts, vous pouvez ajouter ces quelques lignes
au tout début :
NB : au lieux d'ajouter ces lignes au début de chaque script qu'on veut tester, il est possible de
demander au serveur Web d'afficher/cacher les erreurs en modifiant ses fichiers de configuration
(ex. php.ini).
PHP + HTML/CSS/Javascript
Dans l'exemple précédent, vous pouvez constater que le résultat obtenu correspond (uniquement) au contenu
de la chaine passée en paramètre de la fonction php echo.
Si vous demandez au navigateur d'afficher le code source de la page, vous pourrez remarquer que le code
php a totalement disparu : il ne reste plus que le code html généré par l'appel à echo.
Lorsqu'on demande une page .php à un serveur web, le serveur envoie le fichier à
l'interpréteur PHP (ou préprocesseur) et tout le code php qui se trouve entre
les balises <?php et ?>est exécuté et remplacé dans la page web
par son résultat.
L'interpréteur PHP ne comprend que le code php :
tout code qui n'est pas du code php (ex. HTML, CSS, Javascript) est recopié à l'identique.
C'est le résultat de ce processus (le code interprété, résultat du pré-processing) qui est envoyé par le serveur
en réponse au client (le navigateur).
On peut donc avoir des fichiers .php tels que :
http://localhost/web3/01_balises.php
<html><head><title>Exemple <?phpecho" de pré-processing PHP"?></title><style>.bleu{color:<?phpecho"blue"?>;}</style></head><body><h2class="bleu">
Voici un exemple de <spanstyle="color:red"><?phpecho"code généré par PHP"?></span></h2></body></html>
Résultat : le code dans les 3 balises <?php ... ?> a été interprété/remplacé.
Exemple de pré-processing PHP
Voici un exemple de code généré par PHP
Il est très important de bien comprendre que, comme dans cet exemple, le code php peut
générer du HTML, du CSS et/ou du Javascript, mais
il ne peut pas interagir avec ces langages : en effet,
les scripts PHP sont traités exclusivement sur le serveur,
alors que les autre langages s'exécutent sur le client, c.a.d. dans le navigateur.
Ils ne partagent donc aucunement le même contexte d'exécution (variables, etc.).
Les Bases du Langage
Code PHP
Le code php doit être écrit entre les balises
<?php et ?>.
Chaque instruction doit se terminer par un ; .
Comme nous venons de le voir, tout ce qui est en dehors de ces balises est ignoré par PHP
(ou plutôt, laissé tel quel).
La balise fermante ?> ne signifie pas la fin
d'un script : l'interpréteur continuera son exécution avec le même contexte (variables, fonctions, etc.)
dès qu'il rencontrera une nouvelle balise <?php.
Le code est donc exécuté séquentiellement de balise en balise en partageant (faisant évoluer)
le même contexte d'exécution.
C'est ce que nous allons voir ci-après, en particulier avec l'utilisation de variables.
Sorties en PHP : echo
C'est l'instruction echo qui sert principalement à faire des sorties dans une page :
<?phpecho"<p>Voici une sortie en PHP</p>";?>
Résultat
Voici une sortie en PHP
Notez que <?= est une variante courte de <?php echo :
<?="<p>Voici une autre sortie en PHP</p>"?>
Résultat
Voici une autre sortie en PHP
Les Variables
Les variables php doivent être déclarées avec le pattern $nom_variable.
Leur portée est limitée au bloc dans lequel elles sont déclarées.
Le typage est dynamique. Il n'est pas obligatoire d'initialiser la valeur d'une variable, mais c'est
fortement conseillé.
http://localhost/web3/02_variable.php
<?php$ma_variable=5;// déclaration|affectation de variable?><p>
Voici la valeur de ma variable : <?=$ma_variable?></p><?php$ma_variable*=2?><p>
Et la voici après avoir été modifiée : <?=$ma_variable?></p>
Résultat
Voici la valeur de ma variable : 5
Et la voici après avoir été modifiée : 10
NB: Vous pouvez constater que le contexte d'exécution est bien partagé par les balises.
Informations sur une variable : var_dump(...)
Quand on développe un site web en php, il est parfois utile de pouvoir afficher simplement
(par ex. pour débugger) les informations concernant une variable.
La fonction var_dump(data) affiche les informations
concernant une data.
<?php$ok=false;?><p>Voici les informations sur $ok : <b><?phpvar_dump($ok)?></b></p>
Résultat
Voici les informations sur $ok : bool(false)
Existence d'une variable : isset / unset
Cela peut sembler bizarre a priori (développer en PHP ne rend pas amnésique),
mais nous verrons qu'en PHP, il est souvent pratique de pouvoir vérifier si une variable existe.
(Ce sera en particulier le cas lorsque nous aurons à traiter des variables
correspondant à des champs de formulaires remplis, ou pas...).
La fonction isset(variable) renvoie true
si variable existe et est différente de null, false sinon.
La fonction unset(variable) permet de "détruire" une
variable.
<p>La variable existe ? <?phpvar_dump(isset($prenom))?></p><?php$prenom="Greg"?><p>La variable existe ? <?phpvar_dump(isset($prenom))?> : <?=$prenom?></p><?phpunset($prenom)?><p>La variable existe ? <?phpvar_dump(isset($prenom))?></p>
Résultat
La variable existe ? bool(false)
La variable existe ? bool(true)
: Greg
La variable existe ? bool(false)
Les Chaînes de Caractères : string
Les chaînes de caractères de PHP sont similaires à celles des autres langages.
On pourra cependant noter que l'opérateur de concaténation est ici le . .
<?php$greeting="bonjour";$fname="greg";$message=$greeting." ".$fname." !";?><p>Le message : <b><?phpecho$message?></b></p><?php// PHP offre de nombreuse fonctions pour manipuler les string$formatted=ucfirst($greeting)." ".strtoupper($fname)." !!!";?><p>
Le message formaté : <b><?phpecho$formatted?></b><br>
Longueur : <?phpechostrlen($formatted)?> caractère(s)
</p>
<?php$tab=['a','b','c','d'];?><p>Voici un tableau de taille <?phpechocount($tab)?> :</p><divstyle="font-family: Monaco ;font-size: 0.8em"><divstyle="white-space: pre ;"><?phpvar_dump($tab)?></div></div><br><p><?php$case=2;// on peut utiliser les variables dans un echo :echo"Le contenu de la case $case est $tab[$case].";?></p>
Vous aurez remarqué que les tableaux de PHP sont associatifs (paires clé=>valeur).
Dans l'exemple précédent, les clés ne sont pas précisées : elles sont attribuées automatiquement
(avec des nombres de 0 à count($tab)-1).
On peut donc aussi créer des tableaux en spécifiant les paires voulues :
<?php$phonetic_alphabet=array("Alpha"=>"A","Bravo"=>"B","Charlie"=>"C","Delta"=>"D");?><p><?php$code="Charlie";?>
Dans l'alphabet phonétique de l'OTAN,
le code "<?phpecho$code?>" signifie '<?phpecho$phonetic_alphabet[$code]?>'.
</p>
Résultat
Dans l'alphabet phonétique de l'OTAN,
le code "Charlie" signifie 'C'.
Fonctions de recherche dans un tableau
PHP offre plusieurs fonctions permettant d'effectuer des recherches dans un tableau :
in_array(valeur, tableau) :
renvoie true si valeur est dans tableau,
false sinon.
array_key_exists(clé, tableau) :
renvoie true si clé existe dans tableau,
false sinon.
array_search(valeur, tableau) :
renvoie la clé correspondante à valeur si valeur
est dans tableau, false sinon.
<?php$week=['lundi','mardi','mercredi','jeudi','vendredi','samedi','dimanche'];$day='vendredi';$idx=array_search($day,$week);// NB: il faudrait vérifier que la réponse n'est pas false...echo"$day est le jour n° ".($idx+1)." dans la semaine";?>
Résultat
vendredi est le jour n° 5 dans la semaine
Les Structures de Contrôle
Conditionnelle : if
La structure du if en PHP est classique. Les blocs sont délimités par des accolades.
Plusieurs formes sont disponibles selon les besoins :
<?php$a_le_permis=true;$est_sobre=false;$a_un_chauffeur=true;$msg="Rentre";if(($a_le_permisand$est_sobre)or$a_un_chauffeur){$msg.=' en voiture';}else{$msg.=' à pieds';}echo$msg;?>
Résultat
Rentre en voiture
Affectation ternaire
Il est aussi possible d'utiliser des opérateurs ternaires :
<?php$notes=[18,15,6,20,12];$acc=0;$i=0;while($i<count($notes)){$acc+=$notes[$i];$i++;}$moyenne=$acc/count($notes);?>
La moyenne est : <?phpecho$moyenne?>
Résultat
La moyenne est : 14.2
Pour : for
<?php$notes=[18,15,6,20,12];$acc=0;for($i=0;$i<count($notes);$i++){$acc+=$notes[$i];}$moyenne=$acc/count($notes);?>
La moyenne est : <?phpecho$moyenne?>
Résultat
La moyenne est : 14.2
foreach
Pour parcourir les tableaux, il peut être plus intéressant d'utiliser un foreach.
foreach(iretable as $value){ ... }
<?php$notes=[18,15,6,20,12];$acc=0;foreach($notesas$n){$acc+=$n;}$moyenne=$acc/count($notes);?>
La moyenne est : <?phpecho$moyenne?>
Résultat
La moyenne est : 14.2
foreach(iretable as $key => $value){ ... }
<p>
Alphabet phonétique de l'OTAN :
</p><ulstyle="list-style-type: square"><?php$phonetic_alphabet=array("Alpha"=>"A","Bravo"=>"B","Charlie"=>"C","Delta"=>"D");foreach($phonetic_alphabetas$code=>$char){echo"<li>\"$code\" : '$char'</li>";}?></ul>
Résultat
Alphabet phonétique de l'OTAN :
"Alpha" : 'A'
"Bravo" : 'B'
"Charlie" : 'C'
"Delta" : 'D'
Les blocs php + HTML/CSS/Javascript
Le code HTML/CSS/Javascript qui est placé dans un bloc php
(dans un { ... } ) est "recopié" par l'interpréteur seulement si ce bloc est exécuté.
Ce mécanisme peut être mis à profit lorsque l'on crée un script php qui intercale plusieurs "morceaux" de
code php dans du HTML.
NB: cela peut aussi rendre le code difficile à lire...
Pour plus de lisibilité, on peut utiliser la
syntaxe alternative
dans laquelle les accolades sont remplacées par des : et la fermeture de bloc est assurée
par (selon le cas) : endif, endwhile, endfor, endforeach,
ou endswitch.
Exemple avec un bloc if : ... else : ... endif ; :
Tu vas rentrer
<?php$a_le_permis=false;?><?phpif($a_le_permis):?><!-- apparait seulement si la condition est true --><spanstyle="color: blue">en voiture :) </span><?phpelse:?><!-- apparait seulement si la condition est false --><spanstyle="color: red">à pieds :(</span><?phpendif?>
Résultat
Tu vas rentrer
à pieds :(
Un autre exemple avec un bloc foreach : ... endforeach ; :
<?php$phonetic_alphabet=array("Alpha"=>"A","Bravo"=>"B","Charlie"=>"C","Delta"=>"D");?><style>.cell{width: 50%;border: 1px solid black ;padding: 3px;}</style><table><tr><thcolspan="2">Alphabet phonétique de l'OTAN</th></tr><?phpforeach($phonetic_alphabetas$code=>$char):?><!-- ce code HTML est intégré à la boucle --><tr><tdclass="cell"><?phpecho$code?></td><tdclass="cell"style="text-align: center"><?phpecho$char?></td></tr><?phpendforeach?></table>
Résultat
Alphabet phonétique de l'OTAN
Alpha
A
Bravo
B
Charlie
C
Delta
D
Les Fonctions
Les fonctions php ont une syntaxe proche de celle qu'on peut trouver dans la plupart des langages.
Comme pour les variables, le type des paramètres ne doit pas être indiqué.
Fonction sans paramètre
<?php// déclaration de la fonctionfunctiondisBonjour(){$msg="Hello World";echo"<p>$msg</p>";}// appel de la fonctiondisBonjour();disBonjour();?>
Résultat
Hello World
Hello World
Fonction avec paramètre(s)
<?php// déclaration de la fonctionfunctiondisBonjourA($nom,$ponctuation='!'){echo"<p>Hello $nom$ponctuation</p>";}// appel de la fonctiondisBonjourA('Greg');disBonjourA('Greg',':)');?>
Résultat
Hello Greg !
Hello Greg :)
Fonction avec valeur de retour (return)
<?php// déclaration d'une fonction qui retourne une chainefunctiongetGreetingMessage($nom,$ponctuation='!'){$msg="Hello $nom$ponctuation";return$msg;// <- l'exécution s'arrête ici ! }?><h2><?phpechogetGreetingMessage('Greg')?></h2>
Résultat
Hello Greg !
Inclusion de Fichiers
De manière à apporter plus de modularité et de ré-utilisabilité, PHP offre plusieurs fonctions qui
permettent d'inclure/importer des fichiers externes dans un résultat.
L'inclusion d'un fichier signifie littéralement insérer la totalité de son code
à l'endroit où est appelée l'inclusion.
L'exécution du script est alors réalisée comme si le code inclus y était collé.
Ce mécanisme permet de réutiliser non seulement des suites d'instructions php, des variables php,
des fonctions php... MAIS AUSSI du code HTML/CSS/Javascript !
Cela s'avère très pratique par exemple lorsque l'on a besoin d'intégrer un header, un
footer, une navbar, ... qui sont typiquement des instructions
HTML/CSS/Javascript qui doivent se répéter à l'identique dans plusieurs pages d'un même site.
Il existe 4 instructions permettant d'inclure le code d'un fichier dans un script :
include(fichier) :
inclut les instructions du fichier à l'endroit où
include est appelé. Ne fait rien si le fichier n'est pas trouvé.
include_once(fichier) :
comme include, mais ne fait rien si fichier a déjà été inclus
(précédemment) dans le script. (Cela permet par exemple d'éviter des re-déclarations, une connexion
à un serveur externe alors qu'elle a déjà été faite, etc.).
Ne fait rien si le fichier n'est pas trouvé.
require(fichier) :
a le même fonctionnement que include, mais déclenche une erreur d'exécution du script php
si fichier n'est pas trouvé.
require_once(fichier) :
a le même fonctionnement que include_once, mais déclenche une erreur d'exécution
du script php si fichier n'est pas trouvé.
Un Exemple
On définit d'abord plusieurs fichiers destinés à être inclus.
Dans cet exemple ce seront les fichiers :
header.html : du code HTML pour le header du site.
footer.php : du code HTML + PHP pour le footer du site.
helpers.php : du code HTML + PHP (ici, l'ajout d'une balise link
pour un fichier .css, et la déclaration d'une fonction PHP nommée generateTitle.
hepers.css : des déclarations CSS utilisées dans helpers.php.
Remarques:
Les fichiers .html (avec du HTML "pur") peuvent aussi être nommés .php
(ex. header.php).
Les fichiers contenant du code PHP (+ HTML) doivent être nommés .php
(ex. footer.php).
Voici le contenu de ces fichiers :
header.html
<h1>Cours de PHP</h1><hr>
footer.php
<divstyle="width: 100% ;padding: 5px ;background: black ;color: white">
Ceci est une démo d'inclusions en PHP <?phpechophpversion()?></div>
helpers.php
<linkrel="stylesheet"href="helpers.css"><?php/**
* Génère une balise h1 avec un titre formaté
* @param $title
*/functiongenerateTitle($title){// formatage du titre$title=ucwords($title);// génération du code HTMLecho"<h2 class='custom'>$title</h2>";}
Il ne reste plus qu'à inclure ces fichiers aux endroits voulus : ici dans index.php.
(NB: dès que helpers.php a été inclus, la fonction generateTitle est disponible.)
index.php
<?phprequire_once"helpers.php"?><!doctypehtml><head><metacharset="UTF-8"><title>Test Inclusion</title></head><body><?phpinclude"header.html"?><?phpgenerateTitle("introduction")?><p>
bla bla blaaa
</p><?phpgenerateTitle("serveurs web dynamiques")?><p>
bla bla blaaa
</p><?phpgenerateTitle("conclusion")?><p>
bla bla blaaa
</p><?phpinclude"footer.php";?></body></html>
Résultat
Test Inclusion
Cours de PHP
Introduction
bla bla blaaa
Serveurs Web Dynamiques
bla bla blaaa
Conclusion
bla bla blaaa
Ceci est une démo d'inclusions en PHP 7.4.33
Les Objets en PHP
PHP fournit un modèle objet avec des mécanismes proches de ceux de Java.
Un bonne nouvelle puisque vous avez tout compris au
cours de LOO ;).
Les classes
Comme en Java, les objets sont instances de classes dont les définitions contiennent des membres
(attrituts/propriétés et méthodes/fonctions).
A partir de PHP 7.4, il est possible (et conseillé) de typer les attributs, paramètres, retours de
méthodes/fonctions. ATTENTION : avec les plus anciennes versions, il ne faut pas mettre les types.
Les constructeurs sont nommés __construct.
L'instanciation est faite par new.
L'objet peut se référencer lui-même grâce à $this.
L'accès aux membres d'instance est faite par ->.
La visibilité est gérée par private,
protected et public.
Dans ce cours, j'utiliserai les déclarations avec types. Si votre version de PHP est antérieure à 7.4, ne mettez/recopiez pas les types !
Exemple de classe
Définition d'un classe People dans un fichoer People.php :
People.php
<?phpclassPeople{privatestring$name;// "string" seulement pour PHP >= 7.4/**
* People constructor.
* @param $name
*/publicfunction__construct($name){$this->name=$name;}/**
* @return string
*/publicfunctiongetName():string{return$this->name;}/**
* @return string
*/publicfunction__toString():string{returnucwords($this->getName());}}
Utilisation de la classe :
ex_01_class.php
<?phpinclude"People.php";$greg=newPeople("grégory bourguin");?><p>
Le contenu de l'attribut : <b><?phpecho$greg->getName()?></b></p><p>
Utilisation de __toString() : <b><?phpecho$greg?></b></p><hr><?php$className="People";$toto=new$className("toto");// désignation de la classe avec une chaine...echo"<p>Autre utilisation de People: <b>$toto</b></p>";?>
Résultat
Le contenu de l'attribut : grégory bourguin
Utilisation de __toString() : Grégory Bourguin
Autre utilisation de People: Toto
Vous aurez remarqué que, similairement à Java, un echo sur un objet fait
automatiquement appel à sa méthode __toString() (qu'on a ici surchargée).
Membres de Classe + Héritage
Comme en Java, les classes peuvent avoir des membres de classe (static).
on y accède par :: (au lieu de -> pour les membres d'instance).
un objet peut référencer sa classe grâce à self.
Le mécanisme d'héritage de PHP est aussi similaire à celui de Java.
pour hériter on utilise extends.
un objet peut faire appel à un membre de sa classe mère grâce à parent.
Exemple d'une classe Citizen qui hérite de People:
Citizen.php
<?phprequire_once"People.php";classCitizenextendsPeople{// attribut de classe (static)privatestaticint$population=0;// méthode de classe (static)publicstaticfunctiongetPopulation():int{returnself::$population;// accès à l'attribut de classe}// -----------------------------------------------------------------------// attribut d'instanceprivate?string$address;// le ? signifie que l'attribut peut être null/**
* Citizen constructor.
* @param $name
*/publicfunction__construct($name){parent::__construct($name);// appel à une méthode de la superclasseself::$population++;// accès à un membre static}/**
* @param string|null $address
*/publicfunctionsetAddress(?string$address):void{$this->address=$address;}/**
* @return string|null
*/publicfunctiongetAddress():?string{return$this->address;}}
Utilisation de la classe :
ex_02_static_extends.php
<?phpinclude"Citizen.php";$greg=newCitizen("grégory bourguin");// la syntaxe Heredoc pour une chaine sur plusieurs lignes$adress=<<<EOT666 Highway to Hell
NEWHAVEN-USAEOT;$greg->setAddress($adress);?><p><?phpecho"<b>$greg</b> a été créé."?></p><pstyle="white-space: pre ;font-weight: bold"><?phpecho$greg->getAddress()?></p><p>
Population : <b><?phpechoCitizen::getPopulation()?></b></p>
Résultat
Grégory Bourguin a été créé.
666 Highway to Hell
NEW HAVEN - USA
Population : 1
Classes Abstraites / Interfaces
abstract
Toujours comme en Java, les classes abstraites de PHP sont des classes avec au moins une
méthode abstraite.
Pour les classes comme pour les méthodes, on utilise le mot clé abstract.
<?phprequire_once"Dog.php";require_once"Bird.php";$dog=newDog();$bird=newBird();?><p><?phpecho$dog?><br><?phpecho$bird?><br>
But... <ahref="https://youtu.be/jofNR_WkoCE"target="_blank">What does the Fox say ???</a></p>
Quand toutes le méthodes sont abstraites, on peut aussi définir des interfaces.
interface remplace abstract class.
implements remplace extends.
Les Exceptions
Encore une fois, PHP founit un mécanisme d'exceptions similaire à
celui de Java constitué de 3 types de blocs :
try : contient le code susceptible de générer une Exception.
catch(Type ex) : récupère l'instance (d'une sous-classe)
d'Exception.
Il peut y avoir plusieurs blocs catch pour capturer plusieurs types
d'Execption.
finally : un bloc qui sera exécuté quel qu'ait été le traitement du
try ... catch.
Voici un exemple avec une classe Fraction dont la méthode setDenominateur
(aussi utilisée dans le __construct) est susceptible de générer une exception :
Fraction.php
<?phpclassFraction{privateint$numerateur;privateint$denominateur;publicfunction__construct(int$numerateur,int$denominateur){$this->setNumerateur($numerateur);$this->setDenominateur($denominateur);}/**
* @return int
*/publicfunctiongetNumerateur():int{return$this->numerateur;}/**
* @param int $numerateur
*/publicfunctionsetNumerateur(int$numerateur):void{$this->numerateur=$numerateur;}/**
* @return int
*/publicfunctiongetDenominateur():int{return$this->denominateur;}/**
* @param int $denominateur
* @throws Exception
*/publicfunctionsetDenominateur(int$denominateur):void{if($denominateur==0){thrownewException("Division par 0 !");}$this->denominateur=$denominateur;}/**
* @return string
*/publicfunction__toString(){return"$this->numerateur / $this->denominateur";}}
Utilisation :
ex_04_exception.php
<?phprequire_once"Fraction.php";$fraction=newFraction(1,2);echo"<p>Voici une fraction : $fraction</p>";try{$fraction->setDenominateur(0);}catch(Exception$e){echo"
<p>
Une erreur s'est produite :
<span style='color: red'>".$e->getMessage()."</span>
</p>
";}
Résultat
Voici une fraction : 1 / 2
Une erreur s'est produite :
Division par 0 !
Espace de nommage
Instruction namespace
Plus un projet grandit, plus il a de chance d'utiliser des classes différentes mais qui
portent le même nom. Ceci est encore plus probable lorsque le projet propose/intègre des frameworks
réutilisables.
En PHP, la notion de namespace permet de différencier des classes qui portent
le même nom en y ajoutant un espace de nommage.
En suivant cette méthode, on peut imaginer que nos classes Animal, Dog et
Bird précédemment définies fassent partie d'un namespace nommé
web3\animals.
Il suffit alors d'utiliser l'instruction namespace au tout début de ces 3 classes.
Pour utiliser Dog, il faut maintenant utiliser son nom
complet : \web3\animals\Dog.
<?php// .. je ne l'ai pas mis ici, mais il ne faut pas oublier d'inclure Dog.php$chien=new\web3\animals\Dog();echo$chien->scream();?>
Instruction use
Il peut sembler lourd et fastidieux de préfixer le nom de la classe à chaque fois qu'on veut l'utiliser.
Heureusment PHP offre une solution :
L'instruction use permet d'importer
une classe afin de pouvoir ensuite l'utiliser sans préciser son namespace.
On pourra alors écrire :
<?php// .. je ne l'ai pas mis ici, mais il ne faut pas oublier d'inclure Dog.phpuseweb3\animals\Dog;$chien=newDog();echo$chien->scream();?>
Arborescence
Dans une application complexe, le nombre de classes peut vite grandir :
il ne serait pas efficace de mettre tous les fichiers correspondants dans le même dossier.
Une bonne pratique est créer une arborescence de dossiers contenant les fichiers des classes
et qui reflète la hiérarchie du namespace.
Les sites en PHP Objet placent généralement leurs classes dans un dossier nommé class situé
à la racine du site.
L'idée est donc de mettre tous les fichiers PHP correspondant à des définitions de classes dans une
arborescence à partir du dossier class, et qui reflète la hiérarchie définie par les
namespace.
Dans notre exemple, on aurait alors quelque chose comme :
NB: __DIR__ est une des
"
constantes magiques"
de PHP qui contient le nom (complet) du dossier du fichier (ici test.php)
dans laquelle l'instruction se trouve.
Autoloading
Un site PHP peut impliquer de nombreuses classes et donc l'inclusion de nombreux fichiers .php
(puisqu'on a 1 classe par fichier).
Afin d'éviter une profusion de require (ou require_once, etc.), PHP offre la
possibilité de mettre en oeuvre ce qu'on appelle l'autoloading.
La fonction PHP spl_autoload_register permet de créer une chaine d'autoload.
Il s'agit d'enregistrer une (série de) fonction(s) qui sera(ont) appelée(s) automatiquement pour tenter
d'inclure le fichier PHP correspondant à une classe la première fois qu'elle est utilisée.
Étape 1 : une fonction d'inclusion
La première étape consiste à écrire une fonction qui sera capable d'inclure le fichier .php
correspondant à une classe à partir de son nom complet (namespace).
Si on reprend l'exemple précédent, la classe Dog s'appelle en réalité : web3\animals\Dog
... et elle se trouve dans le fichier : /class/web3/animals/Dog.php.
Pour trouver le fichier à inclure à partir du nom web3\animals\Dog :
On remplace les \ avec le séparateur de dossiers /. web3\animals\Dog -> web3/animals/Dog
On ajoute l'extension .php.
-> web3/animals/Dog.php
On ajoute le dossier "racine" /class/ dans lequel se trouvent toutes les classes.
-> /class/web3/animals/Dog.php
Le nom de la fonction n'est pas (très) important : la technique d'autoloading permet d'ailleurs
d'en définir plusieurs (donc il n'y a pas/plus un nom unique standardisé).
Nous l'appellerons ici autoload
(en souvenir de l'ancienne technique avant PHP 7.2 qui utilisait 1 fonction nommée __autoload).
functionautoload($class_name){// on remplace les \ du namespace par les / des répertoires$class_name=str_replace('\\','/',$class_name);// on inclut le fichier correspondantrequire'class/'.$class_name.'.php';}
Étape 2 : enregistrer la fonction pour l'autoloading
La fonction PHP spl_autoload_register permet de fournir à PHP une (série de) fonction(s)
qui sera(ont) automatiquement appelée(s) lors de la 1ere référence à une classe
pour inclure son fichier .php
Il suffit donc de faire appel à cette fonction en lui passant en paramètre une fonction
d'inclusion pour que PHP l'utilise automatiquement lorsqu'il recontrera une (nouvelle) classe.
Le code "complet" pour activer l'autoload :
<?phpfunctionautoload($class_name){// on remplace les \ du namespace par les / des répertoires$class_name=str_replace('\\','/',$class_name);// on inclut le fichier correspondantrequire'class/'.$class_name.'.php';}spl_autoload_register('autoload');?>
Étape 3 : Retirer les require (etc.) pour les fichiers de classes
Quand le spl_autoload_register a été exécuté (dans le flux d'exécution d'un script),
vous n'avez plus à faire d'inclusion pour tous les fichiers qui définissent des classes.
L'idée est donc d'ajouter les instructions d'autoloading au tout début du script, et de retirer
tous les require (etc.) qui référencent des fichiers classe.
... et un fichier test.php qui utilise l'autoloading :
test.php
<?phpfunctionautoload($class_name){// on remplace les \ du namespace par les / des répertoires$class_name=str_replace('\\','/',$class_name);// on inclut le fichier correspondantrequire'class/'.$class_name.'.php';}spl_autoload_register('autoload');$chien=new\web3\animals\Dog();echo$chien->scream();
Résultat
WOOF
Étape 4 : Finalisation
Pour que l'autoloading soit utilisable dans plusieurs de vos scripts, l'idée est de le mettre dans un fichier
.php qui sera inclus là où on en a besoin.
NB: oui, on va ajouter une inclusion, mais elle permet d'enlever toutes celles qui référencent des fichier
class !
Le nom du fichier n'est pas important : on l'appellera ici
init_autoload.php
init_autoload.php
<?phpfunctionautoload($class_name){// on remplace les \ du namespace par les / des répertoires$class_name=str_replace('\\','/',$class_name);// on inclut le fichier correspondantrequire'class/'.$class_name.'.php';}spl_autoload_register('autoload');
... et il suffit maintenant d'inclure ce fichier au tout début des scripts qui utilisent des classes.
L'archive
ex05_autoload_v2.zip
contient une variante de cet exemple :
on y remplace le fichier init_autoload.php
par le fichier class/Autoloader.php.
Ce fichier définit la classe
\Autoloader et sa méthode de classe register qui
contient l'appel à spl_autoload_register. NB : dans la suite du cours, j'aurai tendance à utiliser cette 2ème version.
Un site web est généralement constitué de nombreuses pages dont le contenu est différent, mais qui
partagent la même section head, voire, dans la partie body, les mêmes
header et footer.
Imaginez par exemple un site de e-commerce avec une page d'accueil index.php, une page
de login login.php, un magasin store.php, un panier cart.php, etc.
Pour l'unité du site, il est nécessaire de démarrer chaque page avec le même code, d'inclure les mêmes
CSS, etc. Cela fait beaucoup d'include ou require qui sont copié/collés dans
chaque page...
Pour pallier ce problème, une solution consiste à créer un template, c'est à dire une
structure générique qui sera utilisée pour générer toutes les pages du site en répétant les parties
communes et en permettant d'y injecter les différences inhérentes à chaque page.
Exemple de définition de template
La technique pour créer un (des) template n'est pas forcément liée aux objets, mais c'est une manière
efficace de procéder.
Nous allons donc ici créer une classe nommée Template (NB: c'est VOTRE classe, donc elle
pourrait porter un autre nom et être construite différemment !) avec une méthode render($content)
dont le but est d'encapsuler un contenu de page ($content) dans la "coquille" du site constituée
d'un head, header et footer communs à toutes les pages.
NB: pour simplifier l'exemple, je n'ai pas utilisé de CSS externe, n'ai pas créé de namespace,
et n'ai pas mis en place d'autoloading... mais ce serait mieux de le faire !
Template.php
<?phpclassTemplate{publicstaticfunctionrender(string$content):void{?><!doctypehtml><htmllang="en"><head><metacharset="UTF-8"><title>Test Buffering</title><style>.black-ribbon{padding: 3px;background: black ;color: white ;}#injected-content{height: 100px;display: flex;justify-content: start;align-items: center;color: darkred;}</style></head><body><?phpinclude"header.php"?><divid="injected-content"><?phpecho$content?><!-- INJECTION DU CONTENU --></div><?phpinclude"footer.html"?></body></html><?php}}
Vous pouvez remarquer que la méthode render injecte le contenu du paramètre
$content dans le template HTML du site, entre l'inclusion de header.php et
footer.html.
Pour l'exemple, le contenu de ces 2 fichiers est très simple :
header.php
<headerclass="black-ribbon">
Ceci est un header
</header>
footer.html
<footerclass="black-ribbon">
Ceci est un footer
</footer>
Utilisation : injection par buffering
Il reste maintenant à définir une variable qu'on pourra utiliser en tant que paramètre $content
de Template::render.
Le problème est que cette variable doit contenir une string correspondant au résultat d'un
contenu généré par PHP (construit avec par exemple du code HTML pur, des include/require,
des echo, etc.).
La solution réside dans la temporisation de sortie...
La fonction
ob_start
déclenche la temporisation de sortie de PHP.
En d'autres termes, après un appel à ob_start toutes les sorties
d'un script PHP sont stockées dans un tampon/buffer au lieu d'être envoyée directement au navigateur.
La fonction
ob_get_cleanstoppe la temporisation de sortie de PHP,
retourne le contenu du buffer/tampon, puis l'efface.
En résumé, ces 2 fonctions permettent de "détourner" la sortie de PHP pour la stocker dans une variable
qui pourra être utilisée ultérieurement : c'est exactement ce qu'il nous faillait pour injecter le
contenu d'une page dans notre template.
On peut alors par exemple écrire notre page d'accueil comme suit.
index.php
<!-- Ce serait mieux d'utiliser un autoloading... --><?phprequire_once__DIR__.DIRECTORY_SEPARATOR."Template.php";?><!-- Démarre le buffering --><?phpob_start()?><pstyle="font-size: 1.2em">
Ce texte a été <b><?phpecho"bufferisé"?></b>
avant d'être injecté dans mon template.
</p><!-- Récupère le contenu du buffer (et le vide) --><?php$content=ob_get_clean()?><!-- Utilisation du contenu bufferisé --><?phpTemplate::render($content)?>
Résultat
Test Buffering
Ceci est un header
Ce texte a été bufferisé
avant d'être injecté dans mon template.
Bien entendu, tout l'intérêt est que le template peut être ainsi utilisé pour générer toutes les pages
de votre site web !
On peut donc utiliser Template pour générer d'autres pages du site comme
cart.php
cart.php
<!-- Ce serait mieux d'utiliser un autoloading... --><?phprequire_once__DIR__.DIRECTORY_SEPARATOR."Template.php";?><!-- Démarre le buffering --><?phpob_start()?><h2>Votre panier est vide...</h2><!-- Récupère le contenu du buffer (et le vide) --><?php$content=ob_get_clean()?><!-- Utilisation du contenu bufferisé --><?phpTemplate::render($content)?>
PHP permet de manipuler (créer, lire, écrire, supprimer) des fichiers sur le serveur.
Il est important de se souvenir qu'il est nécessaire de faire en sorte que PHP (le serveur Web) possède
bien les droits nécessaires sur les dossier et fichiers que vous souhaitez manipuler, ceci en accord
avec les actions que vous voulez effectuer.
Le script simple_lecture.php utilise file_get_contents pour charger son contenu
et l'afficher dans un div.
lecture_simple.php
<style>.lyrics{height: 150px ;padding: 10px;background: black;color: greenyellow;overflow: auto ;white-space: pre ;}</style><?php// Lecture du fichier dans le répertoire courant$texte=file_get_contents(__DIR__."/lets_bang.txt");?><divclass="lyrics"><?phpecho$texte?></div>
Résultat
Let's Bang (Shaka Ponk) :
Saturday night in a dancing house I say (yeah yeah yeah yeah)
Storming boys staring at my eyes I say (yeah yeah yeah yeah)
You're the one I like
I wanna share my story tonight
Big mama you're my kind
Gimme a part of your precious time
Hey you're the one I like
I wanna share your love tonight
I wanna smoke your special thing
Let's Bang bang bang
You'd better do your dance
You'd better take that chance
You'd better move your butt
You gotta show me what you got
You wanna check this man
Jump on the line
You gotta shake that ass
If you wanna have mine
It's soon the perfect time
I'm sounding lighter
You wanna hang, wanna hang
So do the dance and
Bang bang bang bang bang
Do the dance mate and I lose cabeza
Yeah yeah yeah yeah
You get my ass with the troubleshoot styla
Yeah yeah yeah yeah
I wanna get naughty and no wanna doubt
Yeah yeah yeah yeah
The boys over the rainbow is just what I want
Yeah ! Yeah ! Yeah !
Hey yo chic-chica you wanna hang out with the jerk?
So bring your ass to table!
Wanna hang wanna hang
So do the dance and
Bang bang bang bang bang !
I kill yo, I kill yo, I kill yo yo yo, I kill yo
La fonction file_put_contents permet d'écrire dans un fichier.
Par défaut, cette fonction crée le fichier s'il n'existe pas et/ou remplace totalement son contenu.
Exemple
Dans cet exemple, on ecrit le contenu de $lyrics dans le fichier local eisbar.txt.
Si le fichier n'existe pas, il est créé. S'il existe, le contenu est remplacé.
On utilise ensuite file_get_contents pour relire le fichier et afficher son contenu.
ecriture_simple.php
<?php// EOT permet de définir du texte sur plusieurs lignes$lyrics=<<<EOT
Eisbär (Grauzone) :
Ich möchte ein Eisbär sein
im kalten Polar
dann müßte ich nicht mehr schrei'n
alles wär' so klar
EOT;$filename=__DIR__."/eisbar.txt";// ecriture dans le fichierfile_put_contents($filename,$lyrics);// (re)lecture du fichier$texte=file_get_contents($filename);?><divclass="lyrics"><?phpecho$texte?></div>
Résultat
Eisbär (Grauzone) :
Ich möchte ein Eisbär sein
im kalten Polar
dann müßte ich nicht mehr schrei'n
alles wär' so klar
Ajout : FILE_APPEND
Le flag FILE_APPEND de file_put_contents permet de ne pas écraser le contenu
du fichier mais de faire des ajouts à la fin.
Exemple
On complète ici le fichier eisbar.txt avec de nouvelles paroles : 4 x la même ligne... ajout_simple.php
<?php$lyrics="\nEisbär'n müssen nie weinen";$filename=__DIR__."/eisbar.txt";// ajout de 4 lignes à la fin du fichierfor($i=0;$i<4;$i++){file_put_contents($filename,$lyrics,FILE_APPEND);}// (re)lecture du fichier$texte=file_get_contents($filename);?><divclass="lyrics"style="height: 240px"><?phpecho$texte?></div>
Résultat
Eisbär (Grauzone) :
Ich möchte ein Eisbär sein
im kalten Polar
dann müßte ich nicht mehr schrei'n
alles wär' so klar
Eisbär'n müssen nie weinen
Eisbär'n müssen nie weinen
Eisbär'n müssen nie weinen
Eisbär'n müssen nie weinen
Comme indiqué précédemment, les fonctions telles que file_get_contents chargent la totalité
des données dans la mémoire, ce qui n'est pas envisageable lorsqu'on doit manipuler de gros fichiers.
NB: PHP dispose d'une taille mémoire maximale limitée (qui peut être modifiée dans sa configuration) pour travailler.
Lorsque l'on veut manipuler un fichier de manière plus "fine" (ligne par ligne, caractère par caractère, ...)
PHP peut fournir non pas la totalité du contenu, mais une ressource qui représente un flux (stream) permettant
de se déplacer dans le fichier sans le charger totalement ne mémoire.
fopen ouvre un flux sur un fichier ouvert dans un mode précisé en paramètre.
La liste des modes disponibles (et leur effet) est dans la documentation
Le flux récupéré peut ensuite être utilisé avec diverses autres fonctions.
Quand les traitements sont terminés, il faut fermer le flux.
fclose permet de fermer (libérer) un flux.
Nous allons voir comment utiliser ces méthodes ci-après avec par exemple fgets.
fgets permet de lire un flux ligne par ligne : chaque lecture renvoie une ligne (ou null si
on est à la fin du fichier), et fait passer le "curseur" à la ligne suivante.
Exemple
Dans l'exemple suivant, on ouvre le fichier lets_bang.txt en lecture seule avec fopen,
puis on récupère les $max premières lignes pour les afficher, avant de fermer le flux avec
fclose.
lecture_lignes.php
<?php// ouverture du fichier (ici en lecture seule)$file=fopen(__DIR__."/lets_bang.txt",'r');$max=5;?>
Les <?phpecho$max?> première(s) ligne(s) de la chanson :
<divclass="lyrics"><?php// Lecture et affichage des $max premières lignesfor($i=1;$i<=$max;$i++){$line=fgets($file);// récupération d'une ligneif($line===null)break;// on sort s'il n'y a plus de ligne à lireecho$i." : ".$line;// affichage}// fermeture du fichierfclose($file);?></div>
Résultat
Les 5 première(s) ligne(s) de la chanson :
1 : Let's Bang (Shaka Ponk) :
2 :
3 : Saturday night in a dancing house I say (yeah yeah yeah yeah)
4 : Storming boys staring at my eyes I say (yeah yeah yeah yeah)
5 : You're the one I like
De nombreuses autres fonctions
Il existe de nombreuses autres fonctions permettant de manipuler les fichiers comme :
fputs :
le pendant de fgets pour écrire une ligne.
fseek:
pour déplacer le "curseur" dans le fichier.
PHP est aussi capable de manipuler des chaines de caractères au format JSON, et donc
par extension de travailler avec des fichiers .json pour stocker/récupérer des données.
NB: d'une manière générale, pour stocker/récupérer des données, on travaillera de préférence en couplant
PHP avec un (ou des) serveur(s) de Bases de Données.
Néanmoins, l'utilisation de fichiers JSON
peut s'avérer pratique quand il y a peu d'information à manipuler.
json_encode et json_decode permettent d'encoder/décoder des objets
au format JSON.
Exemple d'écriture d'un objet en JSON
Dans cet exemple, on crée le tableau associatif $data (un objet PHP),
on l'encode en JSON dans une variable $json,
puis on enregistre la chaine générée dans le fichier data.json.
put_json.php
<?php// création d'un objet$data=array('fname'=>"Grégory",'lname'=>"Bourguin",'email'=>"gregory.bourguin@univ-littoral.fr");// encodage de l'objet$json=json_encode($data,JSON_PRETTY_PRINT);// JSON_PRETTY_PRINT met des \n dans la chaine pour qu'elle soit plus lisible// enregistrement dans un fichierfile_put_contents(__DIR__."/data.json",$json);
récupère les blagues enregistrées dans le fichier jokes.json.
génère du code HTML qui affiche ces blagues.
Attention: même si cela ressemble à ce que nous avions fait dans le cours de Javascript, il faut ici lire
les données et afficher les blagues exclusivement en PHP !
Résultat attendu :
Why did the cowboy have a weiner dog? Somebody told him to get a long little doggy.
Me: If humans lose the ability to hear high frequency volumes as they get older, can my 4 week old son hear a dog whistle?
Doctor: No, humans can never hear that high of a frequency no matter what age they are.
Me: Trick question... dogs can't whistle.
What did the dog say to the two trees? Bark bark.
I adopted my dog from a blacksmith. As soon as we got home he made a bolt for the door.
My dog used to chase people on a bike a lot. It got so bad I had to take his bike away.
What kind of dog lives in a particle accelerator? A Fermilabrador Retriever.
I went to the zoo the other day, there was only one dog in it. It was a shitzu.
“My Dog has no nose.” “How does he smell?” “Awful”
what do you call a dog that can do magic tricks? a labracadabrador
It was raining cats and dogs the other day. I almost stepped in a poodle.
At the boxing match, the dad got into the popcorn line and the line for hot dogs, but he wanted to stay out of the punchline.
What did the Zen Buddist say to the hotdog vendor? Make me one with everything.