web-dev-qa-db-fra.com

Les variables globales dans PHP sont-elles considérées comme une mauvaise pratique? Si oui, pourquoi?

function foo () {
    global $var;
    // rest of code
}

Dans mes petits projets PHP je prends habituellement la voie procédurale. J'ai généralement une variable qui contient la configuration du système, et quand je veux accéder à cette variable dans une fonction, je fais global $var;.

Est-ce une mauvaise pratique?

84
KRTac

Lorsque les gens parlent de variables globales dans d'autres langages, cela signifie quelque chose de différent de ce qu'il fait en PHP. C'est parce que les variables ne sont pas vraiment globales en PHP. La portée d'un programme PHP est une requête HTTP. Les variables de session ont en fait une portée plus large que PHP les variables "globales" car elles englobent généralement de nombreuses requêtes HTTP) .

Souvent (toujours?), Vous pouvez appeler des fonctions membres dans des méthodes comme preg_replace_callback() comme ceci:

preg_replace_callback('!pattern!', array($obj, 'method'), $str);

Voir rappels pour en savoir plus.

Le fait est que les objets ont été boulonnés sur PHP et, à certains égards, conduisent à une certaine maladresse.

Ne vous préoccupez pas trop d'appliquer des normes ou des constructions de différents langages à PHP. Un autre écueil courant est d'essayer de transformer PHP en un pur langage OOP) en collant des modèles d'objets au-dessus de tout.

Comme toute autre chose, utilisez des variables "globales", du code procédural, un cadre particulier et OOP parce que cela a du sens, résout un problème, réduit la quantité de code que vous avez besoin d'écrire ou le rend plus maintenable et plus facile à comprendre, pas parce que vous pensez que vous devriez.

98
cletus

Les variables globales, si elles ne sont pas utilisées avec précaution, peuvent rendre les problèmes plus difficiles à trouver. Supposons que vous demandiez un script php et que vous obteniez un avertissement disant que vous essayez d'accéder à un index d'un tableau qui n'existe pas dans une fonction.

Si le tableau auquel vous essayez d'accéder est local à la fonction, vous vérifiez la fonction pour voir si vous y avez fait une erreur. Il peut s'agir d'un problème avec une entrée de la fonction, vous devez donc vérifier les endroits où la fonction est appelée.

Mais si ce tableau est global, vous devez vérifier tous les endroits où vous utilisez cette variable globale, et pas seulement cela, vous devez déterminer dans quel ordre ces références à la variable globale sont accessibles.

Si vous avez une variable globale dans un morceau de code, il est difficile d'isoler la fonctionnalité de ce code. Pourquoi voudriez-vous isoler des fonctionnalités? Vous pouvez donc le tester et le réutiliser ailleurs. Si vous avez du code que vous n'avez pas besoin de tester et que vous n'aurez pas besoin de réutiliser, l'utilisation de variables globales est très bien.

27
rojoca

je suis d'accord avec cletus. j'ajouterais deux choses:

  1. utilisez un préfixe pour pouvoir l'identifier immédiatement comme global (par exemple $ g_)
  2. déclarez-les au même endroit, ne les saupoudrez pas tout autour du code.

cordialement, Don

16
Don Dickinson

Qui peut contester l'expérience, les diplômes universitaires et le génie logiciel? Pas moi. Je dirais seulement qu'en développant une seule page orientée objet PHP applicatons, je m'amuse plus quand je sais que je peux construire le tout à partir de zéro sans se soucier des collisions d'espace de noms. Construire à partir de zéro est quelque chose beaucoup de gens n'en font plus. Ils ont un travail, une échéance, un bonus ou une réputation à se soucier. Ces types ont tendance à utiliser tellement de code pré-construit avec des enjeux élevés, qu'ils ne peuvent pas risquer du tout d'utiliser des variables globales.

Il peut être mauvais d'utiliser des variables globales, même si elles ne sont utilisées que dans la zone globale d'un programme, mais n'oublions pas ceux qui veulent juste s'amuser et faire fonctionner quelque chose.

Si cela signifie utiliser quelques variables (<10) dans l'espace de noms global, qui ne sont utilisées que dans la zone globale d'un programme, qu'il en soit ainsi. Oui, oui, MVC, injection de dépendances, code externe, bla, bla, bla, bla. Mais, si vous avez contenu 99,99% de votre code dans des espaces de noms et des classes, et que le code externe est en bac à sable, le monde ne se terminera pas (je le répète, le monde ne se terminera pas) si vous utilisez une variable globale.

En général, je ne dirais pas que l'utilisation de variables globales est mauvaise pratique. Je dirais que l'utilisation de variables globales (drapeaux et autres) en dehors de la zone globale d'un programme est demander des ennuis et (à long terme) peu judicieux parce que vous peuvent perdre la trace de leurs états assez facilement. De plus, je dirais que plus vous en apprendrez, moins vous serez dépendant sur les variables globales car vous aurez eu la "joie" de retrouver les bogues associés à leur utilisation. Cela seul vous incitera à trouver un autre moyen de résoudre le même problème. Par coïncidence, cela tend à pousser PHP personnes dans le sens d'apprendre à utiliser les espaces de noms et les classes (membres statiques, etc ...).

Le domaine de l'informatique est vaste. Si nous effrayons tout le monde de faire quelque chose parce que nous l'étiquetons mauvais, alors ils perdent le plaisir de vraiment comprendre le raisonnement derrière l'étiquette.

Utilisez des variables globales si vous le devez, mais voyez si vous pouvez résoudre le problème sans elles. Les collisions, les tests et le débogage signifient plus lorsque vous comprenez intimement la vraie nature du problème, pas seulement une description du problème.

5
Anthony Rutledge

Republié à partir de la fin SO Documentation Beta

Nous pouvons illustrer ce problème avec le pseudo-code suivant

function foo() {
     global $bob;
     $bob->doSomething();
}

Votre première question ici est évidente

D'où $bob Vient-il?

Êtes-vous confus? Bien. Vous venez d'apprendre pourquoi les mondiaux sont déroutants et considérés comme une mauvaise pratique. S'il s'agissait d'un vrai programme, votre prochain plaisir est de retrouver toutes les instances de $bob Et j'espère que vous trouverez le bon (cela empire si $bob Est utilisé partout). Pire, si quelqu'un d'autre va définir $bob (Ou si vous avez oublié et réutilisé cette variable) votre code peut casser (dans l'exemple de code ci-dessus, avoir le mauvais objet, ou aucun objet du tout, provoquerait une erreur fatale ). Étant donné que pratiquement tous les programmes PHP utilisent du code comme include('file.php'); votre travail de maintenance de code comme celui-ci devient exponentiellement plus difficile à mesure que vous ajoutez de fichiers.

Comment éviter les globaux?

La meilleure façon d'éviter les globaux est une philosophie appelée Injection de dépendance. C'est là que nous transmettons les outils dont nous avons besoin à la fonction ou à la classe.

function foo(\Bar $bob) {
    $bob->doSomething();
}

C'est beaucoup plus facile à comprendre et à maintenir. Il n'est pas possible de deviner où $bob A été configuré car l'appelant est responsable de le savoir (il nous transmet ce que nous devons savoir). Mieux encore, nous pouvons utiliser déclarations de type pour restreindre ce qui est passé. Nous savons donc que $bob Est soit une instance de la classe Bar, soit une instance d'un enfant de Bar, ce qui signifie que nous savons que nous pouvons utiliser les méthodes de cette classe. Combiné avec un chargeur automatique standard (disponible depuis PHP 5.3), nous pouvons maintenant rechercher où Bar est défini. PHP 7.0 ou version ultérieure) inclut des déclarations de type développées, où vous pouvez également utiliser des types scalaires (comme int ou string).

2
Machavity

Comme:

global $my_global; 
$my_global = 'Transport me between functions';
Equals $GLOBALS['my_global']

est une mauvaise pratique (comme Wordpress $pagenow) ... hmmm

Considérez ceci:

$my-global = 'Transport me between functions';

est PHP Mais:

$GLOBALS['my-global'] = 'Transport me between functions';

est PAS erreur, les hypens ne se heurteront pas avec les variables déclarées par l'utilisateur "communes" , comme $pagenow. Et l'utilisation de UPPERCASE indique un superglobal en cours d'utilisation, facile à repérer dans le code ou à suivre avec trouver dans les fichiers

J'utilise des tirets, si je suis paresseux pour créer des classes de tout pour une seule solution, comme:

$GLOBALS['PREFIX-MY-GLOBAL'] = 'Transport me ... ';

Mais dans les cas d'une utilisation plus large, j'utilise UN globaux comme tableau:

$GLOBALS['PREFIX-MY-GLOBAL']['context-something'] = 'Transport me ... ';
$GLOBALS['PREFIX-MY-GLOBAL']['context-something-else']['numbers'][] = 'Transport me ... ';

Ce dernier est pour moi, une bonne pratique sur les objectifs "cola light" ou à utiliser, au lieu d'encombrer à chaque fois les classes singleton pour "mettre en cache" certaines données. Veuillez faire un commentaire si je me trompe ou s'il manque quelque chose de stupide ici ...

0
Jonas Lundman