web-dev-qa-db-fra.com

PHP global dans les fonctions

Quelle est l'utilité du mot-clé global ?

Y a-t-il des raisons de préférer une méthode à une autre?

  • Sécurité?
  • Performance?
  • Rien d'autre?

Méthode 1:

function exempleConcat($str1, $str2)
{
  return $str1.$str2;
}

Méthode 2:

function exempleConcat()
{
  global $str1, $str2;
  return $str1.$str2;
}

Quand est-il judicieux d'utiliser global?

Pour moi, cela semble être dangereux ... mais c'est peut-être juste un manque de connaissances. Je suis intéressé par des raisons techniques documentées (par exemple avec un exemple de code, un lien vers la documentation ...).

Merci d'avance!


Prime

Ceci est une belle question générale sur le sujet, je (@Gordon) offre une prime pour obtenir des réponses supplémentaires. Que votre réponse soit en accord avec la mienne ou donne un point de vue différent n'a pas d'importance. Puisque le sujet global revient de temps en temps, nous pourrions utiliser une bonne réponse "canonique" pour créer un lien vers.

98
Pascal Qyy

Les globaux sont mauvais

Cela est vrai pour le mot clé global ainsi que tout ce qui va d'une portée locale à la portée globale (statique, singletons, registres, constantes). Vous ne voulez pas les utiliser. Un appel de fonction ne devrait pas avoir à s'appuyer sur quoi que ce soit à l'extérieur, par exemple.

function fn()
{
    global $foo;              // never ever use that
    $a = SOME_CONSTANT        // do not use that
    $b = Foo::SOME_CONSTANT;  // do not use that unless self::
    $c = $GLOBALS['foo'];     // incl. any other superglobal ($_GET, …)
    $d = Foo::bar();          // any static call, incl. Singletons and Registries
}

Tout cela fera dépendre votre code de l'extérieur. Cela signifie que vous devez connaître l'état global complet de votre application avant de pouvoir appeler de manière fiable l'un de ces éléments. La fonction ne peut pas exister sans cet environnement.

L'utilisation des superglobaux n'est peut-être pas un défaut évident, mais si vous appelez votre code à partir d'une ligne de commande, vous n'avez pas $_GET Ou $_POST. Si votre code repose sur la saisie de ces informations, vous vous limitez à un environnement Web. Il suffit de résumer la demande dans un objet et de l'utiliser à la place.

En cas de couplage de noms de classes codés en dur (statiques, constantes), votre fonction ne peut pas non plus exister sans que cette classe soit disponible. C'est moins un problème lorsque ce sont des classes du même espace de noms, mais lorsque vous commencez à mélanger à partir d'espaces de noms différents, vous créez un désordre emmêlé.

La réutilisation est gravement entravée par tout ce qui précède. Il en va de même pour les tests unitaires .

En outre, vos signatures de fonction mentent lorsque vous vous connectez à la portée globale

function fn()

est un menteur, car il prétend que je peux appeler cette fonction sans rien lui passer. Ce n'est que lorsque je regarde le corps de la fonction que j'apprends que je dois mettre l'environnement dans un certain état.

Si votre fonction nécessite des arguments pour s'exécuter, rendez-les explicites et passez-les:

function fn($arg1, $arg2)
{
    // do sth with $arguments
}

indique clairement à partir de la signature ce dont elle a besoin pour être appelée. Il ne dépend pas de l'environnement d'être dans un état spécifique. Tu n'as pas à faire

$arg1 = 'foo';
$arg2 = 'bar';
fn();

Il s'agit de tirer (mot-clé global) vs pousser (arguments). Lorsque vous poussez/injectez des dépendances, la fonction ne dépend plus de l'extérieur. Lorsque vous faites fn(1) vous n'avez pas besoin d'avoir une variable contenant 1 quelque part à l'extérieur. Mais lorsque vous insérez global $one À l'intérieur de la fonction, vous vous associez à la portée globale et vous attendez à ce qu'elle ait une variable définie quelque part. La fonction n'est alors plus indépendante.

Pire encore, lorsque vous modifiez des globaux à l'intérieur de votre fonction, votre code sera rapidement complètement incompréhensible, car vos fonctions ont des effets secondaires partout.

Faute d'un meilleur exemple, envisager

function fn()
{
    global $foo;
    echo $foo;     // side effect: echo'ing
    $foo = 'bar';  // side effect: changing
}

Et puis tu fais

$foo = 'foo';
fn(); // prints foo
fn(); // prints bar <-- WTF!!

Il n'y a aucun moyen de voir que $foo A été modifié à partir de ces trois lignes. Pourquoi appeler la même fonction avec les mêmes arguments changerait-il soudainement sa sortie ou changerait une valeur dans l'état global? Une fonction doit faire X pour une entrée définie Y. Toujours.

Cela devient encore plus grave lorsque vous utilisez OOP, car OOP concerne l'encapsulation et en atteignant la portée globale, vous rompez l'encapsulation. Tous ces singletons et registres que vous voyez dans les frameworks sont des odeurs de code qui doit être supprimé en faveur de l'injection de dépendance. Découpez votre code.

Davantage de ressources:

154
Gordon

La seule raison majeure contre global est que cela signifie que la fonction dépend d'une autre portée. Cela deviendra très rapidement désordonné.

$str1 = 'foo';
$str2 = 'bar';
$str3 = exampleConcat();

vs.

$str = exampleConcat('foo', 'bar');

Requérant $str1 et $str2 à configurer dans la portée d'appel pour que la fonction fonctionne signifie que vous introduisez des dépendances inutiles. Vous ne pouvez plus renommer ces variables dans cette étendue sans les renommer également dans la fonction, et donc également dans toutes les autres étendues que vous utilisez cette fonction. Cela se transforme rapidement en chaos alors que vous essayez de garder une trace de vos noms de variables.

global est un mauvais schéma même pour inclure des choses globales telles que $db Ressources. Là viendra le jour où vous voulez renommer $db mais ne peut pas, car toute votre application dépend du nom.

Limiter et séparer la portée des variables est essentiel pour écrire une application complexe à mi-chemin.

35
deceze

Les globaux sont inévitables.

C'est une vieille discussion, mais je voudrais quand même ajouter quelques réflexions car elles me manquent dans les réponses mentionnées ci-dessus. Ces réponses simplifient ce qu'est trop un global et présentent des solutions qui ne sont pas du tout des solutions au problème. Le problème est: quelle est la bonne façon de traiter une variable globale et l'utilisation du mot-clé global? Pour cela, nous devons d'abord examiner et décrire ce qu'est un global.

Jetez un œil à ce code de Zend - et veuillez comprendre que je ne suggère pas que Zend soit mal écrit:

class DecoratorPluginManager extends AbstractPluginManager
{
/**
 * Default set of decorators
 *
 * @var array
 */
protected $invokableClasses = array(
    'htmlcloud' => 'Zend\Tag\Cloud\Decorator\HtmlCloud',
    'htmltag'   => 'Zend\Tag\Cloud\Decorator\HtmlTag',
    'tag'       => 'Zend\Tag\Cloud\Decorator\HtmlTag',
   );

Il y a beaucoup de dépendances invisibles ici. Ces constantes sont en fait des classes. Vous pouvez également voir require_once dans certaines pages de ce framework. Require_once est une dépendance globale, créant ainsi des dépendances externes. C'est inévitable pour un cadre. Comment pouvez-vous créer une classe comme DecoratorPluginManager sans beaucoup de code externe dont elle dépend? Il ne peut pas fonctionner sans beaucoup d'extras. En utilisant le framework Zend, avez-vous déjà modifié l'implémentation d'une interface? Une interface est en fait un global.

Une autre application utilisée à l'échelle mondiale est Drupal. Ils sont très préoccupés par la bonne conception, mais comme tout grand framework, ils ont beaucoup de dépendances externes. Jetez un œil aux globaux dans cette page:

/**
 * @file
 * Initiates a browser-based installation of Drupal.
 */

/**
 * Root directory of Drupal installation.
 */
define('DRUPAL_ROOT', getcwd());

/**
 * Global flag to indicate that site is in installation mode.
 */
define('MAINTENANCE_MODE', 'install');

// Exit early if running an incompatible PHP version to avoid fatal errors.
if (version_compare(PHP_VERSION, '5.2.4') < 0) {
  print 'Your PHP installation is too old. Drupal requires at least PHP 5.2.4. See the     <a     href="http://drupal.org/requirements">system requirements</a> page for more     information.';
  exit;
}

// Start the installer.
require_once DRUPAL_ROOT . '/includes/install.core.inc';
install_drupal();

Avez-vous déjà écrit une redirection vers la page de connexion? Cela change une valeur globale. (Et puis ne dites-vous pas 'WTF', que je considère comme une bonne réaction à une mauvaise documentation de votre application.) Le problème avec les globaux n'est pas qu'ils sont globaux, vous en avez besoin pour avoir une application significative. Le problème est la complexité de l'application globale qui peut en faire un cauchemar à gérer. Les sessions sont globales, $ _POST est un global, DRUPAL_ROOT est un global, le includes/install.core.inc 'est un global non modifiable. Il y a un grand monde en dehors de toute fonction requise pour laisser cette fonction faire son travail.

La réponse de Gordon est incorrecte, car il surestime l'indépendance d'une fonction et appeler une fonction un menteur simplifie à l'excès la situation. Les fonctions ne mentent pas et lorsque vous regardez son exemple, la fonction est mal conçue - son exemple est un bug. (Soit dit en passant, je suis d'accord avec cette conclusion qu'il faut découpler le code.) La réponse de deceze n'est pas vraiment une bonne définition de la situation. Les fonctions fonctionnent toujours dans un cadre plus large et son exemple est beaucoup trop simpliste. Nous conviendrons tous avec lui que cette fonction est complètement inutile, car elle renvoie une constante. Cette fonction est de toute façon mauvaise conception. Si vous voulez montrer que la pratique est mauvaise, veuillez fournir un exemple pertinent. Renommer des variables dans une application n'est pas un problème d'avoir un bon IDE (ou un outil). La question concerne la portée de la variable, pas la différence de portée avec la fonction. Il y a un le bon moment pour qu'une fonction remplisse son rôle dans le processus (c'est pourquoi elle est créée en premier lieu) et à ce moment-là peut-elle influencer le fonctionnement de l'application dans son ensemble, donc travailler également sur des variables globales. de xzyfer est une instruction sans argumentation. Les globaux sont tout aussi présents dans une application si vous avez des fonctions procédurales ou une conception OOP. Les deux manières suivantes de changer la valeur d'un global sont essentiellement les mêmes:

function xzy($var){
 global $z;
 $z = $var;
}

function setZ($var){
 $this->z = $var;
}

Dans les deux cas, la valeur de $ z est modifiée dans une fonction spécifique. Dans les deux sens de la programmation, vous pouvez effectuer ces modifications dans un tas d'autres endroits du code. Vous pourriez dire qu'en utilisant global, vous pouvez appeler $ z n'importe où et y changer. Oui, vous pouvez. Mais voulez-vous? Et lorsque cela est fait dans des endroits inappropriés, ne devrait-il pas alors être appelé un bug?

Bob Fanger commente xzyfer.

Quelqu'un devrait-il alors simplement utiliser quoi que ce soit et en particulier le mot-clé "global"? Non, mais comme tout type de conception, essayez d'analyser ce dont cela dépend et ce qui en dépend. Essayez de savoir quand il change et comment il change. La modification des valeurs globales ne doit se produire qu'avec les variables qui peuvent changer à chaque demande/réponse. C'est-à-dire uniquement aux variables qui appartiennent au flux fonctionnel d'un processus, pas à sa mise en œuvre technique. La redirection d'une URL vers la page de connexion appartient au flux fonctionnel d'un processus, la classe d'implémentation utilisée pour une interface vers l'implémentation technique. Vous pouvez modifier ce dernier au cours des différentes versions de l'application, mais ne devez pas les modifier à chaque demande/réponse.

Pour mieux comprendre quand c'est un problème de travailler avec les globaux et le mot-clé global et quand je ne vais pas introduire la phrase suivante, qui vient de Wim de Bie lors de l'écriture sur les blogs: 'Personnel oui, privé non'. Lorsqu'une fonction modifie la valeur d'une variable globale dans l'intérêt de son propre fonctionnement, alors j'appellerai cette utilisation privée d'une variable globale et un bug. Mais lorsque le changement de la variable globale est effectué pour le bon traitement de l'application dans son ensemble, comme la redirection de l'utilisateur vers la page de connexion, alors c'est à mon avis peut-être une bonne conception, pas par définition mauvaise et certainement pas un anti-motif.

Rétrospectivement aux réponses de Gordon, deceze et xzyfer: ils ont tous des "oui privés" (et des bugs) comme exemples. C'est pourquoi ils s'opposent à l'utilisation des mondiaux. Je le ferais aussi. Cependant, ils ne sont pas accompagnés d'exemples de "oui personnel, non privé" comme je l'ai fait plusieurs fois dans cette réponse.

34
Loek Bergman

Autrement dit, il y a rarement une raison à global et jamais une bonne dans le code moderne PHP IMHO. Surtout si vous utilisez PHP 5. Et spécialement si vous développez du code orienté objet.

Les globaux affectent négativement la maintenabilité, la lisibilité et la testabilité du code. De nombreuses utilisations de global peuvent et doivent être remplacées par l'injection de dépendances ou simplement en passant l'objet global comme paramètre.

function getCustomer($db, $id) {
    $row = $db->fetchRow('SELECT * FROM customer WHERE id = '.$db->quote($id));
    return $row;
}
14
xzyfer

N'hésitez pas à utiliser le mot-clé global à l'intérieur des fonctions en PHP. Surtout ne prenez pas les gens qui prêchent/crient bizarrement à quel point les globaux sont "mauvais" et ainsi de suite.

Premièrement, parce que ce que vous utilisez dépend totalement de la situation et du problème, et il n'y a AUCUNE solution/façon de faire quoi que ce soit dans le codage. Laissant totalement de côté la fausseté d'adjectifs religieux, subjectifs et indéfinissables comme le "mal" dans l'équation.

Exemple concret:

Wordpress et son écosystème utilisent un mot-clé global dans leurs fonctions. Soyez le code OOP ou pas OOP.

Et à partir de maintenant Wordpress représente essentiellement 18,9% d'Internet, et il gère les énormes mégasites/applications d'innombrables géants allant de Reuters à Sony, au NYT, à CNN.

Et ça le fait bien.

L'utilisation du mot-clé global à l'intérieur des fonctions libère Wordpress de MASSIVE bloat qui se produirait étant donné son énorme écosystème. Imaginez que chaque fonction demandait/passait toute variable nécessaire à partir d'un autre plugin, noyau et retour. Ajouté avec des interdépendances de plugin, qui finiraient dans un cauchemar de variables, ou un cauchemar de tableaux passés en tant que variables. UN ENFER à suivre, un enfer à déboguer, un enfer à développer. Plus difficile à écrire aussi.

Il peut y avoir des gens qui critiquent Wordpress, son écosystème, leurs pratiques et ce qui se passe dans ces régions.

Inutile, car cet écosystème représente à peu près 20% d'Internet à peu près entier. Apparemment, il fonctionne, il fait son travail et plus encore. Ce qui signifie la même chose pour le mot-clé global.

Un autre bon exemple est le fondamentalisme "les iframes sont mauvais". Il y a dix ans, c'était une hérésie d'utiliser des iframes. Et il y avait des milliers de personnes qui prêchaient contre eux sur Internet. Vient ensuite Facebook, puis social, maintenant les iframes sont partout, des boîtes "J'aime" à l'authentification, et le tour est joué - tout le monde se tait. Il y a ceux qui ne se sont toujours pas tus - à tort ou à raison. Mais vous savez quoi, la vie continue malgré de telles opinions, et même ceux qui prêchaient contre les iframes il y a une décennie doivent maintenant les utiliser pour intégrer diverses applications sociales aux applications de leur organisation sans dire un mot.

......

Le fondamentalisme des codeurs est quelque chose de très, très mauvais. Un petit pourcentage d'entre nous peut être honoré par le travail confortable dans une entreprise monolithique solide qui a suffisamment d'influence pour supporter le changement constant des technologies de l'information et les pressions qu'il exerce en matière de concurrence, de temps, de budget et d'autres considérations, et peut donc pratiquer l'intégrisme et le strict respect des "maux" ou des "biens" perçus. Des positions confortables qui rappellent la vieillesse, même si les occupants sont jeunes.

Pour la majorité cependant, le i.t. Le monde est un monde en constante évolution dans lequel ils doivent être ouverts d'esprit et pratiques. Il n'y a pas de place pour l'intégrisme, laissez de côté des mots-clés scandaleux comme "mal" dans les tranchées de première ligne des technologies de l'information.

Utilisez simplement ce qui a le plus de sens pour le problème AT HAND, avec des considérations appropriées pour un avenir à court, moyen et long terme. Ne pas hésiter à utiliser une fonctionnalité ou une approche car elle a une idéologie rampante animosité contre elle, parmi tout sous-ensemble de codeurs donné.

Ils ne feront pas votre travail. Vous serez. Agissez en fonction de votre situation.

8
unity100

Cela n'a aucun sens de créer une fonction de concaténation à l'aide du mot-clé global.

Il est utilisé pour accéder à des variables globales telles qu'un objet de base de données.

Exemple:

function getCustomer($id) {
  global $db;
  $row = $db->fetchRow('SELECT * FROM customer WHERE id = '.$db->quote($id));
  return $row;
}

Il peut être utilisé comme une variation sur le modèle Singleton

6
Bob Fanger

Je pense que tout le monde a à peu près exposé les aspects négatifs des mondiaux. J'ajouterai donc les points positifs ainsi que des instructions pour une bonne utilisation des globaux:

  1. Le but principal des globaux était de partager des informations entre les fonctions. à l'époque où il n'y avait rien de tel qu'une classe, le code php consistait en un tas de fonctions. Parfois, vous devrez partager des informations entre les fonctions. Généralement, le global était utilisé pour ce faire avec le risque de corrompre les données en les rendant globales.

    Maintenant, avant qu'un simple bonjour chanceux simpleton ne commence un commentaire sur l'injection de dépendances, je voudrais vous demander comment l'utilisateur d'une fonction comme l'exemple get_post(1) connaîtrait toutes les dépendances de la fonction. Considérez également que les dépendances peuvent différer de
    version à version et serveur à serveur. Le principal problème avec l'injection de dépendances est que les dépendances doivent être connues à l'avance. Dans une situation où cela n'est pas possible ou des variables globales indésirables étaient le seul moyen d'atteindre cet objectif.

    En raison de la création de la classe, les fonctions courantes peuvent désormais être facilement regroupées dans une classe et partager des données. Grâce à des implémentations comme des médiateurs, même des objets non liés peuvent partager des informations. Ce n'est plus necessaire.

  2. Une autre utilisation pour les globaux est à des fins de configuration. Surtout au début d'un script avant le chargement des chargeurs automatiques, les connexions à la base de données, etc.

    Pendant le chargement des ressources, les globaux peuvent être utilisés pour configurer les données (c'est-à-dire quelle base de données utiliser où se trouvent les fichiers de bibliothèque, l'url du serveur, etc.). La meilleure façon de le faire est d'utiliser la fonction define() car ces valeurs ne changeront pas souvent et peuvent facilement être placées dans un fichier de configuration.

  3. L'utilisation finale pour les globaux est de conserver des données communes (c'est-à-dire CRLF, IMAGE_DIR, IMAGE_DIR_URL), des indicateurs d'état lisibles par l'homme (c'est-à-dire ITERATOR_IS_RECURSIVE). Ici, les globaux sont utilisés pour stocker des informations destinées à être utilisées à l'échelle de l'application, ce qui permet de les modifier et de faire apparaître ces modifications à l'échelle de l'application.

  4. Le modèle singleton est devenu populaire en php pendant php4 lorsque chaque instance d'un objet a pris de la mémoire. Le singleton a aidé à enregistrer la mémoire RAM en autorisant la création d'une seule instance d'un objet. Avant les références, même l'injection de dépendance aurait été une mauvaise idée.

    La nouvelle implémentation php des objets de PHP 5.4+ s'occupe de la plupart de ces problèmes, vous pouvez passer des objets en toute sécurité avec peu ou pas de pénalité. Ce n'est plus nécessaire.

    Une autre utilisation des singletons est l'instance spéciale où une seule instance d'un objet doit exister à la fois, cette instance peut exister avant/après l'exécution du script et cet objet est partagé entre différents scripts/serveurs/langues, etc. Ici, un modèle singleton résout les assez bien.

Donc, en conclusion, si vous êtes en position 1, 2 ou 3, l'utilisation d'un global serait raisonnable. Cependant, dans d'autres situations, la méthode 1 doit être utilisée.

N'hésitez pas à mettre à jour toutes les autres instances où les globaux doivent être utilisés.

6
mAsT3RpEE