backend / php-laravel
Fonctions et portée des variables
Explication
Ce que vous allez apprendre
- Déclarer des paramètres avec valeur par défaut et les appeler avec des arguments nommés
- Capturer un nombre variable d'arguments avec l'opérateur splat (
...) - Comprendre pourquoi une fonction PHP ne voit pas les variables globales par défaut
- Créer une closure qui capture son contexte englobant, avec
use()ou une arrow function - Passer une variable par référence pour qu'une fonction puisse la modifier directement
Dans quel contexte ?
Un développeur écrit une fonction creerUtilisateur() appelée à plusieurs endroits du code, mais avec des besoins légèrement différents à chaque fois (parfois on précise l'âge, parfois seulement le statut actif). Plutôt que de créer trois fonctions différentes, les arguments nommés et les valeurs par défaut permettent d'écrire une seule fonction flexible et lisible à l'appel, sans se souvenir de l'ordre exact des dix paramètres possibles.
D'abord, des paramètres qui savent se passer d'une valeur
Une fonction PHP peut définir des valeurs par défaut pour ses paramètres, comme function creerUtilisateur(string $nom, int $age = 18, bool $actif = true). Tant qu'on ne précise rien, ces valeurs par défaut s'appliquent automatiquement.
Depuis PHP 8, on peut aussi appeler la fonction avec des arguments nommés : creerUtilisateur(nom: "Bob", actif: false). L'ordre n'a alors plus d'importance, et on peut sauter des paramètres intermédiaires — un vrai gain de lisibilité dès qu'une fonction a plus de deux ou trois paramètres.
Prérequis
Cette leçon suppose que tu es à l'aise avec les bases vues en leçon 1 (variables, types, ??). Aucune autre connaissance n'est nécessaire.
Ensuite, que se passe-t-il si le nombre d'arguments n'est pas fixe ?
Parfois, on ne connaît pas à l'avance combien de valeurs seront passées à une fonction — additionner deux nombres ou vingt, par exemple. L'opérateur splat (...$nombres) résout ça en récupérant tous les arguments supplémentaires dans un tableau, directement utilisable avec des fonctions comme array_sum().
| Mécanisme | Syntaxe | Usage typique |
|---|---|---|
| Valeur par défaut | int $age = 18 | Paramètre optionnel courant |
| Argument nommé | creerUtilisateur(nom: "Bob") | Lisibilité, ordre libre |
| Splat (variadique) | function somme(int ...$n) | Nombre d'arguments inconnu |
| Référence | function doubler(int &$n) | Modifier la variable de l'appelant |
Il reste un point qui surprend souvent : la portée des variables
Une fonction PHP ne voit pas automatiquement les variables déclarées en dehors d'elle, contrairement à ce qu'on pourrait attendre en venant d'un script bash ou d'un notebook Python. C'est une protection volontaire : sans cette isolation, chaque fonction pourrait accidentellement modifier l'état de tout le programme.
Le mot-clé global permet d'y accéder explicitement, mais c'est justement une pratique à éviter en dehors de cas très ponctuels : elle rend le code difficile à suivre, puisqu'une fonction peut alors modifier des données sans que ça apparaisse dans sa signature.
Piège fréquent
S'appuyer sur global $compteurGlobal dans plusieurs fonctions rend le comportement du programme dépendant de l'ordre d'exécution et très difficile à tester isolément. Préfère toujours passer la donnée en paramètre, ou l'encapsuler dans un objet (voir la leçon sur la POO).
Maintenant, comment garder un peu de contexte sans variable globale ?
C'est là qu'interviennent les closures : une fonction anonyme peut "capturer" une variable de son environnement grâce à use($facteur), et s'en souvenir même après que la fonction englobante a terminé son exécution. creerMultiplicateur(3) renvoie ainsi une fonction qui se souviendra toujours du facteur 3.
Astuce
Les arrow functions (fn($n) => $n * $facteur), disponibles depuis PHP 7.4, capturent automatiquement le contexte englobant sans avoir besoin d'écrire use(). Elles sont idéales pour des callbacks courts avec array_map ou array_filter, comme tu le verras dans la prochaine leçon sur les tableaux.
Une fois ces mécanismes de fonctions et de portée bien compris, la suite logique consiste à les appliquer massivement sur des collections de données : direction la prochaine leçon, entièrement consacrée aux tableaux PHP.
Commandes & code
Fonctions et portée des variables
<?php
declare(strict_types=1);
// Paramètres par défaut et arguments nommés (PHP 8+)
function creerUtilisateur(string $nom, int $age = 18, bool $actif = true): array {
return compact('nom', 'age', 'actif');
}
// Appel avec arguments nommés : ordre libre, lisibilité accrue
$u = creerUtilisateur(nom: "Bob", actif: false);
print_r($u); // ['nom' => 'Bob', 'age' => 18, 'actif' => false]
// Nombre variable d'arguments avec splat operator
function somme(int ...$nombres): int {
return array_sum($nombres);
}
echo somme(1, 2, 3, 4) . "
"; // 10
// Passage par référence : modifie la variable appelante
function doubler(int &$n): void {
$n *= 2;
}
$valeur = 5;
doubler($valeur);
echo $valeur . "
"; // 10
// Portée : une fonction ne voit pas les variables globales par défaut
$compteurGlobal = 0;
function incrementer(): void {
global $compteurGlobal; // accès explicite requis (à éviter en pratique)
$compteurGlobal++;
}
// Closures et use() pour capturer le contexte englobant
function creerMultiplicateur(int $facteur): callable {
return function (int $n) use ($facteur): int {
return $n * $facteur;
};
}
$fois3 = creerMultiplicateur(3);
echo $fois3(7) . "
"; // 21
// Arrow functions (PHP 7.4+) : capturent automatiquement le scope englobant
$facteur = 10;
$fois10 = fn(int $n): int => $n * $facteur;
echo $fois10(4) . "
"; // 40
// Fonctions de première classe : passer une fonction en argument
$nombres = [5, -3, 8, -1, 2];
$positifs = array_filter($nombres, fn($n) => $n > 0);
$carres = array_map(fn($n) => $n ** 2, $nombres);
print_r(array_values($positifs));Résumé
- Les arguments nommés (
nom: "Bob") améliorent la lisibilité des appels à beaucoup de paramètres. ...$argscapture un nombre variable d'arguments dans un tableau.use (&$var)dans une closure classique, ou capture implicite avecfn(), pour accéder au contexte.- Passage par référence (
&$n) modifie directement la variable de l'appelant.
Exercices pratiques
Mission : fabriquer des generateurs de remise independants
Objectif : Utiliser closures, arguments nommes et portee des variables pour construire des fonctions de calcul de remise fiables et reutilisables.
Contexte
Le service facturation doit generer plusieurs calculateurs de remise (10%, 20%, remise VIP) utilises a des endroits differents de l'application. Un premier essai stagiaire a ecrit une seule fonction appliquerRemise() qui lit une variable globale $tauxCourant, modifiee un peu partout dans le code avant chaque appel. Le resultat : deux calculs lances presque en meme temps donnent parfois un mauvais taux, personne ne sait plus qui a modifie la variable globale en dernier.