web-dev-qa-db-fra.com

Comment définir et utiliser des variables globales? Ou pourquoi ne pas les utiliser du tout

MISE À JOUR: / Ma question initiale a été résolue, mais cela se transforme en une discussion valable sur la raison pour laquelle il ne faut pas utiliser de variables globales. Je suis donc en train de mettre à jour la question pour refléter cela. La solution était <?php global $category_link_prop; echo esc_url( $category_link_prop ); ?>, comme suggéré par @TomJNowell.

UPDATE 2: Je l'ai maintenant faire exactement ce que je voulais. Mais j'utilise toujours la portée mondiale et serais heureux de trouver un meilleur moyen.

J'essaie de mettre en place toute une série de variables globales pour les liens permanents aux catégories à utiliser à différents endroits de mon thème. La raison principale en est l'utilisation dans la navigation principale, ainsi que dans une série de sous-navigations choisies en fonction de la catégorie dans laquelle se trouve la publication actuelle. Ce n'est pas un thème que je vais aborder libérer pour une utilisation par d'autres, mais est construit pour un but très spécifique.

C’est ainsi que je les crée actuellement (je n’ai collé que dans quelques-unes des variables).

function set_global_nav_var()
{
    //proposal
    global $prop;
    // Get the ID of a given category
    $category_id_prop = get_cat_ID( 'proposal' );
    // Get the URL of this category
    $category_link_prop = get_category_link( $category_id_prop );
    $prop = '<a href="' .esc_url( $category_link_prop ). '" title="Proposal">Proposal</a>';

    //Calvinball
    global $cb;
    // Get the ID of a given category
    $category_id_cb = get_cat_ID( 'calvinball' );
    // Get the URL of this category
    $category_link_cb = get_category_link( $category_id_cb );
    $cb = '<a href="' .esc_url( $category_link_cb). '" title="Calvinball">Calvinball</a>';
}
add_action( 'init', 'set_global_nav_var' );

Je peux maintenant faire <?php global $prop; echo $prop; ?> int il 4 endroits qui vont et récupérer le lien entier pour le code. Lorsque cela change, je n’ai plus qu’à le changer. Je suis ouvert aux alternatives qui n'impliquent pas la portée globale.

27
JPollock

Bien que je déconseille fortement cela, et que cela ne va pas accélérer les choses, votre utilisation est incorrecte.

Lorsque vous essayez d'utiliser un global, vous devez d'abord spécifier le mot clé global. Vous l'avez spécifié ici lors de la définition de sa valeur, mais en dehors de cette portée, il doit être redéclaré en tant que variable de portée globale.

par exemple. dans functions.php:

function test() {
    global $hello;
    $hello = 'hello world';
}
add_action( 'after_theme_setup', 'test' );

Dans single.php, cela ne fonctionnera pas:

echo $hello;

Parce que $ hello est indéfini. Ceci cependant fonctionnera travaillera:

global $hello;
echo $hello;

Bien sûr, vous ne devriez faire ni l'un ni l'autre. WordPress tente déjà de mettre ces objets en cache dans le cache d'objets. Cela n'augmentera pas la vitesse (vous constaterez peut-être une faible diminution de la vitesse), tout ce que vous obtiendrez sera une complexité supplémentaire et la nécessité de taper un grand nombre de déclarations globales non nécessaires.

Vous feriez mieux d'utiliser des données structurées, telles que des objets ou une injection de dépendance, ou dans votre cas, un ensemble de fonctions.

Par exemple, voici un moyen de faire quelque chose de similaire via des variables statiques (toujours mauvaises pour les mêmes raisons, mais un peu moins, et plus faciles à taper), par exemple.

function awful_function( $new_hello='' ) {
    static $hello;
    if ( !empty( $new_hello ) ) {
        $hello = $new_hello;
    }
    return $hello;
}

awful_function( 'telephone' );
echo awful_function(); // prints telephone
awful_function( 'banana');
echo awful_function(); // prints banana

Si vous voulez vraiment gagner du temps en stockant les données à réutiliser, envisagez d’utiliser le système WP_Cache avec wp_cache_get etc.

21
Tom J Nowell

N'utilisez pas de variables globales , aussi simple que cela.

Pourquoi ne pas utiliser globals

Parce que l'utilisation de globals rend plus difficile la maintenance du logiciel à long terme.

  • Un global peut être déclaré n'importe où dans le code, ou nulle part, il n'y a donc aucun endroit où vous pouvez instinctivement regarder pour trouver des commentaires sur l'utilisation du global.
  • Lors de la lecture du code, vous supposez généralement que les variables sont locales à la fonction et vous ne comprenez pas que le fait de modifier leur valeur dans une fonction peut avoir une incidence sur l'ensemble du système.
  • Si elles ne gèrent pas les entrées, les fonctions doivent renvoyer la même valeur/sortie lorsqu'elles sont appelées avec les mêmes paramètres. L'utilisation de globaux dans une fonction introduit des paramètres supplémentaires qui ne sont pas documentés dans la déclaration de fonction.
  • les globales n'ont pas de structure d'initialisation spécifique et vous ne pouvez donc jamais être sûr de pouvoir accéder à la valeur du global et vous n'obtenez aucune erreur lorsque vous essayez d'accéder au global avant l'initialisation.
  • Quelqu'un d'autre (un plugin peut-être) peut utiliser des globales portant le même nom, ruinant votre code, ou vous détruisant en fonction de l'ordre d'initialisation.

Le noyau WordPress a beaucoup trop recours aux globals. Tout en essayant de comprendre le fonctionnement de fonctions de base telles que the_content, vous réalisez soudain que la variable $more n’est pas locale, mais globale. Vous devez donc rechercher l’ensemble des fichiers de base pour comprendre quand elle est définie sur true.

Alors, que peut-on faire en essayant d’arrêter de copier-coller de plusieurs lignes de code au lieu de stocker le résultat de la première exécution dans un résultat global? Il existe plusieurs approches, fonctionnelle et POO.

La fonction édulcorant. C’est simplement un wrapper/macro pour sauvegarder le copier/coller

// input: $id - the category id
// returns: the foo2 value of the category
function notaglobal($id) {
  $a = foo1($id);
  $b = foo2($a);
  return $b;
}

Les avantages sont qu’il existe désormais une documentation sur ce que fait l’ancien global et que vous avez un intérêt évident à déboguer lorsque la valeur renvoyée n’est pas celle que vous attendez.

Une fois que vous avez un édulcorant, il est facile de mettre en cache le résultat si nécessaire (ne le faites que si vous découvrez que l'exécution de cette fonction prend beaucoup de temps)

function notaglobal($id) {
  static $cache;

  if (!isset($cache)) {
    $a = foo1($id);
    $b = foo2($a);
    $cache = $b;
  } 
  return $cache;
} 

Cela vous donne le même comportement qu'un global mais avec l'avantage d'avoir une initialisation assurée à chaque fois que vous y accédez.

Vous pouvez avoir des modèles similaires avec la POO. Je trouve que OOP n'ajoute généralement aucune valeur aux plugins et aux thèmes, mais il s'agit d'une discussion différente.

class notaglobal {
   var latestfoo2;

   __constructor($id) {
     $a = foo1($id);
     $this->latestfoo2 = foo2($a)
   }
}

$v = new notaglobal($cat_id);
echo $v->latestfoo2;

C'est un code plus maladroit, mais si vous souhaitez précalculer plusieurs valeurs parce qu'elles sont toujours utilisées, cela peut être une solution. Fondamentalement, il s'agit d'un objet qui contient tous vos globals de manière organisée. Pour éviter de rendre une instance de cet objet globale (vous voulez une instance sinon vous recalculez les valeurs), vous pouvez utiliser un modèle singleton pattern (certaines personnes soutiennent que c'est une mauvaise idée, YMMV).

Je n'aime pas accéder directement à un attribut d'objet, donc dans mon code, il va se déformer davantage

class notaglobal {
   var latestfoo2;

   __constructor() {}

   foo2($id) {  
     if (!isset($this->latestfoo2)) {    
       $a = foo1($id);
       $b = foo2($a);
       $this->latestfoo2= $b;
     } 
     return $this->latestfoo2;
   }
}

$v = new notaglobal();
echo $v->foo2($cat_id);
19
Mark Kaplun

Votre question concerne le fonctionnement de php.

Prenons $ wpdb par exemple

$ wpdb est une variable globale bien connue.

Savez-vous quand il sera déclaré et attribué avec des valeurs?

Chaque page chargée , ouais, chaque fois que vous visitez votre site wordpress.

De même, vous devez vous assurer que les variables à globaliser seront déclarées et affectées avec les valeurs correspondantes à chaque page chargée.

Bien que je ne sois pas un concepteur de thème, je peux dire que after_setup_theme est un crochet unique. il ne sera déclenché que lorsque le thème sera activé.

Si j'étais vous, j'utiliserais init ou d'autres hooks. Non, si j'étais vous, je n'utiliserai pas de variables globales ...

Je ne suis vraiment pas bon pour expliquer les choses. Vous devriez donc choisir un livre si vous voulez explorer PHP.

6
Jesse

Vous pouvez toujours utiliser un motif singleton via des accesseurs statiques.

<ul>
    <li><?php echo MyGlobals::get_nav_prop( 'proposal' )[ 'html' ]; ?></li>
    <li><?php echo MyGlobals::get_nav_prop( 'calvinball', 'html' ); ?></li>
</ul>


<?php

if ( ! class_exists('MyGlobals') ):

class MyGlobals {

    public $props;

    public function __construct(){
      $this->props = array (
        'proposal' => array( 'title' => 'Proposal', 'text' => 'Proposal' ),
        'calvinball' => array( 'title' => 'Calvinball', 'text' => 'Calvinball' ),
      );
    }

    public function get_nav_prop ( $term, $prop = false )
    {
      $o = self::instance();
      if ( ! isset( $o->props[$term] ) ) {  return falst; }
      if ( ! isset( $o->props[$term][ 'html' ] ) ) {
          $id = get_cat_ID( $term );
          $link = esc_url ( get_category_link( $id ) );
          $title = $o->props[$term]['title'];
          $text = $o->props[$term]['text'];
          $o->props[$term]['html'] = '<a href="'.$link.'" title="'.$title.'">'.$text.'</a>';
          $o->props[$term]['link'] = $link;
          $o->props[$term]['id'] = $id;
      }

      if($prop){ return isset($o->props[$term][$prop]) ? $o->props[$term][$prop] : null; }

      return $o->props[$term];
    }

    // -------------------------------------

    private static $_instance;

    public static function instance(){

      if(!isset(self::$_instance)) {
        self::$_instance = new MyGlobals();
      }
      return self::$_instance;
    }

}

endif; // end MyGlobals
2
jgraup