Aller au contenu
Réussir mon BTS SIO

Tape une notion, une commande ou le nom d'une épreuve.

Par exemple

Chapitre 222 minIntermédiaire

Les bases de PHP : variables, types, conditions et boucles

Par Josselyn C., prof de BTS SIO. Mis à jour le .

À la fin de ce chapitre, tu sauras

  • déclarer des variables et connaître les types de PHP ;
  • activer le typage strict et comparer avec === ;
  • manipuler des chaînes de caractères, accents compris ;
  • écrire des conditions avec if et match, et des boucles.

4 exercices corrigés

Les bases du langage PHP tiennent en quelques règles : une variable commence par $, une instruction se termine par ;, les types sont vérifiés à l'exécution et l'on compare avec ===. Ce chapitre présente les variables, les types et le typage strict, les opérateurs, les chaînes de caractères, les conditions avec if et match, et les boucles. Si tu as déjà programmé dans un autre langage, lis-le vite, mais lis attentivement les encadrés : ils signalent les pièges propres à PHP.

Variables et constantes

Une variable commence par le signe $, suivi d'un nom qui commence par une lettre ou _. Elle n'a pas besoin d'être déclarée : elle existe dès qu'on lui affecte une valeur.

php
<?php

$reference = 'PC-0101';
$valeur = 1180.00;
$nbJoursMax = 14;
$estDisponible = true;
$dateRetour = null;            // pas encore de date de retour

Les noms de variables sont sensibles à la casse : $valeur et $Valeur sont deux variables différentes. L'usage, dans le code PHP moderne, est le camelCase ($nbJoursMax). Écris des noms en français ou en anglais, mais pas un mélange des deux dans le même projet.

Une constante garde la même valeur pendant toute l'exécution. Elle s'écrit sans $, en majuscules par convention :

php
<?php

const DUREE_PRET_MAX = 14;           // en jours
const CATEGORIES = ['portable', 'videoprojecteur', 'tablette', 'camera', 'autre'];

echo DUREE_PRET_MAX;                 // 14

Les types de données

PHP est un langage à typage dynamique : c'est la valeur qui a un type, pas la variable. La même variable peut contenir un entier, puis une chaîne.

TypeExempleRemarque
int42, -7, 0x1AEntier sur 64 bits : jusqu'à 9 223 372 036 854 775 807
float1180.0, 3.5e3Nombre à virgule, avec un point décimal
string'PC-0101', "Bonjour"Suite d'octets : un caractère accentué en UTF-8 en occupe deux
booltrue, falseInsensible à la casse, mais écris-le en minuscules
nullnullAbsence de valeur
array[1, 2, 3], ['id' => 4]Liste ou tableau associatif (chapitre 3)
objectnew DateTimeImmutable()Instance d'une classe (chapitre 11)

Pour connaître le type et la valeur d'une variable pendant que tu développes, utilise var_dump() : c'est l'outil de débogage le plus simple de PHP.

php
<?php

var_dump(1180.00);        // float(1180)
var_dump('PC-0101');      // string(7) "PC-0101"
var_dump(null);           // NULL
echo get_debug_type(14);  // int

Le typage strict avec declare(strict_types=1)

Quand une fonction attend un int et reçoit la chaîne '14', PHP la convertit silencieusement en mode par défaut. C'est pratique, mais cela cache des erreurs : '14 jours' donne une erreur, '14.0' une valeur arrondie, et tu ne sais plus d'où viennent tes données.

La directive declare(strict_types=1);, placée en première instruction du fichier, désactive ces conversions pour les appels de fonctions écrits dans ce fichier : un mauvais type déclenche une erreur TypeError au lieu d'être converti.

php
<?php

declare(strict_types=1);

function dateRetourPrevue(DateTimeImmutable $debut, int $nbJours): DateTimeImmutable
{
    return $debut->modify("+{$nbJours} days");
}

$debut = new DateTimeImmutable('2026-11-02');
echo dateRetourPrevue($debut, 14)->format('d/m/Y');   // 16/11/2026
echo dateRetourPrevue($debut, '14')->format('d/m/Y');  // TypeError : string given

Les données d'un formulaire arrivent toujours sous forme de chaînes ($_POST['nb_jours'] vaut '14', pas 14). En typage strict, tu dois donc les valider et les convertir toi-même, ce qui est exactement ce qu'il faut faire (chapitre 4).

Conversions et comparaisons : == ou ===

PHP propose deux opérateurs d'égalité :

  • == (égalité souple) compare après avoir converti les deux valeurs dans un type commun ;
  • === (égalité stricte) compare la valeur et le type, sans conversion.
ExpressionRésultat en PHP 8Explication
'1' == '01'trueDeux chaînes numériques : comparées comme des nombres
'10' == '1e1'true1e1 vaut 10 en notation scientifique
100 == '1e2'trueMême raison
0 == 'a'falseDepuis PHP 8 ; c'était true en PHP 7
null == falsetrueLes deux sont « vides »
[] == falsetrueUn tableau vide est « faux »
null == 0trueMême raison
'1' === 1falseUne chaîne n'est pas un entier

Pour convertir explicitement, utilise un transtypage (cast) :

php
<?php

var_dump((int) '12');        // int(12)
var_dump((int) '12abc');     // int(12) : PHP lit le début et ignore le reste
var_dump((int) 'abc');       // int(0)
var_dump((int) 12.9);        // int(12) : tronqué, pas arrondi
var_dump((float) '3.5');     // float(3.5)
var_dump((bool) '0');        // bool(false) : la chaîne '0' est fausse
var_dump((bool) '0.0');      // bool(true) : mais pas '0.0'

Le transtypage ne vérifie rien : (int) 'abc' donne 0 sans erreur. Pour une saisie, préfère une validation qui refuse ce qui n'est pas un entier, avec filter_var() (chapitre 4).

Les opérateurs

FamilleOpérateursExempleRésultat
Arithmétiques+ - * / % **7 / 2, 7 % 2, 2 ** 103.5, 1, 1024
Division entièreintdiv()intdiv(7, 2)3
Concaténation. et .='PC-' . '0101''PC-0101'
Affectation combinée+= -= *= /= .= ??=$total += $valeur;
Incrément++ --$nb++;
Comparaison=== !== < > <= >=$nb >= 3true ou false
Vaisseau spatial<=>10 <=> 51 (ou 0, ou -1)
Logiques&& || !$dispo && !$enPanne
Fusion null??$_GET['page'] ?? 1La valeur, ou 1 si elle n'existe pas ou vaut null

Deux pièges reviennent souvent :

  • + n'est pas la concaténation. '5' + '3' vaut 8 (une addition), '5' . '3' vaut '53'.
  • Les nombres à virgule sont approximatifs. 0.1 + 0.2 === 0.3 est faux, car ces nombres n'ont pas de représentation binaire exacte. Pour de l'argent, stocke des DECIMAL en base et calcule en centimes entiers, ou arrondis avec round($x, 2) au moment d'afficher.

L'opérateur ?? est très utilisé avec les données reçues : $_GET['page'] ?? 1 vaut le paramètre page s'il existe, 1 sinon, sans avertissement « Undefined array key ». Sa variante ??= n'affecte que si la variable est null ou inexistante : $_SESSION['panier'] ??= [];.

Les chaînes de caractères

Une chaîne s'écrit entre apostrophes ou entre guillemets. La différence : entre guillemets, PHP remplace les variables par leur valeur (c'est l'interpolation) et interprète les séquences comme \n (saut de ligne).

php
<?php

$libelle = 'Portable Dell';
$materiel = ['reference' => 'PC-0101', 'valeur' => 1180.5];

echo 'Matériel : $libelle';                      // Matériel : $libelle
echo "Matériel : $libelle";                      // Matériel : Portable Dell
echo "Référence : {$materiel['reference']}";     // les accolades pour un tableau
echo 'Référence : ' . $materiel['reference'];    // ou la concaténation

Pour un long texte sur plusieurs lignes, la syntaxe heredoc interpole comme des guillemets ; l'indentation de la ligne de fermeture est retirée de chaque ligne :

php
<?php

$nom = 'Karim Morel';
$reference = 'PC-0102';
$message = <<<TXT
    Bonjour {$nom},
    le matériel {$reference} est à rendre demain.
    TXT;
echo $message;

Les fonctions de chaînes que tu utiliseras le plus :

FonctionExempleRésultat
mb_strlen()mb_strlen('Étagère')7 caractères (strlen() donne 9 octets)
mb_strtoupper()mb_strtoupper('étagère')'ÉTAGÈRE' (strtoupper() laisse les accents en minuscule)
trim()trim(' karim ')'karim' : retire les espaces au début et à la fin
str_contains()str_contains('PC-0101', 'PC')true
str_starts_with()str_starts_with('PC-0101', 'PC-')true
str_replace()str_replace('-', '', 'PC-0101')'PC0101'
substr()substr('PC-0101', 3)'0101'
explode()explode('-', 'PC-0101')['PC', '0101']
implode()implode(', ', ['a', 'b'])'a, b'
str_pad()str_pad('42', 4, '0', STR_PAD_LEFT)'0042'
sprintf()sprintf('PC-%04d', 42)'PC-0042'
number_format()number_format(1180.5, 2, ',', ' ')'1 180,50'
ucfirst()ucfirst('karim')'Karim'

Conditions : if, elseif, else

php
<?php

$etat = 'en_reparation';
$empruntEnCours = false;

if ($etat !== 'disponible') {
    $message = 'Ce matériel ne peut pas être prêté.';
} elseif ($empruntEnCours) {
    $message = 'Ce matériel est déjà prêté.';
} else {
    $message = 'Ce matériel peut être prêté.';
}

Pour choisir entre deux valeurs, l'opérateur ternaire est plus court : $libelle = $nb > 1 ? 'matériels' : 'matériel';. Ne l'imbrique pas : deux ternaires imbriqués sans parenthèses sont même une erreur de syntaxe depuis PHP 8.

Une condition accepte n'importe quelle valeur, convertie en booléen. Sont fausses : false, 0, 0.0, '', '0', [] et null. Tout le reste est vrai. La fonction empty($x) teste exactement cela, et isset($x) teste qu'une variable existe et n'est pas null.

match : le switch moderne

match choisit une valeur selon une expression. Il remplace avantageusement switch :

php
<?php

$etat = 'en_reparation';

$libelle = match ($etat) {
    'disponible' => 'Disponible',
    'en_reparation' => 'En réparation',
    'reforme' => 'Réformé',
};
echo $libelle;   // En réparation
switchmatch
Comparaisonsouple (==)stricte (===)
Oubli de breakpasse au cas suivant, souvent par erreurimpossible : chaque bras renvoie une valeur
Valeur renvoyéenon, c'est une instructionoui, c'est une expression
Aucun cas ne correspondrien ne se passeerreur UnhandledMatchError, sauf bras default

Plusieurs valeurs peuvent partager un bras ('portable', 'tablette' => 14,). Pour des intervalles, la forme match (true) teste des conditions dans l'ordre :

php
<?php

$joursDeRetard = 9;

$niveau = match (true) {
    $joursDeRetard <= 0 => 'à l\'heure',
    $joursDeRetard <= 7 => 'relance',
    default => 'blocage des emprunts',
};
echo $niveau;   // blocage des emprunts

Les boucles : for, while, foreach

php
<?php

// for : quand tu connais le nombre de tours
for ($i = 1; $i <= 3; $i++) {
    echo "Relance n° $i\n";
}

// while : tant qu'une condition est vraie (testée avant chaque tour)
$stock = 3;
while ($stock > 0) {
    echo "Il reste $stock portable(s)\n";
    $stock--;
}

// foreach : pour parcourir un tableau, la boucle la plus utilisée en PHP
$references = ['PC-0101', 'PC-0102', 'VP-0001'];
foreach ($references as $reference) {
    echo $reference . "\n";
}

break sort de la boucle, continue passe directement au tour suivant. La boucle do { … } while (…); teste sa condition après le tour : elle s'exécute au moins une fois. Le chapitre 3 détaille foreach sur les tableaux associatifs, qui est la façon normale de parcourir les lignes renvoyées par la base.

La syntaxe alternative dans les gabarits HTML

Dans une page qui mélange HTML et PHP, les accolades deviennent difficiles à suivre. PHP propose une syntaxe alternative : : à la place de {, et endif;, endforeach;, endwhile; à la place de }.

php
<?php $materiels = [['reference' => 'PC-0101', 'disponible' => true], ['reference' => 'VP-0001', 'disponible' => false]]; ?>
<?php if ($materiels === []): ?>
  <p>Aucun matériel enregistré.</p>
<?php else: ?>
  <ul>
    <?php foreach ($materiels as $m): ?>
      <li>
        <?= htmlspecialchars($m['reference']) ?>
        <?php if (!$m['disponible']): ?><em>(prêté)</em><?php endif; ?>
      </li>
    <?php endforeach; ?>
  </ul>
<?php endif; ?>

C'est la syntaxe des vues : les fichiers qui affichent les données, sans logique métier (chapitre 12).

Exercices

Exercice 1 sur 4 Prédire l'affichage Réussi À revoir

Sans exécuter le code, donne ce qu'affiche chaque ligne.

php
<?php
var_dump('5' + '3');
var_dump('5' . '3');
var_dump(7 / 2);
var_dump(intdiv(7, 2));
var_dump('1' == '01');
var_dump('1' === '01');
var_dump(0 == 'a');
var_dump((int) '3 portables');
Voir la réponseMasquer la réponse de l'exercice 1
text
int(8)
string(2) "53"
float(3.5)
int(3)
bool(true)
bool(false)
bool(false)
int(3)

'1' == '01' est vrai, car deux chaînes numériques sont comparées comme des nombres ; avec ===, ce sont deux chaînes différentes. 0 == 'a' est faux depuis PHP 8. (int) '3 portables' lit le début de la chaîne et donne 3, sans erreur.

Tu avais trouvé ?

Exercice 2 sur 4 Remplacer un switch par match Réussi À revoir

Réécris ce code avec match. Quelle différence de comportement apparaît si $categorie vaut 'drone' ?

php
<?php
switch ($categorie) {
    case 'portable':
    case 'tablette':
        $duree = 14;
        break;
    case 'videoprojecteur':
    case 'camera':
        $duree = 3;
        break;
    default:
        $duree = 7;
}
Voir la réponseMasquer la réponse de l'exercice 2
php
<?php
$duree = match ($categorie) {
    'portable', 'tablette' => 14,
    'videoprojecteur', 'camera' => 3,
    default => 7,
};

Avec ce default, 'drone' donne 7 dans les deux versions. Sans bras default, match lèverait une UnhandledMatchError pour 'drone', alors qu'un switch sans default laisserait $duree non définie, sans rien signaler : match rend l'oubli visible. Autre différence : match compare avec ===, donc la valeur 0 ne correspondrait à aucun bras chaîne.

Tu avais trouvé ?

Exercice 3 sur 4 Le niveau de relance Réussi À revoir

Un emprunt devait être rendu il y a $joursDeRetard jours (0 ou négatif : pas en retard). Écris le code qui affiche, avec match (true) :

  • « Rien à faire » s'il n'y a pas de retard ;
  • « Relance par mail » de 1 à 3 jours de retard ;
  • « Appel du gestionnaire » de 4 à 10 jours ;
  • « Signalement au responsable » au-delà.

Puis écris une boucle qui affiche le niveau pour chaque valeur de 0 à 12 et vérifie les limites.

Voir la réponseMasquer la réponse de l'exercice 3
php
<?php
declare(strict_types=1);

function niveauRelance(int $joursDeRetard): string
{
    return match (true) {
        $joursDeRetard <= 0 => 'Rien à faire',
        $joursDeRetard <= 3 => 'Relance par mail',
        $joursDeRetard <= 10 => 'Appel du gestionnaire',
        default => 'Signalement au responsable',
    };
}

for ($j = 0; $j <= 12; $j++) {
    echo $j . ' : ' . niveauRelance($j) . "\n";
}

Les bras sont testés dans l'ordre : pour 3, $joursDeRetard <= 0 est faux, $joursDeRetard <= 3 est vrai, on s'arrête. La boucle affiche « Rien à faire » pour 0, « Relance par mail » de 1 à 3, « Appel du gestionnaire » de 4 à 10, « Signalement au responsable » pour 11 et 12. Teste toujours les limites (0, 1, 3, 4, 10, 11) : c'est là que se cachent les erreurs de < au lieu de <=.

Tu avais trouvé ?

Exercice 4 sur 4 Corriger une erreur de type Réussi À revoir

Ce script, en typage strict, lève une TypeError. Explique pourquoi et corrige-le sans retirer declare(strict_types=1).

php
<?php
declare(strict_types=1);

function formaterPrix(float $prix): string
{
    return number_format($prix, 2, ',', ' ') . ' €';
}

$saisie = '1180.5';            // valeur reçue d'un formulaire
echo formaterPrix($saisie);
Voir la réponseMasquer la réponse de l'exercice 4

$saisie est une chaîne (tout ce qui vient d'un formulaire est une chaîne) et la fonction attend un float : en typage strict, PHP refuse de convertir. On valide et on convertit à l'entrée :

php
<?php
declare(strict_types=1);

function formaterPrix(float $prix): string
{
    return number_format($prix, 2, ',', ' ') . ' €';
}

$saisie = '1180.5';
$prix = filter_var($saisie, FILTER_VALIDATE_FLOAT);
if ($prix === false) {
    exit('Prix invalide');
}
echo formaterPrix($prix);    // 1 180,50 €

filter_var() renvoie un vrai float, ou false si la saisie n'est pas un nombre : la conversion est contrôlée, pas subie. Un simple (float) $saisie ferait disparaître l'erreur, mais transformerait aussi 'abc' en 0.0 sans prévenir.

Tu avais trouvé ?

Chapitre terminé !

Fais les 4 exercices avant de passer à la suite : c'est en t'entraînant que tout se fixe.

chapitres
–
de série
–
du cours
–
Chapitre suivant : Tableaux et fonctions en PHPRevoir le sommaire du cours