Aller au contenu
Réussir mon BTS SIO

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

Par exemple

Chapitre 319 minIntermédiaire

Tableaux et fonctions en PHP

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

À la fin de ce chapitre, tu sauras

  • créer et parcourir des tableaux indexés et associatifs ;
  • filtrer, transformer et trier un tableau sans boucle inutile ;
  • écrire des fonctions typées avec des arguments nommés ;
  • utiliser les fonctions anonymes et fléchées.

3 exercices corrigés

Un tableau PHP (array) range plusieurs valeurs sous une seule variable, chacune repérée par une clé : un numéro pour une liste, un nom pour un tableau associatif. Une fonction regroupe des instructions sous un nom, avec des paramètres typés et une valeur de retour. Ce chapitre montre comment créer, parcourir, trier et filtrer des tableaux, puis comment écrire des fonctions propres en PHP 8.5. Ce sont les deux outils que tu manipuleras en permanence : les lignes lues dans la base arrivent sous forme de tableaux.

Listes et tableaux associatifs

Un tableau indexé (une liste) a des clés numériques qui commencent à 0. Un tableau associatif a des clés de type chaîne, choisies par toi. En PHP, c'est le même type array.

php
<?php

// Tableau indexé : clés 0, 1, 2
$references = ['PC-0101', 'PC-0102', 'VP-0001'];
echo $references[0];              // PC-0101
$references[] = 'TAB-0003';       // ajoute à la fin, avec la clé 3
echo count($references);          // 4

// Tableau associatif : une ligne de la table materiel
$materiel = [
    'id' => 1,
    'reference' => 'PC-0101',
    'libelle' => 'Portable Dell Latitude 5450',
    'valeur' => 1180.0,
];
echo $materiel['libelle'];        // Portable Dell Latitude 5450
$materiel['etat'] = 'disponible'; // ajoute une clé
unset($materiel['valeur']);       // supprime une clé

Lire une clé qui n'existe pas affiche l'avertissement « Undefined array key » et renvoie null. Teste avant avec isset($tab['cle']), ou donne une valeur par défaut avec $tab['cle'] ?? 'défaut'.

Un tableau peut contenir d'autres tableaux. Le résultat d'une requête SQL, par exemple, est une liste de tableaux associatifs : une ligne par élément, une clé par colonne. C'est la forme que tu verras partout dans la suite du cours.

php
<?php

$materiels = [
    ['id' => 1, 'reference' => 'PC-0101', 'categorie' => 'portable', 'valeur' => 1180.0, 'disponible' => true],
    ['id' => 3, 'reference' => 'VP-0001', 'categorie' => 'videoprojecteur', 'valeur' => 899.0, 'disponible' => true],
    ['id' => 2, 'reference' => 'PC-0102', 'categorie' => 'portable', 'valeur' => 1180.0, 'disponible' => false],
    ['id' => 4, 'reference' => 'TAB-0003', 'categorie' => 'tablette', 'valeur' => 449.9, 'disponible' => false],
];

echo $materiels[2]['reference'];   // PC-0102 : 3e ligne, colonne reference

Parcourir un tableau avec foreach

foreach parcourt chaque élément. La forme $cle => $valeur donne aussi la clé.

php
<?php

$materiel = ['reference' => 'PC-0101', 'categorie' => 'portable', 'valeur' => 1180.0];

foreach ($materiel as $colonne => $valeur) {
    echo "$colonne : $valeur\n";
}
// reference : PC-0101
// categorie : portable
// valeur : 1180

Pour une liste de lignes, une boucle suffit à produire un tableau HTML :

php
<?php $materiels = [['reference' => 'PC-0101', 'categorie' => 'portable'], ['reference' => 'VP-0001', 'categorie' => 'videoprojecteur']]; ?>
<table>
  <tr><th>Référence</th><th>Catégorie</th></tr>
  <?php foreach ($materiels as $m): ?>
    <tr>
      <td><?= htmlspecialchars($m['reference']) ?></td>
      <td><?= htmlspecialchars($m['categorie']) ?></td>
    </tr>
  <?php endforeach; ?>
</table>

Chercher dans un tableau

BesoinFonctionExemple
La clé existe-t-elle ?array_key_exists(), isset()isset($m['photo']) est faux si la clé vaut null ; array_key_exists('photo', $m) est vrai
La valeur est-elle présente ?in_array($v, $tab, true)in_array($categorie, CATEGORIES, true)
À quelle clé est cette valeur ?array_search($v, $tab, true)array_search('VP-0001', $references, true) donne 1
Le premier élément qui vérifie une conditionarray_find() (PHP 8.4)array_find($materiels, fn($m) => !$m['disponible'])
Au moins un élément vérifie-t-il la condition ?array_any(), array_all() (PHP 8.4)array_any($materiels, fn($m) => $m['categorie'] === 'camera')
Le premier ou le dernier élémentarray_first(), array_last() (PHP 8.5)array_first($materiels)

Transformer, filtrer et trier

PHP fournit des fonctions qui évitent d'écrire des boucles à la main. Elles prennent souvent une fonction fléchée (fn) en paramètre, présentée plus bas.

php
<?php

$materiels = [
    ['id' => 1, 'reference' => 'PC-0101', 'categorie' => 'portable', 'valeur' => 1180.0, 'disponible' => true],
    ['id' => 3, 'reference' => 'VP-0001', 'categorie' => 'videoprojecteur', 'valeur' => 899.0, 'disponible' => true],
    ['id' => 2, 'reference' => 'PC-0102', 'categorie' => 'portable', 'valeur' => 1180.0, 'disponible' => false],
    ['id' => 4, 'reference' => 'TAB-0003', 'categorie' => 'tablette', 'valeur' => 449.9, 'disponible' => false],
];

// Extraire une colonne
$refs = array_column($materiels, 'reference');            // ['PC-0101', 'VP-0001', 'PC-0102', 'TAB-0003']
$refsParId = array_column($materiels, 'reference', 'id');  // [1 => 'PC-0101', 3 => 'VP-0001', 2 => 'PC-0102', 4 => 'TAB-0003']

// Filtrer : garder les éléments pour lesquels la fonction renvoie true
$disponibles = array_filter($materiels, fn(array $m): bool => $m['disponible']);

// Transformer chaque élément
$libelles = array_map(fn(array $m): string => $m['reference'] . ' (' . $m['categorie'] . ')', $materiels);

// Réduire à une seule valeur
$valeurTotale = array_sum(array_column($materiels, 'valeur'));   // 3708.9

// Trier : du plus cher au moins cher, puis par référence
usort($materiels, fn(array $a, array $b): int
    => $b['valeur'] <=> $a['valeur'] ?: $a['reference'] <=> $b['reference']);
// PC-0101, PC-0102, VP-0001, TAB-0003

Quelques détails qui piègent :

  • array_filter() conserve les clés d'origine : $disponibles a les clés 0 et 1 ici, mais si le premier élément avait été filtré, la liste commencerait à 1. Passe le résultat dans array_values() si tu as besoin d'une liste numérotée à partir de 0 (pour la convertir en tableau JSON, par exemple).
  • sort(), usort() et leurs variantes trient le tableau lui-même (il est passé par référence) et renvoient true, pas le tableau trié. N'écris pas $tries = sort($liste);.
  • L'opérateur <=> renvoie -1, 0 ou 1 : c'est exactement ce qu'attend la fonction de comparaison de usort(). ?: passe au critère suivant quand le premier donne 0 (égalité).
FonctionTrie selonGarde les clés ?
sort() / rsort()les valeurs, croissant / décroissantnon
asort() / arsort()les valeursoui
ksort() / krsort()les clésoui
usort()ta fonction de comparaisonnon
uasort()ta fonction de comparaisonoui

Pour compter par catégorie, la boucle classique reste la plus lisible :

php
<?php

$materiels = [['categorie' => 'portable'], ['categorie' => 'videoprojecteur'], ['categorie' => 'portable'], ['categorie' => 'tablette']];

$parCategorie = [];
foreach ($materiels as $m) {
    $parCategorie[$m['categorie']] = ($parCategorie[$m['categorie']] ?? 0) + 1;
}
// ['portable' => 2, 'videoprojecteur' => 1, 'tablette' => 1]

Si les données viennent de la base, fais plutôt ce calcul en SQL avec GROUP BY (cours SQL) : la base est faite pour ça, et tu ne transfères que le résultat.

Décomposer et fusionner

php
<?php

// Décomposer une liste
[$prefixe, $numero] = explode('-', 'PC-0101');   // 'PC' et '0101'

// Décomposer un tableau associatif
$materiel = ['reference' => 'PC-0101', 'valeur' => 1180.0];
['reference' => $ref, 'valeur' => $val] = $materiel;

// Fusionner : l'opérateur ... (spread) et array_merge()
$defauts = ['etat' => 'disponible', 'photo' => null];
$saisie = ['reference' => 'CAM-0002', 'photo' => 'cam-0002.jpg'];
$materiel = [...$defauts, ...$saisie];
// ['etat' => 'disponible', 'photo' => 'cam-0002.jpg', 'reference' => 'CAM-0002']

Avec des clés chaînes, la valeur de droite remplace celle de gauche. L'opérateur + fait l'inverse : $a + $b garde la valeur de $a quand la clé existe des deux côtés.

Écrire une fonction

Une fonction se déclare avec function, un nom en camelCase, des paramètres typés et un type de retour :

php
<?php

declare(strict_types=1);

function creerReference(string $categorie, int $numero, int $largeur = 4): string
{
    $prefixe = match ($categorie) {
        'portable' => 'PC',
        'videoprojecteur' => 'VP',
        'tablette' => 'TAB',
        'camera' => 'CAM',
        default => 'DIV',
    };

    return sprintf('%s-%0' . $largeur . 'd', $prefixe, $numero);
}

echo creerReference('portable', 42);                     // PC-0042
echo creerReference(numero: 7, categorie: 'camera');     // CAM-0007 : arguments nommés
echo creerReference('autre', 5, largeur: 3);             // DIV-005

Ce que tu peux déclarer :

ÉlémentSyntaxeExemple
Type simpleint, float, string, bool, arrayint $numero
Type nullable?type?string $photo accepte une chaîne ou null
Type uniontype1|type2int|float $valeur
Valeur par défaut= valeurint $largeur = 4
Aucun retour: voidfunction journaliser(string $msg): void
Ne revient jamais: neverune fonction qui fait toujours exit ou lève une exception
Nombre variable d'argumentstype ...$nomfloat ...$valeurs reçoit un tableau

Les arguments nommés (numero: 7) rendent les appels lisibles et permettent de sauter les paramètres qui ont une valeur par défaut. Une fonction ne voit que ses paramètres et ses variables locales : une variable définie à l'extérieur n'est pas accessible à l'intérieur. N'utilise pas le mot-clé global pour contourner cela : passe la valeur en paramètre.

Par défaut, un tableau passé à une fonction est copié : la fonction travaille sur sa copie. Pour qu'elle modifie le tableau d'origine, déclare le paramètre par référence avec & (function ajouter(array &$liste, string $ref): void). Réserve cette possibilité aux cas où elle est vraiment utile : une fonction qui renvoie une nouvelle valeur est plus facile à comprendre et à tester.

Fonctions anonymes, fléchées et callables

Une fonction anonyme (ou closure) n'a pas de nom ; on la range dans une variable ou on la passe en argument. Pour utiliser une variable extérieure, elle doit la capturer avec use. La fonction fléchée fn, plus courte, capture automatiquement les variables extérieures et ne contient qu'une expression.

php
<?php

$tva = 0.2;

$ttc = function (float $ht) use ($tva): float {
    return round($ht * (1 + $tva), 2);
};

$ttcFleche = fn(float $ht): float => round($ht * (1 + $tva), 2);

echo $ttc(100.0);        // 120
echo $ttcFleche(100.0);  // 120

Les deux capturent la valeur de $tva au moment de leur création : si $tva change ensuite, elles gardent l'ancienne.

La syntaxe nomDeFonction(...) crée un callable à partir d'une fonction existante : array_map(strtoupper(...), $refs) met chaque référence en majuscules.

PHP 8.5 ajoute l'opérateur pipe |>, qui passe une valeur d'une fonction à la suivante, de gauche à droite :

php
<?php

// PHP 8.5
$identifiant = '  Vidéoprojecteur Epson  '
    |> trim(...)
    |> mb_strtolower(...)
    |> (fn(string $s): string => str_replace(' ', '-', $s));
// 'vidéoprojecteur-epson'

C'est l'équivalent de str_replace(' ', '-', mb_strtolower(trim($texte))), en plus lisible. Si tu travailles en PHP 8.4, garde la forme imbriquée.

Exercices

Exercice 1 sur 3 Manipuler la liste du matériel Réussi À revoir

À partir du tableau $materiels de la section Transformer, filtrer et trier, écris une instruction (ou une courte boucle) pour obtenir :

  1. la liste des références des matériels prêtés (non disponibles), numérotée à partir de 0 ;
  2. la valeur totale du matériel disponible ;
  3. un tableau [référence => valeur] ;
  4. le libellé « 2 portable(s), 1 videoprojecteur(s), 1 tablette(s) », dans l'ordre d'apparition des catégories.
Voir la réponseMasquer la réponse de l'exercice 1
php
<?php
// 1. ['PC-0102', 'TAB-0003']
$pretes = array_values(array_column(
    array_filter($materiels, fn(array $m): bool => !$m['disponible']),
    'reference'
));

// 2. 2079 (1180 + 899)
$valeurDispo = array_sum(array_column(
    array_filter($materiels, fn(array $m): bool => $m['disponible']),
    'valeur'
));

// 3. ['PC-0101' => 1180.0, 'VP-0001' => 899.0, 'PC-0102' => 1180.0, 'TAB-0003' => 449.9]
$valeurParRef = array_column($materiels, 'valeur', 'reference');

// 4.
$parCategorie = [];
foreach ($materiels as $m) {
    $parCategorie[$m['categorie']] = ($parCategorie[$m['categorie']] ?? 0) + 1;
}
$morceaux = [];
foreach ($parCategorie as $categorie => $nb) {
    $morceaux[] = "$nb $categorie(s)";
}
echo implode(', ', $morceaux);

Pour la question 1, array_column() renvoie déjà une liste numérotée à partir de 0 ; le array_values() est une précaution, sans effet ici. array_column() accepte un troisième argument, la colonne qui sert de clé : c'est la question 3.

Tu avais trouvé ?

Exercice 2 sur 3 Écrire une fonction typée Réussi À revoir

Écris la fonction dureePret(string $categorie, bool $prioritaire = false): int qui renvoie la durée maximale d'un prêt en jours : 14 pour un portable ou une tablette, 3 pour un vidéoprojecteur ou une caméra, 7 sinon. Un emprunteur prioritaire (un commercial en déplacement, par exemple) a le double. Appelle-la avec un argument nommé pour un vidéoprojecteur prioritaire.

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

function dureePret(string $categorie, bool $prioritaire = false): int
{
    $jours = match ($categorie) {
        'portable', 'tablette' => 14,
        'videoprojecteur', 'camera' => 3,
        default => 7,
    };

    return $prioritaire ? $jours * 2 : $jours;
}

echo dureePret('videoprojecteur', prioritaire: true);   // 6

La fonction ne fait qu'un calcul et renvoie un int : elle ne lit ni la base ni la session, ce qui la rend facile à tester avec quelques valeurs (portable, caméra, une catégorie inconnue, avec et sans priorité).

Tu avais trouvé ?

Exercice 3 sur 3 Trier correctement Réussi À revoir

Ce code doit afficher les matériels du moins cher au plus cher. Il affiche un avertissement d'obsolescence, « 1 », puis un avertissement sur le foreach, et aucune référence. Corrige-le.

php
<?php
$tries = usort($materiels, fn($a, $b) => $a['valeur'] > $b['valeur']);
echo $tries;
foreach ($tries as $m) {
    echo $m['reference'] . "\n";
}
Voir la réponseMasquer la réponse de l'exercice 3

Deux erreurs. usort() trie $materiels sur place et renvoie true (affiché « 1 ») : $tries n'est pas un tableau, d'où l'avertissement « foreach() argument must be of type array|object, true given » : la boucle ne s'exécute pas. Et la fonction de comparaison doit renvoyer un entier négatif, nul ou positif, pas un booléen : depuis PHP 8, un booléen est accepté mais signalé comme obsolète (deprecated), et le tri peut être faux.

php
<?php
usort($materiels, fn(array $a, array $b): int => $a['valeur'] <=> $b['valeur']);
foreach ($materiels as $m) {
    echo $m['reference'] . "\n";
}
// TAB-0003, VP-0001, puis PC-0101 et PC-0102

Les deux portables ont la même valeur : le tri de PHP est stable depuis la version 8.0, ils restent dans leur ordre d'origine.

Tu avais trouvé ?

Chapitre terminé !

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

chapitres
–
de série
–
du cours
–
Chapitre suivant : Formulaire PHP : $_GET, $_POST et validationRevoir le sommaire du cours