web-dev-qa-db-fra.com

Référence: Quelle est la portée de la variable, quelles sont les variables accessibles depuis où et quelles sont les erreurs "variable non définie"?

Note: Ceci est une question de référence pour traiter de la portée variable en PHP. Veuillez fermer n’importe laquelle des nombreuses questions correspondant à ce modèle en tant que duplicata de celui-ci.

Qu'est-ce que "portée variable" en PHP? Les variables d'un fichier .php sont-elles accessibles dans un autre? Pourquoi ai-je parfois des erreurs "variable indéfinie"?

162
deceze

Qu'est-ce que "portée variable"?

Les variables ont une "portée" ou "des lieux à partir desquels elles sont accessibles". Juste parce que tu as écrit $foo = 'bar'; une fois quelque part dans votre application ne signifie pas que vous pouvez vous référer à $foo de partout dans l’application. La variable $foo a une certaine portée dans laquelle il est valide et seul le code de la même portée a accès à la variable.

Comment une portée est-elle définie en PHP?

Très simple: PHP a la portée de la fonction . C'est le seul type de séparateur de portée existant en PHP. Les variables à l'intérieur d'un Les variables en dehors des fonctions sont disponibles n'importe où en dehors des fonctions, mais pas à l'intérieur d'une fonction. Cela signifie qu'il y a une portée spéciale en PHP: le global portée: toute variable déclarée en dehors de toute fonction se trouve dans cette portée globale.

Exemple:

<?php

$foo = 'bar';

function myFunc() {
    $baz = 42;
}

$foo est dans la portée globale , $baz est dans une portée locale à l'intérieur de myFunc. Seul le code à l'intérieur de myFunc a accès à $baz. Seul le code extérieur à myFunc a accès à $foo. Ni l'un ni l'autre n'a accès à l'autre:

<?php

$foo = 'bar';

function myFunc() {
    $baz = 42;

    echo $foo;  // doesn't work
    echo $baz;  // works
}

echo $foo;  // works
echo $baz;  // doesn't work

Portée et fichiers inclus

Les limites de fichier ne ne séparent pas la portée:

a.php

<?php

$foo = 'bar';

b.php

<?php

include 'a.php';

echo $foo;  // works!

Les mêmes règles s'appliquent au code included de la même manière qu'à tout autre code: seule la portée séparée de functions. Aux fins de l'étendue, vous pouvez penser à inclure des fichiers tels que copier et coller du code:

c.php

<?php

function myFunc() {
    include 'a.php';

    echo $foo;  // works
}

myFunc();

echo $foo;  // doesn't work!

Dans l'exemple ci-dessus, a.php a été inclus dans myFunc, toutes les variables à l'intérieur de a.php ont uniquement la portée de la fonction locale. Tout simplement parce qu'ils apparaissent dans le champ d'application global de a.php ne signifie pas nécessairement qu’ils le sont, cela dépend en fait du contexte dans lequel le code est inclus/exécuté.

Qu'en est-il des fonctions à l'intérieur des fonctions et des classes?

Chaque nouvelle déclaration function introduit une nouvelle portée, c'est aussi simple que cela.

Fonctions (anonymes) à l'intérieur des fonctions

function foo() {
    $foo = 'bar';

    $bar = function () {
        // no access to $foo
        $baz = 'baz';
    };

    // no access to $baz
}

des classes

$foo = 'foo';

class Bar {

    public function baz() {
        // no access to $foo
        $baz = 'baz';
    }

}

// no access to $baz

A quoi sert la portée?

Traiter les problèmes de cadrage peut sembler ennuyeux, mais la portée des variables est essentielle pour écrire des applications complexes! Si chaque variable que vous déclarez serait disponible de partout ailleurs dans votre application, vous iriez de l'avant sur vos variables sans moyen réel de suivre ce qui change quoi. Vous ne pouvez donner que trop de noms sensibles à vos variables, vous voudrez probablement utiliser la variable "$name "à plusieurs endroits. Si vous ne pouviez avoir ce nom de variable unique qu'une seule fois dans votre application, vous auriez à recourir à des schémas de nommage vraiment compliqués pour vous assurer que vos variables sont uniques et que vous ne modifiez pas le mauvais variable du mauvais morceau de code.

Observer:

function foo() {
    echo $bar;
}

S'il n'y avait pas de portée, que ferait la fonction ci-dessus? Où est-ce que $bar viens de? Quel état a-t-il? Est-il même initialisé? Devez-vous vérifier à chaque fois? Ce n'est pas maintenable. Ce qui nous amène à ...

Franchir les limites de la portée

La bonne façon: passer des variables dedans et dehors

function foo($bar) {
    echo $bar;
    return 42;
}

La variable $bar entre explicitement dans cette étendue en tant qu'argument de fonction. En regardant cette fonction, on voit clairement d'où proviennent les valeurs avec lesquelles il travaille. Il renvoie ensuite explicitement une valeur. L'appelant a l'assurance de savoir avec quelles variables la fonction travaillera et d'où proviennent ses valeurs de retour:

$baz   = 'baz';
$blarg = foo($baz);

Extension de la portée des variables aux fonctions anonymes

$foo = 'bar';

$baz = function () use ($foo) {
    echo $foo;
};

$baz();

La fonction anonyme inclut explicitement $foo de sa portée environnante. Notez que ce n'est pas la même chose que global .

La mauvaise façon: global

Comme indiqué précédemment, la portée globale est quelque peu spéciale et les fonctions peuvent explicitement importer des variables à partir de celle-ci:

$foo = 'bar';

function baz() {
    global $foo;
    echo $foo;
    $foo = 'baz';
}

Cette fonction utilise et modifie la variable globale $foo. Ne fais pas ça! (À moins que vous ne sachiez vraiment ce que vous faites, et encore: ne le faites pas!)

Tout l'appelant de cette fonction voit est ceci:

baz(); // outputs "bar"
unset($foo);
baz(); // no output, WTF?!
baz(); // outputs "baz", WTF?!?!!

Rien n'indique que cette fonction ait des effets secondaires , mais c'est le cas. Cela devient très facilement un désordre enchevêtré car certaines fonctions continuent à modifier et nécessitant un certain état global. Vous voulez que les fonctions soient sans état , agissant uniquement sur leurs entrées et renvoyant une sortie définie, quel que soit le nombre de fois que vous les appelez.

Vous devez éviter autant que possible d'utiliser la portée globale. très certainement, vous ne devriez pas "extraire" des variables du champ global vers un champ local.

175
deceze

Bien que les variables définies à l'intérieur de la portée d'une fonction ne puissent pas être accédées de l'extérieur, cela ne signifie pas que vous ne pouvez pas utiliser leurs valeurs une fois cette fonction terminée. PHP a un mot-clé bien connu static qui est largement utilisé dans les objets orientés objet PHP pour définir des méthodes et des propriétés statiques, mais il convient de le conserver.) Notez que static peut également être utilisé dans les fonctions pour définir des variables statiques.

Qu'est-ce que la 'variable statique'?

La variable statique diffère de la variable ordinaire définie dans l'étendue de la fonction dans le cas où elle ne perd pas de valeur lorsque l'exécution du programme quitte cette étendue. Prenons l'exemple suivant d'utilisation de variables statiques:

function countSheep($num) {
 static $counter = 0;
 $counter += $num;
 echo "$counter sheep jumped over fence";
}

countSheep(1);
countSheep(2);
countSheep(3);

Résultat:

1 sheep jumped over fence
3 sheep jumped over fence
6 sheep jumped over fence

Si nous avions défini $counter sans static alors chaque valeur renvoyée serait la même chose que $num paramètre passé à la fonction. Utiliser static permet de construire ce compteur simple sans solution de contournement supplémentaire.

Cas d'utilisation de variables statiques

  1. Pour stocker des valeurs entre les appels consécutifs à la fonction.
  2. Pour stocker des valeurs entre des appels récursifs lorsqu'il n'y a aucun moyen (ou aucun objectif) de les transmettre en tant que paramètres.
  3. Pour mettre en cache une valeur qu'il est normalement préférable de récupérer une fois. Par exemple, résultat de la lecture d'un fichier immuable sur le serveur.

astuces

La variable statique n'existe que dans une étendue de fonction locale. Vous ne pouvez pas y accéder en dehors de la fonction dans laquelle elle a été définie. Vous pouvez donc être sûr qu'il conservera sa valeur inchangée jusqu'au prochain appel à cette fonction.

La variable statique ne peut être définie que comme scalaire ou comme expression scalaire (depuis PHP 5.6). Son assignation à d'autres valeurs entraîne inévitablement un échec au moins au moment de la rédaction de cet article. Néanmoins vous pouvez le faire simplement sur la ligne suivante de votre code:

function countSheep($num) {
  static $counter = 0;
  $counter += sqrt($num);//imagine we need to take root of our sheep each time
  echo "$counter sheep jumped over fence";
}

Résultat:

2 sheep jumped over fence
5 sheep jumped over fence
9 sheep jumped over fence

La fonction statique est un peu "partagée" entre les méthodes d'objets de la même classe. Il est facile à comprendre en consultant l'exemple suivant:

class SomeClass {
  public function foo() {
    static $x = 0;
    echo ++$x;
  }
}

$object1 = new SomeClass;
$object2 = new SomeClass;

$object1->foo(); // 1
$object2->foo(); // 2 oops, $object2 uses the same static $x as $object1
$object1->foo(); // 3 now $object1 increments $x
$object2->foo(); // 4 and now his twin brother

Cela ne fonctionne qu'avec des objets de la même classe. Si les objets appartiennent à différentes classes (même s’étendant les unes sur les autres), le comportement des vars statiques sera comme prévu.

La variable statique est-elle le seul moyen de conserver les valeurs entre les appels d'une fonction?

Une autre façon de conserver les valeurs entre les appels de fonction consiste à utiliser des fermetures. Les fermetures ont été introduites dans PHP 5.3. En deux mots, elles vous permettent de limiter l’accès à un ensemble de variables d’une portée de fonction à une autre fonction anonyme qui sera le seul moyen d’y accéder. les variables de fermeture peuvent imiter (avec plus ou moins de succès) OOP des concepts tels que 'constantes de classe' (si elles ont été passées dans fermeture par valeur) ou bien 'propriétés privées' (si passées par référence) en programmation structurée .

Ce dernier permet en fait d’utiliser des fermetures au lieu de variables statiques. Ce qu’il faut utiliser revient toujours au développeur qui décide, mais il convient de mentionner que les variables statiques sont certainement utiles lorsqu’on travaille avec des récurrences et méritent d’être remarquées par les développeurs.

10
alex_edev

Je ne publierai pas de réponse complète à la question, car celles qui existent déjà et le manuel PHP font un excellent travail en expliquant l'essentiel de cette question.

Mais un sujet qui a été oublié est celui de superglobals , y compris les $_POST, $_GET, $_SESSION, Etc. couramment utilisés. Ces variables sont des tableaux qui sont toujours disponibles, quelle que soit leur portée, sans déclaration global.

Par exemple, cette fonction affichera le nom de l'utilisateur exécutant le script PHP. La variable est disponible pour la fonction sans aucun problème.

<?php
function test() {
    echo $_ENV["user"];
}

La règle générale "les globaux sont mauvais" est généralement modifiée dans PHP à "les globaux sont mauvais mais les superglobales sont correctes", à condition de ne pas en abuser. (Toutes ces variables sont en écriture, afin qu'ils puissent être utilisés pour éviter l'injection de dépendance si vous étiez vraiment terrible.)

La présence de ces variables n’est pas garantie; un administrateur peut désactiver tout ou partie d'entre eux à l'aide de la directive variables_order dans php.ini, mais il ne s'agit pas d'un comportement courant.


Une liste des superglobales actuelles:

  • $GLOBALS - Toutes les variables globales du script actuel
  • $_SERVER - Informations sur le serveur et l'environnement d'exécution
  • $_GET - Valeurs transmises dans la chaîne de requête de l'URL, quelle que soit la méthode HTTP utilisée pour la demande.
  • $_POST - Valeurs transmises dans une requête HTTP POST avec les types application/x-www-form-urlencoded Ou multipart/form-data
  • $_FILES - Fichiers transmis dans une requête HTTP POST avec un type multipart/form-data
  • $_COOKIE - Cookies passés avec la demande en cours
  • $_SESSION - Variables de session stockées en interne par PHP
  • $_REQUEST - Généralement, une combinaison de $_GET Et de $_POST, Mais parfois $_COOKIES. Le contenu est déterminé par la directive request_order dans php.ini.
  • $_ENV - Les variables d'environnement du script actuel
1
miken32