Programmation PHP

Transcription

Programmation PHP
Programmation PHP
François Rioult
7 septembre 2012
Table des matières
1 Notion de programme, instructions
1.1
1.2
1.3
4
Premier exemple : lire un message et l'acher . . . . . . . . . . .
4
1.1.1
Entrée / sortie
4
1.1.2
Suite de l'exemple
1.1.3
Séquencement . . . . . . . . . . . . . . . . . . . . . . . . .
6
1.1.4
Variable . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6
Structures de contrôle
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
1.2.1
Instruction conditionnelle
1.2.2
Itérations
. . . . . . . . . . . . . . . . . .
5
8
8
. . . . . . . . . . . . . . . . . . . . . . . . . . .
10
Bilan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
2 TP1
13
2.1
Découvrir
2.2
Programmes et exercices (TD)
2.2.1
2.2.2
2.2.3
2.2.4
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
Acher le double d'un nombre choisi par l'utilisateur . .
13
Acher le nombre de lettres et le nombre de "a" que
contient un mot choisi par l'utilisateur . . . . . . . . . . .
13
Exercice . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
Comparer deux nombres saisis par l'utilisateur - diérentes écritures . . . . . . . . . . . . . . . . . . . . . . . .
2.2.5
13
. . . . . . . . . . . . . . . . . . .
14
Répondre des messages diérents en fonction du nom de
. . . . . . . . . . . . . . . . . . . . . . . . . .
15
2.2.6
l'utilisateur
Exercice . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
2.2.7
Répeter un traitement jusqu'à ce que l'utilisateur veuille
2.2.8
s'arrêter . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
Amélioration : compter le nombre de traitements faits
16
. .
2.3
Jeu du nombre mystérieux . . . . . . . . . . . . . . . . . . . . . .
17
2.4
Vote
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18
2.4.1
Version 1 : saisie des noms au clavier . . . . . . . . . . . .
18
2.4.2
Version 2 : les noms sont stockés dans un chier
18
. . . . .
3 Fichier texte et algorithmes sur les chiers
3.1
3.2
19
Notion de chier texte . . . . . . . . . . . . . . . . . . . . . . . .
19
3.1.1
Dénition . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
3.1.2
Principe d'utilisation des chiers textes
. . . . . . . . . .
20
. . . . . . . . . . . . . .
22
Algorithmes élémentaires sur les chiers
3.2.1
Lecture d'un chier . . . . . . . . . . . . . . . . . . . . . .
22
3.2.2
Création et écriture d'un chier . . . . . . . . . . . . . . .
25
1
4 TP 2 - Calcul de moyenne de notes
26
4.1
Exercice 1 : utilisation de boucles . . . . . . . . . . . . . . . . . .
4.2
Exercice 2 : compter les rouges et les verts . . . . . . . . . . . . .
26
4.3
Exercice 3 : moyenne de notes par personne . . . . . . . . . . . .
27
5 Les tableaux
26
29
5.1
Les tableaux simples . . . . . . . . . . . . . . . . . . . . . . . . .
5.2
Les chaînes de caractères . . . . . . . . . . . . . . . . . . . . . . .
31
5.3
Les tableaux associatifs
32
5.4
Fonctions pour les tableaux
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
6 TD 3
6.1
6.2
34
35
Exercice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.1.1
29
Manipulations
35
. . . . . . . . . . . . . . . . . . . . . . . .
35
Exercice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
35
7 TP 3
38
7.1
Exercice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
38
7.2
Exercice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
38
7.3
Exercice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
38
7.3.1
Version élémentaire . . . . . . . . . . . . . . . . . . . . . .
38
7.3.2
Vérication des balises . . . . . . . . . . . . . . . . . . . .
38
7.3.3
Vérication avancée
39
. . . . . . . . . . . . . . . . . . . . .
8 Les fonctions
40
8.1
Exemples
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8.2
Portée des variables
8.3
Génie logiciel
8.4
Récursivité
8.5
. . . . . . . . . . . . . . . . . . . . . . . . .
40
42
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
44
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
45
Passage par référence . . . . . . . . . . . . . . . . . . . . . . . . .
46
9 TD 4
49
9.1
Exercice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
49
9.2
Exercice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
49
10 TP 4
50
10.1 Exercice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
50
10.1.1 Exercice . . . . . . . . . . . . . . . . . . . . . . . . . . . .
50
10.2 Exercice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
50
10.3 Exercice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
50
11 Programmation objet
51
11.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11.2 Conception orientée objet
51
. . . . . . . . . . . . . . . . . . . . . .
52
11.3 Passage d'objet . . . . . . . . . . . . . . . . . . . . . . . . . . . .
55
11.4 Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . .
55
12 TD 5
56
12.1 Exercice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12.1.1 enregistre
12.1.2 lit
56
. . . . . . . . . . . . . . . . . . . . . . . . . . .
56
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
56
2
13 Héritage
57
14 TD - Héritage
62
14.1 Mise en place des formulaires
. . . . . . . . . . . . . . . . . . . .
14.2 Ajout de classes pour gérer les enfants
. . . . . . . . . . . . . . .
15 Exceptions
63
65
15.1 Principe des exceptions
15.2 La classe PHP
62
. . . . . . . . . . . . . . . . . . . . . . .
65
. . . . . . . . . . . . . . . . . . . . . .
65
Exception
15.3 Héritage d'exception
. . . . . . . . . . . . . . . . . . . . . . . . .
15.4 Utilisation des exceptions
. . . . . . . . . . . . . . . . . . . . . .
3
66
67
Chapitre 1
Notion de programme,
instructions
1.1 Premier exemple : lire un message et l'acher
Programme
: description précise d'actions à exécuter sur un ordinateur pour
réaliser une tâche.
Les programmes ne se rencontrent pas seulement en informatique. Exemples :
partition musicale, recette de cuisine, méthode pour calculer la longueur moyenne
et le poids moyen d'un ensemble de personnes.
Traitement automatique
: signie que le traitement, une fois déni, ne dépend
que des données fournies en entrée et non de choses extérieures. L'ordinateur
n'est pas l'unique type de machine à eectuer des traitements automatiques
(ou programmés) : un orgue de barbarie, un métier à tisser automatique, une
machine à laver sont aussi des machines programmées.
Exemple de programme PHP : acher un message à l'écran
Voici ce premier programme :
1
<?php
?>
echo "Bonjour à tous\n" ;
Remarquer les balises
<?php et ?> pour indiquer au système qu'il s'agit d'un
script PHP. Ces balises doivent obligatoirement être présentes.
Le texte entre " " est une
chaine
de caractères.
\n
est le saut de ligne dans
un contexte de chaîne.
Pour exécuter le programme (stocké dans le chier de nom
test1.php), taper
la ligne de commande :
bruno@pc159:~$ php test1.php
1.1.1 Entrée / sortie
On souhaite maintenant modier le programme pour que celui-ci demande
à l'utilisateur son nom et l'ache. De quoi avons-nous besoin ?
4
entrée / sortie : saisie du
variable : pour stocker et
nom (entrée) et achage (sortie),
retrouver le nom.
Les notions d'entrée / sortie (encore appelées lecture / écriture) sont à considérer du point de vue de l'ordinateur (cf. gure 1.1).
écrire
humain
lire
Figure 1.1 lecture / écriture
entrée
: l'utilisateur fournit des informations à l'ordinateur (i.e. lecture
lire()
<RETOUR>).
d'information de la part de l'ordinateur) : l'instruction
une ligne de saisie (n de la saisie terminée par
sortie
collecte
: l'ordinateur donne des informations à l'utilisateur (i.e. écriture
(achage) d'information de la part de l'ordinateur) : la fonction
echo
envoie ses arguments sur le périphérique de sortie standard.
Remarque : La fonction
lire
utilisée dans les programmes qui suivent pour
lire une chaine de caractères tapée au clavier par l'utilisateur, n'est pas une
fonction prédénie dans PHP. La suite d'instructions permettant de réaliser
ce travail n'est pas détaillée ici cer elle est un peu complexe pour démarrer.
Le code de cette fonction est rangé dans le chier
fonctions1.inc
que vous
devez recopier dans votre répertoire de travail. Pour pouvoir l'utiliser dans un
programme rajouter en tête du programme l'instruction :
require("fonctions1.inc")
1.1.2 Suite de l'exemple
Voici le programme qui permet de réaliser cette version améliorée de l'exemple.
1
5
<?php
require("fonctions1.inc");
echo "Bonjour à tous\n";
echo "Quel est ton nom : ";
$nompersonne = lire();
echo "Bonjour $nompersonne !\n";
?>
Voici maintenant un exemple de résultat d'exécution de ce programme.
Bonjour à tous
Quel est ton nom : fanny
Bonjour fanny
5
En fait dans un premier temps il y a eu seulement achage de :
Bonjour à tous
Quel est ton nom :
Le programme s'arrête, et reprend son exécution lorsque l'utilisateur a ni
de taper une chaine de caractères terminée par un retour-chariot. Le reste du
texte est alors aché.
1.1.3 Séquencement
Séquencement.
Les instructions d'un programme sont exécutées séquen-
tiellement. Cela signie :
les instructions sont traitées les unes après les autres,
chaque instruction est traitée une fois, aucune n'est répétée ni omise,
les instructions sont traitées de la première à la dernière, le programme
est alors ni,
l'état nal (par exemple, les variables et leurs valeurs) d' une instruction
devient l'état initial de l'instruction qui la suit.
Marque de séquencement séparant deux instructions :
";".
1.1.4 Variable
$nompersonne
est ce que l'on appelle une variable.
En informatique, une variable est un objet permettant de stocker et de retrouver une information en mémoire (cf. gure 1.2).
<nom>
<valeur>
$utilisateur
Pierre
Figure 1.2 schématisation d'une variable
Une variable est caractérisée par :
nom : choisi par le programmeur, désigne la variable sans ambiguïté (ici :
$nompersonne).
valeur : contenu de la variable (ici : fanny après que l'utilisateur ait ni
de taper ce texte au clavier.
Remarque :
une variable peut être "accessible" de certains points d'un pro-
gramme et pas d'autres. C'est ce que l'on appelle la portée d'une variable. Cette
question sera vue avec la modularité.
•
Pas de véritable notion de type en PHP (contrairement à d'autres langages). Un nom de variable commence par
•
$
Choisir des noms signicatifs pour les variables. PHP distingue majuscules
/ minuscules. Convention possible : faire ressortir les diérentes parties
d'un nom par une majuscule.
6
•
Initialisation de variables par défaut par PHP. Cette initialisation dépend
du contexte (la notion de contexte sera ultérieurement détaillée). Si la
variable considérée est :
nombre : valeur 0,
chaîne : chaîne vide,
valeur booléenne attendue : valeur "faux" (codée
FALSE)
Attention : une chaîne ayant la valeur 0 est considérée dans un contexte
booléen comme ayant la valeur faux. Exemple (cet exemple sera détaillé à la
section 1.2.1).
<?php
$a = "toto";
if ($a) {
echo "vrai \n" ;
}
else {
echo "faux \n" ;
}
?>
1
5
ache
faux
si
$a
n'est pas initialisé.
aché si
$a
faux
est aussi aché si
a (par exemple) la valeur
1
$a
a la valeur
0
mais
vrai
est
Autre exemple :
echo "Somme = ", 30 + $a + 10 ;
echo "\n" ;
echo "Chaine = ", "30" . $a . "10"
ache :
Somme = 40
Chaine = 3010
Aectation. Assignation d'une valeur à une variable : symbole = (à ne pas
confondre avec la notion d'égalité !).
$n1 = $n2 ;
$n1 est le receveur, $n2 le donneur
Le donneur peut être n'importe quelle expression, le receveur doit être un emplacement valide de stockage (variable, élément de tableau).
$n1 = $n1 + $n2 ;
$n1
est ici d'abord donneur puis receveur.
lire() est ce que l'on appelle une fonction. Quand
$nompersonne = lire(), est rencontrée, il y a successivement
Dans le texte ci-dessus
l'instruction
7
•
exécution de la fonction
lire()
: le programme s'arrète et ne reprend
qu'après que l'utilisateur ait tapé un retour chariot.
•
la chaine de caractère qu'a tapé l'utilisateur est considérée comme le résultat de la fonction
lire(). On dit que lire() retourne
caractères.
•
cette valeur retournée est aectée à la variable
Quand le programme passe à l'instruction suivante
cette chaine de
$nompersonne
echo '"Bonjour", $nompersonne
, c'est alors la valeur de cette variable qui est utilisée pour exécuter l'instruction
et produire l'achage.
1.2 Structures de contrôle
1.2.1 Instruction conditionnelle
Imaginons qu'on veuille personnaliser la réponse : si l'utilisateur est Pierre,
on ache
bonjour mon cher Pierre, sinon bonjour <Nom de l'utilisateur>.
Pour cela, il faut utiliser une instruction conditionnelle.
if (expression) {
instruction1 ;
instruction2 ;
}
else {
instruction3 ;
instruction4 ;
}
Dans le contexte d'une instruction conditionnelle,
<expression>, (aussi apFALSE). Ne pas oublier
pelée test), est évaluée à une valeur booléenne (TRUE ou
les
() autour de <expression>. Les délimiteurs de blocs sont impératifs dès que
else et les
il y au moins deux instructions à exécuter dans une alternative. Le
instructions qui le suivent peuvent être absents.
1
<?php
require("fonctions1.inc");
echo "Bonjour à tous\n" ;
echo "Quel est ton nom : " ;
$nompersonne = lire() ;
5
10
?>
if ($nompersonne == "Pierre") {
echo "Bonjour mon cher Pierre\n" ;
}
else {
echo "Bonjour ", $nompersonne ,"\n" ;
}
Remarques :
•
Ici les
{ }
auraient pu être omises puisque dans chaque alternative il n'y
a qu'une seule instruction à exécuter.
8
•
Observer l'indentation du texte du programme. Elle n'est pas signicative
pour PHP. Le texte pourait être écrit entièrement sur une seule ligne.
Mais une bonne disposition facilite la lecture et la compréhension de la
structuration du programme pour le programmeur.
•
Une partie entre accolades s'appelle un bloc. Le ; qui suit un bloc peut-être
omis.
S'il y a plus de deux alternatives on peut utiliser une "cascade" de
elseif :
<?php
require("fonctions1.inc") ;
echo "Bonjour à tous\n" ;
echo "Quel est ton nom : " ;
$nompersonne = lire() ;
1
5
10
15
?>
if ($nompersonne == "Pierre") {
echo "Bonjour mon cher Pierre \n" ;
}
elseif ($nompersonne == "Marie") {
echo "Bonjour ma chère Marie\n" ;
}
elseif ($nompersonne == "Clara") {
echo "Bonjour ma très chère Clara\n" ;
}
else {
echo "Bonjour ", $nompersonne ,"\n" ;
}
Remarquez que les diérentes alternatives sont disjointes : si on passe dans
une, les suivantes sont ignorées même si une ou plusieurs conditions sont vériées.
Comme dit précédemment, l'évaluation de l'expression qui suit le
if
doit
produire vrai ou faux. Par extension on considèrera qu'une chaine de carac-
TRUE.
FALSE.
tères qui n'est pas vide ou un nombre non nul à la valeur
et 0 sont considérés comme ayant la valeur booléenne
La chaine vide
Exemple :
<?php
if ($a) {
print "vrai \n" ;
}
else {
print "faux \n" ;
}
?>
Dans le programme ci-dessus
$a n'a jamais reçu d'aectation. Il est considéré
comme étant la chaine vide ou le nombre 0 et dans le test l'évaluation booléenne
sera donc faux. Ce programme achera donc le mot
9
faux.
1.2.2 Itérations
On souhaite répéter l'achage du message tant que la chaîne
fin
n'est pas
tapée. Pour cela, on utilise une itération :
while (expression) {
instruction1 ;
instruction 2 ;
}
L'itération est répétée tant que expression a la valeur vrai. Dans le contexte
<expression>, (i.e. test), est évaluée à une valeur booléenne.
() autour <expression>. Le bloc entre accolades qui suit
while s'appelle le corps de la boucle. (expression) exprime la "condition
d'une itération,
Ne pas oublier les
le
d'arrêt".
<?php
require("fonctions1.inc");
echo "Bonjour à tous\n";
echo "Quel est ton nom : ";
$nompersonne = lire();
1
5
10
15
20
?>
}
while ($nompersonne != "fin") {
if ($nompersonne == "Pierre") {
echo "Bonjour mon cher Pierre\n";
}
elseif ($nompersonne == "Marie") {
echo "Bonjour ma chère Marie\n";
}
else {
echo "Bonjour ", $nompersonne ,"\n";
}
echo "Quel est le nom suivant : ";
$nompersonne = lire();
Remarques :
• ($nompersonne != "fin") est un test qui prend la valeur vrai si la
valeur de $nompersonne est diérente de fin
• Observer le == pour tester l'égalité entre la valeur reçue par $nompersonne
et les chaines Pierre ou Marie suivant le cas.
• Observer que l'instruction $nompersonne = lire() ; apparaît deux fois.
Une première fois avant le while pour saisir le nom de la première personne. Une deuxième fois en n de boucle, an d'avoir une nouvelle valeur
de
$nompersonne
avant de refaire le test.
Il existe plusieurs structures de contrôle permettant de réaliser des boucles,
et souvent plusieurs manières diérentes d'écrire des traitement identiques ou
voisins. Nous y reviendrons ultérieurement.
Reprenons le programme précédent. On veut en outre compter le nombre de
personnes à qui le programme dit bonjour.
10
Quel va être le principe ? L'expliciter en langage courant.
Quelles variables et traitement sont à introduire ?
Voici une solution :
<?php
/*commentaire
Saluer des personnes.
Ce programme permet de montrer les briques élémentaires d'un
programme.
*/
require("fonctions1.inc");
1
5
echo "Bonjour à tous\n" ;
$nbpersonne = 0 ; // initialisation facultative
echo "Quel est ton nom : " ;
$nompersonne = lire() ;
10
while ($nompersonne != "fin") {
$nbpersonne = $nbpersonne + 1 ;
if ($nompersonne == "Pierre") {
echo "Bonjour mon cher Pierre\n";
}
elseif ($nompersonne == "Marie") {
echo "Bonjour ma chère Marie\n";
}
else {
echo "Bonjour ", $nompersonne ,"\n";
} ;
echo "Quel est le nom suivant : " ;
$nompersonne = lire() ;
} ;
15
20
25
30
?>
echo "J'ai dit bonjour à ", $nbpersonne, " personne (s).\n" ;
/* ... */
encadrent un texte que l'on appelle commentaire, qui peut tenir
sur plusieurs lignes.
//
précède également un commentaire mais qui occuppe uniquement la n
de la ligne. Les commentaires sont ignorés par PHP. Ils sont très utiles au
programmeur et autres lecteurs du programme pour comprendre celui-ci.
Remarquer ici l'instruction
$nbpersonne = $nbpersonne + 1 ; L'exécution
de cette instruction se déroule selon un mécanisme analogue à celui décrit un
peu plus haut pour l'aectation
$nbpersonne + 1
$nompersonne = lire() ;
est exécuté ou plus exactement calculé.
le résultat de ce calcul est rangé dans la variable à gauche du signe
=
cette instruction a donc pour eet d'augmenter de 1, la valeur connue par
le système pour la variable
$nbpersonne
11
1.3 Bilan
Eectuons le bilan de chapitre :
•
Un programme se compose d'instructions, celles-ci sont ordonnées et exécutées séquentiellement.
•
Deux types d'instructions :
instruction élémentaire
: instruction directement comprise par PHP :
aectation, lecture, fonctions (echo,
log,. . .).
instruction non élémentaire et écrite par le programmeur
: (lire(). . .
Une telle instruction est écrite pour réaliser une tâche et nit toujours
par se décomposer en termes d'instructions élémentaires (cf. fonctions
et cours sur la modularité).
•
On distingue :
mots réservés : mots et symboles appartenant à PHP :
if, $, ; ,. . .
echo, print,
mots ou instructions librement choisis par le programmeur en respectant
les conventions du langage :
• Commentaire
$nbpersonne = 0 ;. . .
: texte facilitant la lecture du programme par un humain
mais non exploité par la machine. Remarquez la notation diérente entre
commentaire uniligne et multiligne.
• Présentation
: PHP est un langage de format libre : en général, les espaces
entre éléments sont optionnels. Remarquez l'indentation, elle est importante pour la lisibilité du programme par le programmeur.
Principe de déroulement d'un programme (cf. gure 1.3).
état initial
état final
programme
données
résultats
Figure 1.3 déroulement d'un programme
Les instructions manipulent des objets portant l'information : les variables.
Les variables sont consultées ou modiées.
Analogie avec les langues naturelles :
nom
: variable, comme endroit pour conserver quelque chose, un endroit
qui a un nom.
verbe
: commande. Une instruction commençant par un verbe est en gé-
néral impérative et est évaluée pour ses eets secondaires. Ces verbes sont
souvent appelés procédures (la commande
echo est un tel verbe, la sortie
est l'eet secondaire désirée). D'autres verbes traduisent leurs paramètres
d'entrée en valeurs de retour (fonctions).
12
Chapitre 2
TP1
2.1 Découvrir
•
gérez vos répertoires et vos chiers : créez un répertoire pour le module
d'analyse / programmation en PHP, des sous-répertoires par séquence ou
thème.
.php
•
suxez vos scripts PHP par
•
travaillez par analogie : sachez récupérer un programme et le transformer
pour vos propres besoins.
•
récupérez les programmes vus en cours, copiez-les dans votre répertoire
de travail, exécutez-les, modiez-les à votre guise pour observer les diérences, jusqu'à ce que vous ayez bien compris le rôle de chaque instruction.
2.2 Programmes et exercices (TD)
2.2.1
Acher le double d'un nombre choisi par l'utilisateur
Programme doublelog.php
1
5
<?php
require("fonctions1.inc");
echo "Veuillez rentrer un nombre :\n";
$nombre = lire();
echo "Le double de $nombre est : ";
echo 2*$nombre;
echo "\n";
?>
2.2.2 Acher le nombre de lettres et le nombre de "a"
que contient un mot choisi par l'utilisateur
Programme nblettres.php
13
<?php
require("fonctions1.inc");
1
echo "Veuillez entrer un mot\n";
$chaine = lire();
$nblettres = strlen($chaine);
5
10
15
$nba = 0;
for($i=0; $i<$nblettres; $i++)
{
if($chaine[$i] == 'a')
{
$nba++;
}
}
echo "Le mot '$chaine' contient $nblettres lettres et $nba 'a'.\n";
?>
2.2.3 Exercice
En vous inspirant des deux exemples qui précèdent écrire les deux programmes ci-dessous :
1. On demande deux nombres à l'utilisateur, acher leur somme et leur
produit.
2. On demande un mot à l'utilisateur, acher le nombre de voyelles de chaque
type et le nombre total de voyelles.
2.2.4
Comparer deux nombres saisis par l'utilisateur diérentes écritures
Programme pour comparer deux nombres :
Programme comparenombres2.php
<?php
// Comparaison de deux nombres avec test d'égalité
require("fonctions1.inc");
// Saisie des nombres =============================
echo "Donnez-moi un nombre \n ";
$nombre1 = lire();
echo "Donnez-moi un autre nombre \n";
$nombre2 = lire();
// Comparaison ====================================
if ($nombre1 < $nombre2)
{ echo "le premier nombre est plus petit que le deuxième \n" ;}
elseif ($nombre2 < $nombre1)
{echo "le deuxième nombre est inférieur au premier \n" ;}
else
14
{ echo "Les deux nombres sont egaux \n";}
?>
Ou encore
Programme comparenombres3.php
<?php
// Comparaison de deux nombres avec test d'égalité
require("fonctions1.inc");
// Saisie des nombres =============================
echo "Donnez-moi un nombre \n ";
$nombre1 = lire();
echo "Donnez-moi un autre nombre \n";
$nombre2 = lire();
?>
// Comparaison ====================================
if ($nombre1 == $nombre2)
{ echo "Les deux nombres sont égaux \n" ;}
elseif ($nombre2 < $nombre1)
{echo "le deuxième nombre est inférieur au premier \n" ;}
else
{ echo "Le premier nombre est inférieur au second \n";}
2.2.5
Répondre des messages diérents en fonction du
nom de l'utilisateur
Programme nom.php
<?php
require("fonctions1.inc");
?>
echo "quel est votre nom \n";
$nompersonne = lire();
if ($nompersonne == "fanny")
{ print "Bonjour ma chère fanny";}
else
{print "Bonjour $nompersonne";}
2.2.6 Exercice
Ecrire un programme qui compare le nombre de voyelles de deux mots donnés
par l'utilisateur.
2.2.7 Répeter un traitement jusqu'à ce que l'utilisateur
veuille s'arrêter
On reprend le programme qui répond des messages diérents à l'utilisateurs
Programme nomIter1.php
15
<?php
require("fonctions1.inc");
echo "quel est votre nom \n";
$nompersonne = lire();
?>
while ($nompersonne != "fin")
{
if ($nompersonne == "fanny")
print "Bonjour ma chère fanny\n";
else
print "Bonjour $nompersonne\n";
echo "quel est votre nom \n";
$nompersonne = lire();
}
2.2.8 Amélioration : compter le nombre de traitements
faits
Le même en comptant le nombre de personnes saluées.
Programme nomIter2.php
<?php
require("fonctions1.inc");
echo "quel est votre nom \n";
$nompersonne = lire();
$nbpersonne = 0;
?>
while ($nompersonne != "fin")
{$nbpersonne = $nbpersonne +1 ;
if ($nompersonne == "fanny")
print "Bonjour ma chère fanny\n";
else
print "Bonjour $nompersonne \n";
echo "quel est votre nom \n";
$nompersonne = lire();
}
echo "j'ai salué $nbpersonnes \n";
16
2.3 Jeu du nombre mystérieux
Dans le jeu du nombre mystérieux, l'ordinateur tire au hasard un nombre
que l'utilisateur doit deviner. Pour cela, l'utilisateur propose un nombre :
s'il est trop petit, l'ordinateur répond trop petit,
s'il est trop grand, l'ordinateur répond trop grand,
sinon, c'est que le nombre proposé par l'utilisateur est celui choisi par
l'ordinateur : l'utilisateur a alors gagné.
Le but de cet exercice est d'écrire
en procédant par étapes
un programme de
jeu du nombre mystérieux. Dans cet exercice, les étapes sont proposés et chaque
étape complète la précédente.
1. Dans un premier temps, on triche : le nombre mystérieux n'est pas tiré au
hasard : il est xé (par le programmeur) dans une variable. Cela permettra
de faire plus facilement les tests ! Ecrivez le programme qui initialise cette
variable et demande un nombre à l'utilisateur.
2. Indiquez au joueur si le nombre qu'il a proposé est plus petit, plus grand
ou s'il a gagné.
3. Répétez les tours de jeu jusqu'à ce que le joueur ait deviné.
4. Indiquez en combien de tours le jour a deviné. On pourra adresser un
message de félicitations si le joueur a deviné (par exemple) en moins de 8
tours.
5. Maintenant c'est l'ordinateur qui choisit le nombre. En phase de test, vous
pouvez en début de partie faire acher le nombre choisi. Evidemment en
version nale cet achage disparaitra.
Indication : Le chier
fonctions1.inc contient une fonction choix() qui
retourne un nombre compris entre 0 et 100.
6. Bien sûr, d'autres améliorations sont possibles :
Enchaîner les parties : à la n d'une partie, le programme demande à
l'utilisateur s'il souhaite enchaîner une nouvelle partie.
Indroduisez une condition d'arrêt supplémentaire : si au bout d'un certain nombre d'essais (xé par l'utilisateur ou le programme) l'utilisateur
n'a pas trouvé le nombre mystérieux, le programme s'arrête automatiquement.
Ajoutez un message de d'accueil pour souhaiter la bienvenue à l'utilisateur, un message d'adieu. Le programme peut demander au début le
nom de l'utilisateur et le message d'adieu peut ainsi être personnalisé à
l'utilisateur.
Modiez le programme pour qu'il compte le nombre d'essais de l'utilisateur et qu'il ache, à chaque proposition de l'utilisateur, le nombre
d'essais eectués.
17
2.4 Vote
2.4.1 Version 1 : saisie des noms au clavier
Dans une petite commune, les électeurs, lors d'une élection partielle, ont le
choix entre deux candidats, mais peuvent aussi voter pour une personne de leur
choix. On souhaite connaître le nombre et le pourcentage de votes pour les deux
candidats ociels.
Scénario : les électeurs saisissent au clavier (l'anonymat et la validité du vote
sont garantis !), chacun leur tour le nom de la personne pour laquelle ils désirent
voter. A la clôture du bureau, le responsable tape
fin pour terminer la saisie et
acher le résultat (partiel) de l'élection.
1. Ecrivez d'abord un programme qui accepte des noms désignant les élus
potentiels (par exemple,
pierre, marie,. . .) saisis
XXX. La
après chaque saisie : Vous avez voté pour
n de saisie.
fin
au clavier et ache,
chaîne
fin
indique la
ne doit pas être aché comme un vote.
2. Modiez le programme pour que celui-ci connaisse les noms des deux candidats déclarés saisis au clavier et indique :
le nombre de voix obtenu par chacun de ces candidats
lequel de ces deux candidats a obtenu le plus de le plus de voix.
3. Indiquez le pourcentage de voix de chacun des candidats par rapport au
nombre total de votants. Avant de vous lancer dans les modications du
programme, rééchissez aux questions suivantes :
comment s'obtient (se calcule) un pourcentage ?
quelle variable faut-il introduire ?
Que se passe-t-il si personne ne vient voter ?
2.4.2 Version 2 : les noms sont stockés dans un chier
On suppose maintenant que les noms ne sont plus saisis au clavier mais qu'ils
ont été rangés dans un chier au fur et à mesure du vote et qu'un traitement
de ce chier est ensuite fait pour calculer les résultats.
Ecrire un chier texte contenant les votes (1 nom par ligne). Modiez le
programme précédent, pour qu'il lise ce chier et ache les résultats du vote.
Modier le programme pour que le nom du chier texte contenant les votes
soit saisi au clavier et qu'un message d'erreur s'ache si le chier n'est pas
trouvé.
18
Chapitre 3
Fichier texte et algorithmes
sur les chiers
3.1 Notion de chier texte
3.1.1 Dénition
Dénition d'un chier. Un chier est un ensemble d'informations identié
par un nom et enregistré sur un support magnétique. Un chier texte est une
suite de caractères ASCII. Ces caractères sont organisés en lignes. Chaque ligne
est terminée par le caractère
<RETOUR> (facultatif pour la dernière ligne). Les
diérentes lignes ne sont pas nécessairement de même longueur. Historiquement,
une ligne (ou che) d'un chier correspondait à un élément (par exemple, les
ches signalétiques des livres d'une bibliothèque, des caractéristiques d'individus d'une même population,...). La gure 3.1 représente un chier texte.
fin de ligne
fin de fichier
Figure 3.1 schématisation d'un chier
Intérêts des chiers :
stockage sur un support permanent (disque dur, disquette) autorisant l'archivage et non pas en mémoire vive,
19
stockage d'informations nécessaires à plusieurs programmes (cela évite de
devoir maintenir une information commune à plusieurs programmes, cette
idée débouchant sur les systèmes de gestion de bases de données).
La contiguïté est l'ordre implicite des éléments du chier : la correspondance
entre une position et un élément est implicite (on est sur le 3
ème
élément uni-
quement parce que celui-ci a deux prédécesseurs). Les chiers textes standards
ne permettent pas d'accéder directement à une ligne : pour accéder à la i
ème
ème
ligne, il faut parcourir les (i-1)
premières.
3.1.2 Principe d'utilisation des chiers textes
Un chier texte peut être édité et manipulé avec un éditeur de texte. Dans
certains cas, c'est le moyen le plus aisé pour le modier (par exemple, remplacer
une ligne). Dans d'autres cas, un programme eectuera plus aisément la tâche
(par exemple remplacer une chaîne de caractères par une autre pour les lignes
impaires du programme). Il peut être aussi nécessaire d'accéder à un chier par
le biais d'un programme pour, par exemple, accéder à des données ou enregistrer
des résultats.
La manipulation d'un chier texte par un programme nécessite les 3 étapes
suivantes :
1.
Ouverture du chier. Cette étape comprend 2 opérations :
(a) eectuer le lien entre le nom du chier dans le programme) et le nom
physique du chier (nom du chier en mémoire secondaire) : canal
d'entrée / sortie.
(b) indiquer le mode d'utilisation du chier : lecture, écriture ou ajout
de données (en fait, d'autres modes sont possibles).
2.
Traitement des éléments du chier.
Exemple : lecture des lignes,
écriture d'information. Pour un chier séquentiel, l'accès se fait élément
par élément sans possibilité de retour en arrière (si on souhaite revenir en
arrière, il est nécessaire de fermer le chier, puis de le ré-ouvrir et d'avancer
jusqu'à atteindre l'élément désiré). Le caractère de n de chier permet
d'arrêter l'itération.
En général, les algorithmes ont la forme indiquée à la gure 3.2.
ouverture en lecture :
ouverture en écriture
lire fichier : <FICHIER>
traiter ligne
traiter ligne
écrire fichier : print FICHIER...;
Figure 3.2 principe des algorithmes usuels sur les chiers
3.
Fermeture du chier.
En PHP, l'ouverture du chier est eectuée par la fonction
deux arguments. Par exemple :
20
fopen qui possède
$FichPers = fopen("fpers1.txt","r") ;
fopen
handle ) de chier (sauf en cas
false est retourné). Le chier fpers1.txt (qui est dans le répertoire
renvoie un pointeur (ou descripteur ou
d'échec ou
courant) est ouvert en lecture.
Le mode d'utilisation du handle de chier est désigné par le deuxième argu-
fopen :
r (comme dans
ment de
l'exemple ci-dessus) : le chier est ouvert en lecture seule.
Le programme est prêt à lire le premier élément, mais celui-ci n'est pas
encore lu.
w
: ouverture en écriture seule. Si le chier n'existe pas, il est créé (et son
contenu est vide), s'il existe déjà, cette opération le vide de son contenu
(cela permet de réinitialiser un chier).
a
: ouverture en ajout. Si le chier n'existe pas, il est créé. Dans tous les
cas, on est positionné à la n du chier, prêt à écrire un nouvel élément
après le dernier élément.
Exemples d'échec :
tentative d'ouverture en lecture d'un chier qui n'existe pas ou pour lequel
on ne dispose pas des autorisations,
tentative d'ouverture en écriture sur un chier protégé en écriture, à un
répertoire inaccessible.
Aussi, il est judicieux de vérier les valeurs de retour des fonctions
fclose
(cf. exemple ci-dessous). Un appel à
fclose
fopen
et
peut échouer en cas de
disque plein, si le serveur contenant le chier devient inaccessible, etc.
•
la fermeture du chier s'eectue avec
fclose
avec comme argument un
pointeur de chier. Par exemple :
fclose($FichPers) ;
feof
•
test de n de chier :
•
lecture dans un chier. Il existe plusieurs fonctions (pf désigne un pointeur
avec comme argument un pointeur de chier.
de chier) :
fgetc(pf) : lecture d'un caractère
fgets(pf,nbmax) : lecture d'une chaîne (terminée par \n ou la n de
chier) ayant au plus nbmax - 1 caractères.
fgetss(pf,nbmax) : comme fgets mais exclut les balises HTML et
PHP lors de l'achage (mais celles-ci sont comptées pour nbmax).
fread(pf,nbmax)
fscanf(pf,chaine)
file(nomphysiquedufichier) : chaque ligne du chier est placée dans
un élément d'un tableau.
•
écriture dans un chier :
pointé par
pf.
fwrite(pf,chaîne) : écrit chaîne dans le chier
Un troisième argument optionnel indique le nombre de
caractères de la chaîne à écrire.
fputs
est un alias de
• file_exists(nomphysiquedufichier)
true si il existe, false sinon).
• filesize(nomphysiquedufichier)
ment.
21
fwrite
teste si le chier existe (renvoie
donne la taille du chier en argu-
3.2 Algorithmes élémentaires sur les chiers
3.2.1 Lecture d'un chier
Achage des lignes d'un chier
On suppose que le chier existe. Exemple : chier de personnes, chaque ligne
du chier contient le nom d'une personne, son âge et sa taille, ces caractéristiques
étant séparées deux à deux par un espace. Le but du programme est d'acher
chaque ligne, telle qu'elle se présente dans le chier.
Attention :
si le nom de la variable indiquant le nombre de caractères lus dans le
$NbCarMaxLigne)
a la valeur
0
phiée et a donc par défaut la valeur
0),
alors aucun caractère n'est lu à chaque
itération et on boucle.
<?php
$nbcarmaxligne = 1000 ;
$fichpers = fopen("fpers1.txt","r") ;
$num = 0 ;
while (! feof($fichpers)) {
$ligne = fgets($fichpers, $nbcarmaxligne) ;
$num = $num + 1 ;
echo "Ligne numéro $num : $ligne" ;
}
fclose($fichpers) ;
?>
Remarque :
Il est possible d'utiliser une constante :
define (NBCARMAXLIGNE, 1000) ;
...
$ligne = fgets($fichpers, NBCARMAXLIGNE) ;
Pour le chier
fpers1.txt
suivant :
Pierre 1.70 17
Noémie 1.61 25
Julie 1.66 18
Barthélemy 1.79 21
le programme ache :
Ligne
Ligne
Ligne
Ligne
numéro
numéro
numéro
numéro
1
2
3
4
:
:
:
:
fgets (ici,
(par exemple, parce qu'elle a mal été orthogra-
Pierre 1.70 17
Noémie 1.61 25
Julie 1.66 18
Barthélemy 1.79 21
22
\n) est
$ligne.
d'open et close :
Chaque ligne du chier (y compris le caractère
lue une à une lors de
l'itération et est successivement stockée dans
En contrôlant les valeurs de retour
<?php
$nbcarmaxLigne = 1000 ;
$fichpers = fopen("fpers1.txt","r") ;
if (! $fichpers) {
echo "Impossible d'ouvrir fpers1.txt\n" ;
exit ;
}
$num = 0 ;
while (! feof($fichpers)) {
$ligne = fgets($fichpers, $nbcarmaxligne) ;
$num = $num + 1 ;
echo "Ligne numéro $num : $ligne" ;
}
$res = fclose($fichpers) ;
if (! $res) {
echo "Impossible de fermer fpers1.txt\n" ;
}
?>
Achage des caractéristiques des lignes d'un chier
Idem que précédemment, mais on souhaite un achage séparé des caractéristiques de chaque ligne. Pour cela, il est nécessaire de connaître la structure
d'une ligne :
quelles sont les caractéristiques d'une ligne,
comment ces caractéristiques sont-elles séparées
La structure d'une ligne de cet exemple est précisée au paragraphe 3.2.1. Les
explode.
list est utilisé pour aecter en rafale une liste de variables, chaelles correspondant à un élément du tableau renvoyé par explode
diérentes caractéristiques d'une ligne s'obtiennent grâce à la fonction
Le constructeur
cune d'entre
<?php
$nbcarmaxligne = 1000 ;
$fichpers = fopen("fpers1.txt","r") ;
if (! $fichpers) {
echo "Impossible d'ouvrir fpers1.txt\n" ;
exit ;
}
$num = 0 ;
while (! feof($fichpers)) {
$ligne = fgets($fichpers, $nbcarmaxligne) ;
list($nom, $taille, $age) = explode(" ", $ligne) ;
$num = $num + 1 ;
23
}
echo "Ligne numéro $num - Nom : $nom Taille : $taille
Age : $age" ;
$res = fclose($fichpers) ;
if (! $res) {
echo "Impossible de fermer fpers1.txt\n" ;
}
?>
ache :
Ligne
Ligne
Ligne
Ligne
numéro
numéro
numéro
numéro
1
2
3
4
-
Nom
Nom
Nom
Nom
:
:
:
:
Pierre Taille : 1.70 Age : 17
Noémie Taille : 1.61 Age : 25
Julie Taille : 1.66 Age : 18
Barthélemy Taille : 1.79 Age : 21
echo
\n.
Remarquez que le passage à la ligne ne s'eectue pas par le biais du
du programme, mais à cause de la caractéristique
$age
qui contient un
Moyenne des caractéristiques lues dans un chier
Calcul et achage de l'âge moyen et de la taille moyenne des personnes du
chier.
<?php
$nbcarmaxligne = 1000 ;
$fichpers = fopen("fpers1.txt","r") ;
if (! $fichpers) {
echo "Impossible d'ouvrir fpers1.txt\n" ;
exit ;
}
$nbpers = 0 ; $somtaille = 0 ; $somage = 0 ;
while (! feof($fichpers)) {
$ligne = fgets($fichpers, $nbcarmaxligne) ;
$ligne = rtrim($ligne) ;
list($nom, $taille, $age) = explode(" ", $ligne) ;
$nbpers = $nbpers + 1 ;
$somtaille = $somtaille +$taille ;
$somage = $somage + $age ;
}
$res = fclose($fichpers) ;
if (! $res) {
echo "Impossible de fermer fpers1.txt\n" ;
}
$agemoy = $somage / $nbpers ;
$agemoyannees = intval($agemoy) ;
$nbmois = round(($agemoy - $agemoyannees) * 12) ;
24
echo "taille moyenne : ", number_format($somtaille/$nbpers, 2),
" age moyen $agemoyannees et $nbmois mois\n" ;
?>
ache, toujours pour notre chier usuel :
Taille moyenne : 1.69
Age moyen : 20 ans et
3 mois
$age contient la valeur numérique de l'âge,
\n. La somme des âges est cependant correctement calculée
car la chaîne age\n est convertie dans le contexte arithmétique de $somage +=
$age ; en valeur numérique de age.
Remarquez qu'à chaque itération
suivi du caractère
3.2.2 Création et écriture d'un chier
Lecture d'un chier de personnes et création d'un chier contenant les noms
et les tailles des personnes supérieures à une certaine taille.
<?php
require("fonctions1.inc") ;
$nbcarmaxligne = 1000 ;
$fichpers = fopen("fpers1.txt","r") ;
if (! $fichpers) {
echo "Impossible d'ouvrir fpers1.txt\n" ;
exit ;
}
$fichpersout = fopen("fpers2.txt","w") ;
if (! $fichpersout) {
echo "Impossible d'ouvrir fpers2.txt\n" ;
exit ;
}
echo "Taille ? : " ;
$seuiltaille = lire() ;
while (! feof($fichpers)) {
$ligne = fgets($fichpers, $nbcarmaxligne) ;
list($nom, $taille, $age) = explode(" ", $ligne) ;
if ($taille >= $seuiltaille) {
fwrite($fichpersout, "$nom $taille\n") ;
}
}
$res = fclose($fichpers) ;
if (! $res) {
echo "Impossible de fermer fpers1.txt\n" ;
}
$res = fclose($fichpersout) ;
if (! $res) {
echo "Impossible de fermer fpers2.txt\n" ;
}
?>
25
Chapitre 4
TP 2 - Calcul de moyenne de
notes
4.1 Exercice 1 : utilisation de boucles
En utilisant la structure
for ($i = 1; $i <= 1000; $i ++){
...
}
écrire un programme qui ache 1000 fois "Mais non, ce n'est pas une
chanson monotone".
écrire un programme qui ache 1000 fois "X kilomètres à pied, ça use les
souliers" pour X variant de 1 à 1000.
4.2 Exercice 2 : compter les rouges et les verts
On considère disposer d'un chier contenant, pour chaque ligne, le mot rouge ou vert.
rouge
vert
rouge
rouge
vert
rouge
rouge
rouge
vert
vert
vert
rouge
Écrire un programme qui lit ce chier et compte le nombre de rouges et
de verts. Pour cela, on pourra utiliser deux variables
structure
switch
suivante :
26
$rouge
et
$vert
puis la
switch ($motludanslefichier}{
case "rouge":
$rouge ++;
break;
case "vert":
$vert ++;
break;
}
default:
echo "couleur non autorisée\n";
break;
4.3 Exercice 3 : moyenne de notes par personne
On considère des chiers structurés comme le chier
fnotes1.txt (_
est le
caractère souligné) :
sport_math_français_histoire_anglais
paul:12_7_8_3_4
marie:7_2_5_19_11
albert:0_0_0_0_0
jean:15_9_10_7_20
julie:7_18_20_0_20
clara:13_7_15_10_9
La première ligne du chier contient une liste de matières, chaque matière
est séparée par le caractère
puis le caractère
:
_.
Chaque ligne contient le nom d'une personne,
puis une série de notes, les notes étant séparées par l_.
1. Écrivez une procédure qui reçoit en paramètre d'entrée une chaîne de
caractères contenant des nombres séparés par
_ et qui retourne la moyenne
de ces nombres. Écrivez le script php minimal qui teste cette fonction
(indication : le test peut être eectué en utilisant une chaîne comme par
exemple 9_11_8_14).
2. Écrivez un script php achant le nom de chaque personne contenue dans
un chier structuré comme
fnotes1.txt
La première ligne du chier est
donc à ignorer (i.e. à sauter).
3. Écrivez un script php achant pour chaque personne sa moyenne. Pour
fnotes1.txt,
le résultat est :
paul : 6.80
marie : 8.80
albert : 0.00
jean : 12.20
julie : 13.00
clara : 10.80
4. Écrivez une procédure qui ache les éléments (clé et valeur) d'un tableau
dont les clés sont des chaînes de caractères. Écrivez le script php mini-
27
mal qui teste cette fonction. En utilisant la fonction
éléments de
Tableau
asort(Tableau),
les
sont triés suivant l'ordre de leurs valeurs.
5. Modiez le script php écrit à la question 3 pour que celui-ci range la
moyenne de chaque personne dans un tableau dont les clés sont les noms
des personnes.
6. Modiez le script php écrit à la question précédente pour que la première
ligne du chier (i.e. les matières) soit traitée (c'est-à-dire, la liste des matières est achée avant les noms et les moyennes). Plusieurs techniques
sont possibles pour traiter la première ligne. Sur
fnotes1.txt,
ce script
produit :
Les
Cle
Cle
Cle
Cle
Cle
Cle
matières sont : sport math français histoire anglais
: albert - valeur : 0.00
: paul - valeur : 6.80
: marie - valeur : 8.80
: clara - valeur : 10.80
: jean - valeur : 12.20
: julie - valeur : 13.00
Remarques :
On rappelle que pour écrire l'ensemble d'un programme deux démarches
sont possibles :
(a)
démarche ascendante :
soit commencer par écrire et tester les fonc-
tions les plus élémentaires. Ensuite, remonter jusqu'au programme
principal.
(b)
démarche descendante : soit commencer par écrire le programme principal avec une version simpliée des fonctions nécessaires et tester
l'ensemble. Ensuite, descendre jusqu'à l'écriture complète des fonctions élémentaires.
En fait, ces deux démarches sont concomitantes et complémentaires et,
dans la pratique, on passe souvent de l'une à l'autre. Dans les questions
précédentes, vous pouvez distinguer celles relevant d'une démarche ascendante et celle d'une démarche descendante.
28
Chapitre 5
Les tableaux
5.1 Les tableaux simples
Les tableaux permettent un premier niveau de structuration des données en
PHP. Il s'agit de collectionner des éléments qui ont un rapport entre eux, en
utilisant un nom de variable générique.
Par exemple, dans le chier ci-dessous, on décide de stocker les noms des
mois de l'année dans un tableau
$annee[1]
sera
février,
$annee.
Ainsi
$annee[0]
sera
janvier,
etc.
1
<?php
// -------------------- mois.php -------------------// manipulation d'un tableau de mois
5
// création d'un tableau
$annee = array( "janvier", "fevrier", "mars", "avril");
10
15
20
25
// affichage formaté
print_r($annee);
/*Array
(
[0] => janvier
[1] => fevrier
[2] => mars
[3] => avril
)*/
// affichage avec un compteur
for($i = 0; $i < sizeof($annee); $i ++)
echo "le mois " . ($i + 1) . " de l'annee est $annee[$i].\n";
/*le mois 1 de l'annee est janvier.
le mois 2 de l'annee est fevrier.
le mois 3 de l'annee est mars.
le mois 4 de l'annee est avril.
*/
29
30
35
40
45
50
55
60
65
70
75
// affichage avec foreach
foreach($annee as $mois) // pas d'indice
echo "$mois\n";
/*janvier
fevrier
mars
avril
*/
// ajout d'un mois supplémentaire à la fin
array_push($annee, "mai");
$annee[] = "juin";
$annee[sizeof($annee)] = "juillet";
print_r($annee);
/*Array
(
[0] => janvier
[1] => fevrier
[2] => mars
[3] => avril
[4] => mai
[5] => juin
[6] => juillet
)*/
// retrait de la fin
echo "dernière valeur : " . array_pop($annee) . "\n";
/*dernière valeur : juillet*/
print_r($annee);
/*Array
(
[0] => janvier
[1] => fevrier
[2] => mars
[3] => avril
[4] => mai
[5] => juin
)*/
// ajout d'un mois supplémentaire au début
array_unshift($annee, "decembre");
print_r($annee);
/*Array
(
[0] => decembre
[1] => janvier
[2] => fevrier
[3] => mars
[4] => avril
30
80
85
90
95
)*/
[5] => mai
[6] => juin
// retrait du début
echo "première valeur : " . array_shift($annee) . "\n";
// première valeur : decembre
print_r($annee);
/*Array
(
[0] => janvier
[1] => fevrier
[2] => mars
[3] => avril
[4] => mai
[5] => juin
)*/
?>
5.2 Les chaînes de caractères
Les chaînes de caractère peuvent être considérées comme des tableaux de
caractères. Dans l'exemple suivant,
$chaine[$i]
est le caractère de rang
dans la chaîne.
1
<?php
$chaine = "Bonjour à tous !";
5
10
15
20
for($i = 0; $i < strlen($chaine); $i ++)
echo "caractère $i : $chaine[$i]\n";
/*
caractère
caractère
caractère
caractère
caractère
caractère
caractère
caractère
caractère
caractère
caractère
caractère
caractère
0 : B
1 : o
2 : n
3 : j
4 : o
5 : u
6 : r
7 :
8 : à
9 :
10 : t
11 : o
12 : u
31
$i
25
caractère 13 : s
caractère 14 :
caractère 15 : !
*/
?>
On peut créer un tableau en découpant une chaîne de caractère suivant un
délimiteur grâce à l'instruction
explode
:
<?php
1
$mots = explode(" ","Bonjour à tous !");
5
10
15
print_r($mots);
/*
Array
(
[0] => Bonjour
[1] => à
[2] => tous
[3] => !
)
*/
?>
5.3 Les tableaux associatifs
Jusqu'ici, nous avons vu des tableaux où les valeurs correspondent à des
indices entiers, appelés également des
clés.
Les tableaux associatifs permettent
d'associer une clé de type chaîne de caractère à une valeur.
Les usages sont multiples : associer sa traduction en Anglais à un mot français, liste de caractéristiques d'un ensemble de personnes, indiquer pour chaque
immatriculation le nom du propriétaire, . . .
Dans l'exemple ci-dessous, on associe à un nom d'artiste son score de vente.
1
<?php
5
// définition du tableau de classement, qui associe un artiste à son score de vente
$classement = array("georges" => 1000,
"jacques" => 500,
"lucienne" => 750,
"edith" => 800);
10
// affichage du tableau
print_r($classement);
15
/*-------------------------------------------Résultat :
Array
(
32
20
)
*/
[georges] => 1000
[jacques] => 500
[lucienne] => 750
[edith] => 800
?>
1
<?php
// ----------------------------------- exo2.php -------------------------------------// parcours de tableau
5
require("definition.inc");
10
15
// affichage du tableau
foreach($classement as $artiste => $score)
echo "l'artiste $artiste a un score de $score\n";
echo "\n";
// affichage avec un while
reset($classement);
while(list($artiste, $score) = each($classement))
echo "l'artiste $artiste a un score de $score\n";
echo "\n";
20
25
30
// affichage avec un itérateur
if(sizeof($classement)){
end($classement); $fin = key($classement);
reset($classement);
while(true){
echo "l'artiste " . key($classement);
echo " a un score de " . current($classement) . "\n";
if(key($classement) == $fin) break;
next($classement);
}
}
exit(0);
35
40
/*-------------------------------------------Résultat :
l'artiste georges a un score de 1000
l'artiste jacques a un score de 500
l'artiste lucienne a un score de 750
l'artiste edith a un score de 800
*/
33
?>
5.4 Fonctions pour les tableaux
Nom
Signication
array_pop($variable) ;
supprime le dernier élément d'un tableau tout
array_push($variable, $val) ;
ajoute une valeur à la n un tableau.
array_unshift($variable, $val) ;
ajoute une valeur au début d'un tableau.
arsort($tableau)
trie
en le retournant.
un
tableau
dans
un
ordre
inverse
en
conservant le couple clé/valeur.
asort($variable)
trie les valeurs d'un tableau en conservant le
valeur = current($variable)
retourne l'élément courant désigné par le poin-
couple clé/valeur.
teur d'un tableau.
$tableau = each($variable)
retourne chacune des paires clé/valeur dans un
tableau à quatre éléments (0 => clé, 1 => 'valeur', key => clé, value => 'valeur') et avance
le pointeur de tableau.
end($variable) ;
place le pointeur sur le dernier élément du tableau.
true | false = in_array($valeur,
recherche la valeur spéciée dans un tableau.
$tableau)
clé
|
false
=
ar-
retourne la clé associée en cas de réussite de
ray_search($valeur, $tableau)
la recherche de la valeur spéciée.
clé = key($variable)
retourne la clé en cours dans le tableau.
nombre = krsort($variable)
trie les clés d'un tableau dans l'ordre inverse
en conservant les paires clé/valeur.
nombre = ksort($tableau)
trie les clés d'un tableau en conservant les
paires clé/valeur.
list($variable , ..., $variableN)
aecte une série de variables en une seule opération.
valeur | false = next($variable)
avance le pointeur au prochain élément et retourne la valeur correspondante.
valeur | false = prev($variable)
déplace le pointeur sur l'élément précédent et
valeur = reset($variable)
déplace le pointeur sur le premier élément d'un
nombre = sizeof($variable)
retourne le nombre d'éléments d'un tableau.
retourne la valeur.
tableau et retourne sa valeur.
34
Chapitre 6
TD 3
6.1 Exercice
Il s'agit de lire un chier contenant, sur chaque ligne, une association <artiste> <score>. Ecrire un programme qui charge le contenu d'un tel chier dans
un tableau associatif.
Indications : pour découper la ligne en artiste et score, utilisez la fonction
explode(" ", $ligne)
informations à l'aide de
qui renvoie un tableau dont vous pouvez récupérer les
list($cle, $valeur).
6.1.1 Manipulations
En le parcourant, calculer puis acher la taille du tableau. Chercher dans le
tableau la personne qui a le meilleur score. Chercher la personne qui a un score
de 750.
6.2 Exercice
Réaliser un programme qui compte les occurrences des lettres de l'alphabet
contenues dans ce chier. Utiliser un tableau de 26 valeurs, indexées de 0 à 25.
ord($chaine) renvoie le code ASCII de la première
ord($char) - ord(A) est l'index de $char.
od -c <fichier> ache le contenu d'un chier en mode
Indications : la fonction
lettre (voir table 6.1). Ainsi,
La commande Linux
caractère.
35
code
0
1
2
3
4
5
6
7
8
9
0
NUL
SOH
STX
ETX
EOT
ENQ
ACK
BEL
BS
HT
10
LF
VT
NP
CR
SO
SI
DLE
DC1
DC2
DC3
20
DC4
NAK
SYN
ETB
CAN
EM
SUB
ESC
FS
GS
30
RS
US
SP
!
"
#
$
%
&
'
40
(
)
*
+
,
-
.
/
0
1
50
2
3
4
5
6
7
8
9
:
;
60
<
=
>
?
@
A
B
C
D
E
70
F
G
H
I
J
K
L
M
N
O
80
P
Q
R
S
T
U
V
W
X
Y
90
Z
[
]
∧
_
`
a
b
c
100
d
e
f
g
h
i
j
k
l
m
110
n
o
p
q
r
s
t
u
v
w
120
x
y
z
{
|
}
DEL
Table 6.1 Table de caractères ASCII - 7 bits
36
nom
décimal
clavier
terme anglais
NULL
0
Ctrl+@
Null
terme français
Nul
SOH
1
Ctrl+A
Start of heading
Début d'entête
Début de texte
STX
2
Ctrl+B
Start of text
ETX
3
Ctrl+C
End of text
Fin de texte
EOT
4
Ctrl+D
End of transmit
Fin de communication
ENQ
5
Ctrl+E
Enquiry
Demande
ACK
6
Ctrl+F
Acknowledge
Accusé de réception
BELL
7
Ctrl+G
Bell
Sonnerie
BS
8
Ctrl+H
Backspace
Retour arrière
Tabulation horizontale
HT
9
Ctrl+I
Horizontal tab
LF
10
Ctrl+J
Line feed
Interligne
VT
11
Ctrl+K
Vertical tab
Tabulation verticale
FF
12
Ctrl+L
Form feed
Page suivante
CR
13
Ctrl+M
Carriage return
Retour en début de ligne
SO
14
Ctrl+N
Shitf out
Hors code
SI
15
Ctrl+O
Shift in
En code
DLE
16
Ctrl+P
Data line escape
Echappement en transmission
DC1
17
Ctrl+Q
Device control 1
Commande auxiliaire 1
DC2
18
Ctrl+R
Device control 2
Commande auxiliaire 2
DC3
19
Ctrl+S
Device control 3
Commande auxiliaire 3
DC4
20
Ctrl+T
Device control 4
Commande auxiliaire 4
NAK
21
Ctrl+U
Negative acknowledge
Accusé de réception négatif
SYN
22
Ctrl+V
Synchronous idle
Synchronisation
ETB
23
Ctrl+W
End of transmit block
Fin de bloc transmis
CAN
24
Ctrl+X
Cancel
Annulation
EM
25
Ctrl+Y
End of medium
Fin de support
SUB
26
Ctrl+Z
Substitute
Remplacement
ESC
27
Ctrl+[
Escape
Echappement
FS
28
Ctrl+
File separator
Séparateur de chier
GS
29
Ctrl+]
Group separator
Séparateur de groupe
RS
30
Ctrl+∧
Record separator
Séparateur d'enregistrement
US
31
Ctrl+_
Unit separator
Séparateur d'unité
SP
32
Barre
Space
Espacement
DEL
127
Del
Delete
Eacement
Table 6.2 Caractères ASCII non imprimables
37
Chapitre 7
TP 3
7.1 Exercice
Lire dans un chier une liste d'association <artiste> <score>. Il peut y avoir
plusieurs lignes pour un même artiste, auquel cas il faut additionner le score lu
au score total. Acher le classement par ordre d'artiste puis par meilleur score.
Indications : la partie relative au chargement a été traitée en TD. Quand on
$artiste => $score, il faut tester si elle est déjà répertoisset().
connaît l'assocation
riée, à l'aide de
7.2 Exercice
Pour expérimenter l'emploi d'un tableau pour gérer une pile (resp. une
le), écrire un programme qui charge un chier dans un tableau à l'aide de
array_push
ou de la notation
$tableau[] = $ligne puis ache les lignes du
array_pop (resp. array_unshift pour ob-
tableau à l'aide d'une succession de
tenir le comportement d'une le.
7.3 Exercice
7.3.1 Version élémentaire
Réaliser un programme qui lit un chier HTML (utiliser le chier fourni,
test.html,
qui reprend une structure simple de tableau) et stocke toutes les
balises lues dans un tableau. On supposera qu'il n'y a qu'une seule balise par
ligne.
Indication : utiliser une expression régulière avec parenthèse capturante pour
preg_match("/<(.*)>/", $ligne, $match) teste
$ligne et met dans $match[1] le contenu matché par
($match[0] contient l'expression régulière complète).
lire la balise. Par exemple
s'il y a une balise dans
les parenthèses
7.3.2 Vérication des balises
Réaliser un programme qui vérie que chaque balise fermante correspond
bien à la dernière balise ouvrante et indique le numéro de ligne et le type d'erreur.
38
Indication : désormais, il ne faut pas stocker toutes les balises dans le tableau,
seulement les ouvrantes. Quand une fermante est lue, on la compare avec le
résultat d'un
array_pop().
7.3.3 Vérication avancée
Améliorer le programme précédent pour qu'il fonctionne avec plusieurs balises par ligne.
preg_match_all("/<(.*)>/U", $ligne,
$match[1] la liste de toutes les balises de la ligne.
Indication : utiliser la fonction
$match)
qui aecte dans
L'option U de l'expression régulière permet de neutraliser le mode glouton qui
cherche à faire correspondre la plus grande chaîne possible. Ici, ce sera la plus
petite.
39
Chapitre 8
Les fonctions
Les fonctions permettent de regrouper un ensemble d'instructions complexes.
L'appel de la fonction remplacera donc cette suite de commandes. Elles répondent à des besoins de structuration du programme, an que sa réalisation
procède par étapes, et proposent au programmeur des possibilités de généricité.
8.1 Exemples
Nous détaillons la réalisation de la fonction
lire,
que nous utilisons pour
récupérer une chaîne saisie au clavier par l'utilisateur. Le programme ci-dessous
lit les prénom et nom puis les ache.
1
<?php
//---------------------------- cours1.php ------------------define(MAXLIGNE, 1000);
5
// lecture du prénom
10
echo "saisissez votre prénom : ";
$fich = fopen("/dev/tty","r");
// ouverture entrée standard
if (!$fich) die("erreur d'ouverture de l'entrée standard");
$prenom = rtrim(fgets($fich, MAXLIGNE)); // lecture d'une ligne
fclose($fich) or die("erreur de fermeture du fichier"); // fermeture
// lecture du nom
15
20
echo "saisissez votre nom : ";
$fich = fopen("/dev/tty","r");
// ouverture entrée standard
if (!$fich) die("erreur d'ouverture de l'entrée standard");
$nom = rtrim(fgets($fich, MAXLIGNE)); // lecture d'une ligne
fclose($fich) or die("erreur de fermeture du fichier"); // fermeture
// affichage
echo "Bonjour, $prenom $nom\n";
40
25
?>
Une fonction est dénie par son nom, introduit à l'aide du mot clé
function,
et par une liste d'arguments. Elle dénit un bloc d'instruction, à la n duquel
une valeur est eventuellement retournée, qui peut être utilisée par l'instruction
qui a appelé la fonction. Une fonction peut retourner tout type de valeur géré
par PHP : booléen (true ou
false),
numérique, chaîne de caractères, tableau,
identiant de chier, etc.
Dans l'exemple précédent, on remarque qu'on refait quasiment deux fois la
même chose. La version ci-dessous est mieux structurée, et sa forme générale
(section principale et fonction principale) sera réutilisée dans les programmes
futurs.
1
<?php
//---------------------------- cours2.php ------------------define(MAXLIGNE, 1000);
5
// lecture d'une chaîne
function lirechaine(){
$fich = fopen("/dev/tty","r");
// ouverture entrée standard
if (!$fich) die("erreur d'ouverture de l'entrée standard");
$chaine = rtrim(fgets($fich, MAXLIGNE)); // lecture d'une ligne
fclose($fich) or die("erreur de fermeture du fichier"); // fermeture
return $chaine;
}
10
15
20
25
// fonction principale
function main(){
echo "saisissez votre prénom : ";
$prenom = lirechaine();
echo "saisissez votre nom : ";
$nom = lirechaine();
echo "Bonjour, $prenom $nom\n";
}
// section principale
main();
?>
Les fonctions utilisées ici ne prennent pas d'argument. La version ci-dessous
est plus générique car elle permet de lire dans n'importe quel chier.
1
5
<?php
//---------------------------- cours3.php ------------------define(MAXLIGNE, 1000);
define(CLAVIER, "/dev/tty");
// lecture d'une chaîne dans le fichier de nom $nomfich
function lirechaine($nomfich){
$fich = fopen($nomfich ,"r");
// ouverture entrée standard
41
10
}
15
20
25
if (!$fich) die("erreur d'ouverture de $nomfich");
$chaine = rtrim(fgets($fich, MAXLIGNE));
// lecture d'une ligne
fclose($fich) or die("erreur de fermeture de $nomfich"); // fermeture
return $chaine;
// fonction principale
function main($nomfich){
echo "saisissez votre prénom : ";
$prenom = lirechaine($nomfich);
echo "saisissez votre nom : ";
$nom = lirechaine($nomfich);
echo "Bonjour, $prenom $nom\n";
}
// section principale
main(CLAVIER);
main("test.txt");
?>
8.2 Portée des variables
Les variables utilisées n'ont d'existence que dans la fonction. Cela semble
naturel pour les paramètres, mais c'est valable pour toute variable qui n'est
pas déclarée à l'aide du mot clé
$chaine
global.
Dans l'exemple ci-dessous, la variable
lirechaine ce
lirechaine2, il
est déclarée globale, ce qui n'empêche pas que dans
soit une autre variable du même nom qui soit utilisée. Dans
est rappelé que
$chaine
est globale, son aectation est donc conservée dans la
fonction appelante.
1
5
10
15
<?php
//---------------------------- cours4.php ------------------define(MAXLIGNE, 1000);
define(CLAVIER, "/dev/tty");
// lecture d'une chaîne dans le fichier de nom $nomfich
function lirechaine($nomfich){
$fich = fopen($nomfich ,"r");
// ouverture entrée standard
if (!$fich) die("erreur d'ouverture de $nomfich");
$chaine = rtrim(fgets($fich, MAXLIGNE));
// lecture d'une ligne
fclose($fich) or die("erreur de fermeture de $nomfich"); // fermeture
return $chaine;
}
// lecture d'une chaîne avec affectation de variable globale
function lirechaine2($nomfich){
$fich = fopen($nomfich ,"r");
// ouverture entrée standard
if (!$fich) die("erreur d'ouverture de $nomfich");
global $chaine;
42
20
}
25
30
35
$chaine = rtrim(fgets($fich, MAXLIGNE));
// lecture d'une ligne
fclose($fich) or die("erreur de fermeture de $nomfich"); // fermeture
return $chaine;
// fonction principale
function main(){
global $chaine;
$chaine = "toto";
echo "$chaine\n";
echo lirechaine(CLAVIER) . " $chaine\n";
echo lirechaine2(CLAVIER). " $chaine\n";
}
// section principale
main();
40
/*
toto
titi
titi toto
tata
tata tata
*/
45
?>
// écho saisie clavier
// écho saisie clavier
43
8.3 Génie logiciel
Un programme est nalement une suite d'instructions élémentaires qu'il est
illusoire de vouloir écrire directement. Il faut procéder par analyse descendante,
qui dissèque progressivement toutes les étapes à réaliser, en allant des plus complexes aux plus simples. Une fois cette analyse réalisée à la main, éventuellement
à l'aide d'UML, on peut passer à la phase d'écriture du code PHP, en utilisant
cette fois-ci une analyse montante : du plus élémentaire au plus complexe, en
écrivant une fonction pour chaque étape.
Lors de la conception de programmes, on veillera à respecter quelques règles :
utiliser un minimum de variables globales. On se retreindra pour cela aux
variables fournies par le navigateur (utiliser
phpinfo()),
en considérant
que le script entier est en fait un appel de fonction avec ses paramètres ;
une fonction doit faire un minimum d'eet de bord. Par exemple, on évitera systématiquement les achages, en choisissant plutôt de renvoyer une
chaîne de caractères qui sera achée par l'instruction appelante.
Cette technique permet de séparer le fond (les calculs menés par les fonctions
PHP) et la forme, gérée par le HTML, dans lequel on fera appel aux fonctions à
l'aide d'échappements locaux de la forme
<?php echo fonction(...);?>.
En
eet, lors de la production d'un site complexe, ce ne seront pas forcément les
mêmes personnes qui écriront le HTML et le PHP. Le chier HTML doit donc
contenir un minimum de PHP et vice-versa.
Le script général
page.php sera chargé par le navigateur, et sa section prin-
cipale contiendra uniquement une inclusion du chier HTML. Il doit donc être
écrit de façon à être parfaitement inactif, le HTML se chargeant de déclencher
tous les achages.
<?php
//------------------- page.php ------------------//------------------- fonctions utilitaires ------function fonction1(...){
...
return ...
}
function fonction2(...){
...
return ...
}
//------------------- section principale ---------include(``page.html'');
?>
<!------------------- page.html ------------------->
<html>
44
<head>
<title>....</title>
</head>
<body>
<table>
<tr>
<td>
<?php echo fonction1(...);?>
</td>
<td>
<?php echo fonction2(...);?>
</td>
</tr>
</table>
</body>
</html>
8.4 Récursivité
Lorsque cela est plus naturel, on pourra écrire une fonction qui s'appelle
elle-même. Par exemple, pour calculer la somme des éléments d'un tableau, on
pourra avoir les deux visions possibles :
itérative : parcourir tout le tableau à l'aide d'un
variable
$somme
foreach qui ajoute à une
$somme ;
chaque élément du tableau et renvoyer
récursive : considérer que la somme d'un tableau, c'est celle de son premier
élément et du reste du tableau auquel on a retiré ce premier élément.
1
<?php
//---------------------------- cours5.php -------------------
5
10
15
20
// calcul de la somme des éléments d'un tableau
// version itérative
function sommeiterative($tab){
$somme = 0;
foreach($tab as $val)
$somme += $val;
return $somme;
}
// calcul de la somme des éléments d'un tableau
// version récursive
function sommerecursive($tab){
if(!sizeof($tab))
return 0;
$premier = array_shift($tab);
return $premier + sommerecursive($tab);
}
45
25
30
// fonction principale
function main(){
$tab = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
echo "somme iterative = " . sommeiterative($tab) . "\n";
echo "somme récursive = " . sommerecursive($tab) . "\n";
}
// section principale
main();
?>
Si la forme récursive est plus séduisante intellectuellement, elle n'est pas
très ecace d'un point de vue informatique. Dans l'exemple précédent, PHP
devra conserver autant de copies diérentes du tableau qu'il contient d'éléments.
Malgré cela, cette forme sera utilisée lorsque la forme itérative est dicile à
concevoir.
8.5 Passage par référence
Nous avons vu que les fonctions que nous écrivons ne doivent pas faire d'eet
de bord. Cela dans le but de mieux contrôler l'endroit où ces eets sont réalisés,
en général dans le code HTML. Nous avons cité le cas des achages, pour
lesquels on conseille de renvoyer le résultat à acher. C'est la fonction appelante
qui se charge de l'eet de bord.
Un eet de bord important consiste en l'aection d'une valeur à une variable
globale. Si de telles instructions sont écrites, il devient dicile de retrouver les
causes d'une erreur qui mettent en cause cette variable. Un simple renommage
de la variable devient impossible. D'une façon générale, on s'eorcera de ne
travailler que sur les variables locales de la fonction.
Comment alors modier ces variables pour que les fonctions ne se contentent
pas de renvoyer un résultat, mais puissent également modier leurs paramètres ?
Si on ne le précise pas, la variable qui représente le paramètre est une copie de
l'argument de la fonction. La fonction modie cette copie autant qu'elle le veut,
mais une fois son action terminée, ces modications ne sont pas répercutées sur
l'original.
Il faut préxer le nom d'un paramètre de fonction avec le symbole & (éperluette ou et-commercial). Dans ce cas, PHP comprend qu'il ne doit pas recopier
l'argument correspondant, mais utiliser le paramètre comme une
référence
de
l'argument, c'est à dire un autre nom de variable que celui utilisé lors de l'appel.
Il ne s'agit plus d'une recopie du contenu de la variable argument, mais d'une
copie de son mode d'accès, sa référence. Ainsi, toute modication de ce paramètre dans la fonction aecte nécessairement la variable argument, car PHP
utilise deux noms diérents pour accéder à la même chose.
1
<?php
//------------------------------ cours1.php -------------
46
5
10
15
20
25
30
35
40
45
50
// ajoute $element dans $tableau, passage par valeur
function ajoute($tableau, $element){
$tableau[] = $element;
echo "dans ajoute : tableau = ";
print_r($tableau);
}
// ajoute $element dans $tableau, passage par référence
function ajoute_reference(&$tableau, $element){
$tableau[] = $element;
echo "dans ajoute_reference : tableau = ";
print_r($tableau);
}
function main(){
$annee = array("janvier", "fevrier", "mars", "avril");
ajoute($annee, "mai");
echo "dans main : annee = ";
print_r($annee);
ajoute_reference($annee, "mai");
echo "dans main : annee = ";
print_r($annee);
}
main();
/*
dans ajoute : tableau = Array
(
[0] => janvier
[1] => fevrier
[2] => mars
[3] => avril
[4] => mai
)
dans main : annee = Array
(
[0] => janvier
[1] => fevrier
[2] => mars
[3] => avril
)
dans ajoute_reference : tableau = Array
(
[0] => janvier
[1] => fevrier
[2] => mars
[3] => avril
[4] => mai
)
47
55
60
65
dans main : annee = Array
(
[0] => janvier
[1] => fevrier
[2] => mars
[3] => avril
[4] => mai
)
*/
?>
48
Chapitre 9
TD 4
9.1 Exercice
Ecrire des fonctions élémentaires qui chargent un chier d'associations :
ouverture d'un chier et retour de son descripteur ;
lecture d'une ligne et retour de la chaîne correspondante ;
fermeture d'un chier ;
chargement d'un chier et retour du tableau correspondant ;
9.2 Exercice
Ecrire une série de fonctions qui achent les cellules d'un tableau :
constitution de la chaîne d'achage d'une section
constitution de la chaîne d'achage d'une section
td ;
tr ;
constitution de la chaîne complète d'achage d'un tableau, à l'aide d'un
parcours séquenciel ;
idem avec un parcours récursif du tableau.
49
Chapitre 10
TP 4
10.1 Exercice
Un chier
musiciens.txt
contient une liste de musiciens, caractérisés par
leur identiant et nom. Dans un chier
exo1.php,
écrire une fonction qui af-
che un tableau HTML avec deux colonnes. Cette fonction sera appelée par la
fonction principale
main.
Indications : on pourra procéder de deux manières diérentes. Soit charger
entièrement le chier dans un tableau PHP puis créer le tableau HTML, soit
lire le chier ligne par ligne et écrire le tableau HTML en une fois. La première
solution a l'intérêt d'utiliser des fonctions génériques mais le défaut de requérir
l'utilisation d'un tableau intermédiaire. La seconde est donc plus ecace.
10.1.1 Exercice
Créer un chier
biblio.php
qui regroupe les fonctions de la bibliothèque
chiers et tableaux.
10.2 Exercice
Aménager le programme précédent pour séparer la forme et le fond et le
visualiser dans un navigateur. Pour cela, copier
un chier
exo2.html
exo1.php en exo2.php et écrire
qui sera inclus dans le chier PHP et remplace l'appel
principal. Le chier de bibliothèque sera également utilisé.
10.3 Exercice
instruments.txt contient une liste de d'instruments.
affectations.txt contient une liste d'associations musi-
Un deuxième chier
Un dernier chier
cien/instrument. Acher un tableau HTML récapitulatif de l'aectation de
chaque personne.
Indications : réaliser une fonction
jointure,
qui prend en argument un ta-
bleau gauche, un tableau milieu et un tableau droit puis construit un tableau
correspondant à la jointure entre ces trois tables.
50
Chapitre 11
Programmation objet
11.1 Introduction
Les objets permettent de manipuler des modèles informatiques composés,
représentatifs d'une entité imaginaire. Il s'agit d'une extension du principe de
variable, qui permet de regrouper dans une structure autonome des variables et
leur traitement.
Jusqu'ici nous avons utilisé des variables de diérents types : numériques,
mySQL.
echo ou
chaînes de caractères, tableaux, identiants de chiers ou de connection
Cela nous a semblé parfaitement naturel d'utiliser une même méthode
print_r
pour acher ces variables, indépendamment de leur type.
Pourtant, à l'aide de chaque variable, nous avons représenté notre conception
d'un objet du monde. Par exemple, une seule variable entière
$idclient
nous
permettait de qualier un client, et d'accéder à ses attributs (prénom, nom),
selon que ces valeurs étaient issues d'un formulaire ou d'une base de données.
Nous pourrions utiliser des variables de type client, et des méthodes sur ces
clients, comme l'achage dans une page HTML ou l'accès à une base de données.
La conception objet permet de dénir de nouveaux types complexes, voire
de les composer entre eux. Pour représenter la classe des clients, dont chaque
entité est dénie par un identiant, un prénom et un nom, on utilise la syntaxe
suivante :
/// définition de la classe des clients
class Client{
/// identifiant du client dans la base de données
public $id = 0;
/// M. ou Mme
public $qualite = "";
/// prénom
public $prenom = "";
/// nom
public $nom = "";
/// constructeur de l'objet
public function __construct($id, $qualite, $prenom, $nom){
$this->id = $id;
51
$this->qualite = $qualite;
$this->prenom = $prenom;
$this->nom = $nom;
}
/// fonction d'affichage
public function affiche(){
return "$this->qualite $this->prenom $this->nom";
}
}
// fin de la classe
Les attributs (ou champs) de la classe sont déclarés avec les mot clés
private, protected.
public,
Il est conseillé d'indiquer la valeur par défaut du champ,
ce qui permet d'en identier le type. Le constructeur (la fonction
__construct))
crée un object (il instancie une variable du type de cet objet) et aecte la valeur
de chaque attribut à l'aide de la variable
$this
qui représente l'objet courant.
La èche permet d'accéder aux champs ou aux méthodes de l'objet.
Il sera alors possible de créer un nouvel objet à l'aide de l'opérateur
new,
puis de l'acher :
$client1 = new Client(1, "M.", "Jean", "Dupont");
$client2 = new Client(2, "Mme", "Jeanne", "Duponne");
echo $client1->affiche() . " est marie a " . $client2->affiche() . "\n";
On peut également accéder à tout composant de l'objet, mais c'est sâle.
$client1->prenom = "Paule"; // accès en écriture du prénom
// accès en lecture
echo $client1->qualite . " " . $client1->prenom . " " . $client1->nom .
" est marie a " . $client2->affiche() . "\n";
11.2 Conception orientée objet
Les avantages de la conception orientée objet sont multiples, dont le premier
est la modularité. Une classe est une entité autonome qui contient à la fois des
données et l'interface d'accès à ces données : c'est le concept d'encapsulation.
Cette méthode permet de bénécier des avantages liés à l'utilisation des fonctions, mais également de les regrouper dans une structure unique, qui contient
toute la sémantique de l'objet à représenter.
Plus précisément, chaque élément de classe (attribut, méthode) possède un
mode d'accès :
public : l'accès à l'élément est libre ;
private : l'accès ne peut se faire que par une méthode de la classe. Il faut
donc concevoir une interface si l'on veut accéder d'autre part.
protected : intermédiaire entre public et privé, accès autorisé aux classes
dérivées (cf. cours suivant).
52
On déclarera en général les attributs selon ce mode et on créera une interface
pour y accéder, c'est-à-dire des méthodes publiques de lecture et d'écriture. Cela
permet de séparer le stockage des données dans l'objet de son mode d'accès pour
l'extérieur. Si le mode de stockage est amené à évoluer, seules les méthodes de
la classe qui font un accès direct aux attributs auront besoin d'être mises à jour.
Les autres morceaux de code utilisant la classe se seront pas modiés.
Reprenons l'exemple précédent de notre classe client :
Chaque attribut a été doté d'un accesseur en lecture et d'un accesseur en
écriture qui constituent l'interface de la classe. Si cela semble fastidieux, on peut
utiliser le canevas générique suivant :
/// accesseur lecture
public function get(){
return $this->;
}
/// accesseur écriture
public function set($){
$this-> = ;
}
Modions maintenant la structure de la classe, en remplaçant le prénom par
un tableau de chaînes de caractères, pour gérer des prénoms multiples :
class Client{
/// prénom
private $prenom = array();
/// constructeur de l'objet
public function __construct($id, $qualite, $prenom, $nom){
$this->prenom = array(0 => $prenom);
}
/// accesseur lecture
public function getPrenom(){
$return = "";
foreach ($this->prenom as $prenom)
$return .= "$prenom ";
return $return;
}
/// accesseur écriture
public function setPrenom($prenom){
$this->prenom = array($prenom);
}
/// ajouter un prénom
public function pushPrenom($prenom){
53
}
$this->prenom[] = $prenom;
/// retirer un prénom
public function popPrenom(){
return array_pop($this->prenom);
}
}
// fin de la classe
$client1 = new Client(1,
$client2 = new Client(2,
echo $client1->affiche()
/*
M. Jean Dupont est marie
*/
"M.", "Jean", "Dupont");
"Mme", "Jeanne", "Duponne");
. " est marie a " . $client2->affiche() . "\n";
a Mme Jeanne Duponne
$client1->setPrenom("Paule"); // accès en écriture du prénom
$client1->pushPrenom("Jean");
$client1->pushPrenom("Marie");
// accès en lecture
echo $client1->affiche() . " est marie a " . $client2->affiche() . "\n";
/*
M. Paule Jean Marie Dupont est marie a Mme Jeanne Duponne
*/
$client1->popPrenom();
echo $client1->affiche() . " est marie a " . $client2->affiche() . "\n";
/*
M. Paule Jean Dupont est marie a Mme Jeanne Duponne
*/
?>
On constate l'intérêt de l'encapsulation : le code qui utilisait la classe n'a
pas à être modié, elle continue de fonctionner de façon autonome, sous la
responsabilité de son programmeur.
La conception objet permet également de mettre en ÷uvre la généricité des
traitements. Pour reprendre l'exemple d'echo ou
print_r,
il est possible d'uti-
liser un même nom de méthode dans diérentes classes pour désigner une opération équivalente, comme l'achage ou l'écriture de la structure dans une base
de données. Seule l'implémentation dans la classe sera particulière. Par exemple,
outre le constructeur, on trouvera souvent dans les classes des méthodes pour
acher l'objet, l'enregistrer dans la base de données, y ajouter ou retirer un
élément par
push
et
pop.
Enn, le génie logiciel fournit de nombreuses méthodes automatiques de
conception et de modélisation objet, comme l'utilisation de diagrammes UML.
Pour débuter, nous essayerons simplement de respecter les conseils suivants :
chaque concept manipulé par un programme doit être traduit par une
classe. Cela ne concerne pas les variables simples qui stockent un résultat
54
temporaire, eectuent un petit calcul, servent d'itération dans les boucles,
etc.
commencer la rédaction de la classe par la méthode qui permet d'acher
l'objet. Cela permet de faire le point sur les attributs ;
rédiger ensuite le constructeur, qui permet d'initialiser l'objet.
rédiger l'interface : accesseurs en lecture
get_
et écriture
set_
11.3 Passage d'objet
Il est possible de passer un objet d'un script à l'autre à l'aide de la fonction
serialize
qui transforme l'objet en une chaîne de caractère qui contient tous
ses attributs.
unserialize eectue l'opération inverse. Il faut néanmoins traiter
la chaîne de caractère pour dé-quoter les guillemets :
$chclient = $methode["client"];
$chclient = str_replace('\\"', '"', $chclient);
$client = unserialize($chclient);
On pourra alors appeler une page PHP avec par exemple
header("location:index.php?client=" . serialize($client))
ou mettre
cette chaîne dans un champ caché, même si ce n'est pas le procédé le plus discret.
11.4 Documentation
Il existe plusieurs solutions de documentation automatique de code. Nous
présentons ici Doxygen (http://www.doxygen.org/), qui s'installe avec les paquets
doxygen
et
doxygen-gui.
L'utilitaire à lancer est
doxywizard.
Doxygen est très simple d'emploi :
1. conguration : l'assistant est susant pour indiquer le nom du projet, sa
version et le répertoire de destination pour la documentation ;
2. en conguration expert, choisir le Français pour la langue et dans l'onglet
input, choisir les chiers à documenter avec le premier bouton de sélection ;
3. choisir le répertoire de travail, c'est-à-dire où devront être stockés les chiers de conguration ;
4. sauvegarder la conguration ;
5. lancer le traitement ;
6. visualiser le HTML ;
7. compiler le latex avec
pdflatex refman.tex (plusieurs compilations sont
nécessaires pour résoudre les problèmes de lien).
55
Chapitre 12
TD 5
12.1 Exercice
Munissez la classe des clients de deux méthodes :
12.1.1 enregistre
Cette méthode enregistre le contenu de l'objet dans un chier
''client-$this->id.txt"
sous la forme :
id=1
qualite=M.
prenom=Jean
nom=Dupont
12.1.2 lit
Cette méthode lit les champs de l'objet dans le chier
56
''client-$this->id.txt".
Chapitre 13
Héritage
En programmation objet, l'héritage répond au besoin de gérer des objets
ayant des propriétés similaires.
Comparons les solutions suivantes pour diérencier les hommes des femmes :
class People{
private $id;
private $nom;
private $prenom;
private $type;
public __construct($id, $nom, $prenom, $type){
$this->id = id$;
$this->nom = $nom;
$this->prenom = $prenom;
$this->type = $type;
}
public getType(){
return $this->type;
}
}
public viewHTML(){
switch($this->type){
case PEOPLE_WOMAN :
return "Mme $this->prenom $this->nom";
case PEOPLE_MAN :
return "M. $this->prenom $this->nom";
}
}
La solution suivante utilise l'héritage, en dénissant une classe
ne peut être instanciée) People et deux classes
dérivées
abstraite
(qui
PeopleWoman et Peo-
pleMan.
Dans la pratique, c'est PHP qui connaît le type des objets. Lorsqu'une méthode est appelée, il exécute en priorité la méthode de la classe de l'objet, sinon
57
il remonte dans la hiérarchie à la recherche d'une méthode implémentée dans
une classe parente.
1
5
<?php
define('PEOPLE_WOMAN', 1);
define('PEOPLE_MAN', 2);
define('PEOPLE_DAUGHTER', 3);
define('PEOPLE_SON', 4);
abstract class People {
private $id;
private $prenom;
private $nom;
10
public function __construct($id, $prenom, $nom) {
$this->id = $id;
$this->prenom = $prenom;
$this->nom = $nom;
}
15
public function getId() {
return $this->id;
}
20
public function getType() {
25
}
public function getTitle() {
}
30
public function edit() {
return "<td><a href=\"?action=edit&id=$this->id\">edit</a></td>";
}
35
public function viewHTML() {
return "<tr><td>$this->id</td><td>" . $this->getTitle() .
"</td><td>$this->prenom</td><td>$this->nom</td>" .
$this->edit() . "</tr>";
}
40
}
45
//-----------------------------------------------------------------------------class PeopleWoman extends People {
public function __construct($id, $prenom, $nom) {
58
}
50
public function getType() {
return PEOPLE_WOMAN;
}
public function getTitle() {
return "Mme";
}
55
60
}
//-----------------------------------------------------------------------------class PeopleMan extends People {
public function __construct($id, $prenom, $nom) {
parent::__construct($id, $prenom, $nom);
}
65
public function getType() {
return PEOPLE_MAN;
}
70
75
80
parent::__construct($id, $prenom, $nom);
public function getTitle() {
return "M.";
}
}
//-----------------------------------------------------------------------------class PeopleDaughter extends People {
public function __construct($id, $prenom, $nom) {
parent::__construct($id, $prenom, $nom);
}
public function getType() {
return PEOPLE_DAUGHTER;
}
85
public function getTitle() {
return "Mlle";
}
90
}
95
//-----------------------------------------------------------------------------class PeopleSon extends People {
59
public function __construct($id, $prenom, $nom) {
parent::__construct($id, $prenom, $nom);
}
100
public function getType() {
return PEOPLE_SON;
}
105
110
public function getTitle() {
return "Jr.";
}
}
?>
Nous gérons maintenant une liste de personnes, stockée dans une base de
données :
1
5
<?php
require_once 'people.factory.php';
require_once 'outils_bd.class.php';
class PeopleList {
private $peoples = array();
10
15
20
25
30
public function __construct() {
$this->peoples = array();
foreach (Outils_Bd::getInstance()->getConnexion()->query(
"SELECT * FROM peoples")
as $row)
switch ($row['type']) {
case PEOPLE_WOMAN:
$this->peoples[] = new PeopleWoman($row['id'],
$row['prenom'], $row['nom']);
case PEOPLE_MAN:
$this->peoples[] = new PeopleMan($row['id'],
$row['prenom'], $row['nom']);
case PEOPLE_DAUGHTER:
$this->peoples[] = new PeopleDaughter($row['id'],
$row['prenom'], $row['nom']);
case PEOPLE_SON:
$this->peoples[] = new PeopleSon($row['id'],
$row['prenom'], $row['nom']);
default:
break;
}
}
60
public function viewHTML() {
$return = '<table>';
foreach ($this->peoples as $people)
$return .= $people->viewHTML();
return $return . '</table>';
}
35
40
}
?>
Le contrôleur est alors simplement :
1
<?php
5
/// merci de reporter toutes les erreurs
ini_set('display_errors', 1);
error_reporting(E_ALL | E_STRICT);
require_once("people.list.php");
10
15
20
25
30
print_r($_GET);
$list = new PeopleList();
$view = '';
if (isset($_GET['action'])) {
switch ($_GET['action']) {
case 'edit':
$view = $list->edit($_GET);
break;
case 'save':
$list->save($_GET);
$view = $list->viewHTML();
break;
default:
$view = $list->viewHTML();
break;
}
}else
$view = $list->viewHTML();
echo $view;
?>
La base de données :
61
Chapitre 14
TD - Héritage
14.1 Mise en place des formulaires
1. comme indiqué par le contrôleur, mettre en place les méthodes permettant
d'éditer une personne. Le code généré peut par exemple être
<table><tr><td>1</td>
<td>M.</td>
<td>Jean</td>
<td>Dupont</td>
<td><a href="?action=edit&id=1">edit</a></td></tr>
<form method="GET" action="index.php">
<input type="hidden" name="action" value="save"/>
<input type="hidden" name="id" value="2"/>
<tr><td>2</td>
<td>Mme</td>
<td><input type="text" name="prenom" value="Jeanne"/></td>
<td><input type="text" name="nom" value="Dupont"/></td>
<td><input type="submit"/></td>
</form></tr>
<tr><td>3</td>
<td>Jr.</td>
<td>Joe</td>
<td>Dupont</td>
<td><a href="?action=edit&id=3">edit</a></td></tr>
<tr><td>4</td>
<td>Mlle</td>
<td>Averelle</td>
<td>Dupon</td>
<td><a href="?action=edit&id=4">edit</a></td></tr>
</table>
2. ajouter les méthodes permettant de sauvegarder le résultat de l'édition.
62
14.2 Ajout de classes pour gérer les enfants
On ajoute maintenant une classe abstraite des enfants, qui possède une information supplémentaire : un adulte responsable.
//-----------------------------------------------------------------------------abstract class PeopleChildren extends People {
private $responsable = -1;
public function __construct($id, $prenom, $nom) {
parent::__construct($id, $prenom, $nom);
foreach (Outils_Bd::getInstance()->getConnexion()->query(
"SELECT * FROM children WHERE id = $this->id")
as $row)
$this->responsable = $row['responsable'];
}
public function viewHTML() {
return "<tr><td>$this->id</td><td>" . $this->getTitle() .
"</td><td>$this->prenom</td><td>$this->nom</td>" .
"<td>$this->responsable</td>" .
$this->edit() . "</tr>";
}
public function save($get) {
parent::save($get);
$this->responsable = $get['responsable'];
Outils_Bd::getInstance()->getConnexion()->query("UPDATE children " .
"SET responsable = $this->responsable WHERE id = $this->id");
}
public function formulaire() {
...
}
}
Pour cela, on ajoute une table
children
au système d'information :
--- Structure de la table `children`
-CREATE TABLE IF NOT EXISTS `children` (
`id` int(11) NOT NULL,
`responsable` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-63
-- Contenu de la table `children`
-INSERT INTO `children` (`id`, `responsable`) VALUES
(4, 2),
(3, 1);
Implémenter le code HTML nécessaire pour que l'édition d'un enfant permette de préciser son responsable. Le code généré pourra être du type :
<table border="1">
<tr><th width="50">Id</th>
<th width="50">Title</th>
<th width="180">Pr&eacute;nom</th>
<th width="180">Nom</th>
<th width="150">Responsable</th>
<th width="100">Action</th>
</tr>
<tr><td>1</td><td>M.</td><td>Jean</td><td>Dupont</td><td>&nbsp;</td>
<td><a href="?action=edit&id=1">edit</a></td></tr>
<tr><td>2</td><td>Mme</td><td>Jeanne</td><td>Dupont</td><td>&nbsp;</td>
<td><a href="?action=edit&id=2">edit</a></td></tr>
<form method="GET" action="/~frioult/svn/m1dnr-dev1/sequence7/td/index.php">
<input type="hidden" name="action" value="save"/>
<input type="hidden" name="id" value="3"/>
<td>3</td>
<td>Jr.</td>
<td><input type="text" name="prenom" value="Joe"/></td>
<td><input type="text" name="nom" value="Dupont"/></td>
<td>
<select name="responsable">
<option value="1"selected="selected">Jean Dupont</option>
<option value="2">Jeanne Dupont</option></select>
</td>
<td><input type="submit"/></td>
</form></tr>
<tr><td>4</td><td>Mlle</td><td>Averelle</td><td>Dupont</td><td>2</td>
<td><a href="?action=edit&id=4">edit</a></td>
</tr>
</table>
64
Chapitre 15
Exceptions
15.1 Principe des exceptions
Dans le cadre de la programmation objet, les exceptions sont utilisées pour
gérer les erreurs. En eet, la construction des objets n'est pas une fonction et ne
peut donc pas renvoyer de code d'erreur. On pourrait éventuellement tester la
qualité de l'objet pour détecter une erreur, mais cela surchargerait la conception.
On utilise alors la structure suivante :
try{
......
le code pouvant générer une erreur
}
catch (Exception $e){
die('exception reçue ' . $e->getMessage());
}
Pour
lever une exception,
il sut d'insérer dans le code l'instruction
throw new Exception('<message>', $code, $previous);
Le
code
est un entier,
previous
est l'exception précédente.
15.2 La classe PHP Exception
Exception {
/* Properties */
protected string $Exception->message ;
protected int $code ;
protected string $file ;
protected int $line ;
65
}
/* Methods */
public Exception::__construct ([ string $message = "" [,
int $code = 0 [, Exception $previous = NULL ]]] )
final public string Exception::getMessage ( void )
final public Exception Exception::getPrevious ( void )
final public mixed Exception::getCode ( void )
final public string Exception::getFile ( void )
final public int Exception::getLine ( void )
final public array Exception::getTrace ( void )
final public string Exception::getTraceAsString ( void )
public string Exception::__toString ( void )
final private void Exception::__clone ( void )
Lorsqu'une exception est levée, l'objet correspondant est crée avec les numéro
de ligne et le nom du chier où l'exception est envoyée. De plus, une exception
conserve la trace des exceptions précédentes, ce qui permet d'acher une pile
des envois.
15.3 Héritage d'exception
La classe
Exception peut être dérivée, pour particulariser l'exception levée.
__toString() peut être surchargée.
On constate que seule la méthode
define('EXCEPTION_PEOPLE_LIST_CONSTRUCT', 1);
define('EXCEPTION_PEOPLE_CONSTRUCT', 2);
class ExceptionPeopleList extends Exception{
public function __construct($message, $previous) {
parent::__construct($message, EXCEPTION_PEOPLE_LIST_CONSTRUCT, $previous);
}
}
public function __toString() {
return 'exception while creation some PeopleList ' . parent::getMessage();
}
class ExceptionPeople extends Exception{
public function __construct($message, $previous) {
parent::__construct($message, EXCEPTION_PEOPLE_LIST_CONSTRUCT, $previous);
}
}
public function __toString() {
return 'exception while saving some People ' . parent::getMessage();
}
66
Ce qui permet, par exemple pendant la création d'une liste de clients, de
gérer les problèmes de connexion à la base de données.
try {
foreach (Outils_Bd::getInstance()->getConnexion()->query("SELECT * FROM peoples")
as $row)
$this->peoples[] = PeopleFactory::createPeople($row);
}
catch (Exception $e){
throw new ExceptionPeopleList(
"probleme de connection a la base de donnees..." .
$e->getMessage(), $e);
}
15.4 Utilisation des exceptions
Il faut toujours respecter les règles suivantes :
1. les exceptions doivent être exceptionnnelles, ce n'est pas le mode de fonctionnement normal du programme ;
2. ne jamais utiliser les exceptions pour contrôler le déroulement du programme ;
3. ne jamais utiliser les exceptions pour passer des paramètres.
67

Documents pareils