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

25

UPDATE: Ma question initiale a été résolue, mais le débat est en train de devenir une discussion valide sur la raison de ne 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.

MISE À JOUR 2: Je le fais maintenant exactement ce que je voulais. Mais j'utilise toujours le champ d'application mondial et serais heureux de trouver un meilleur moyen.

J'essaie de configurer tout un ensemble de variables globales pour les liens permanents vers les catégories à utiliser à divers 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 l'article en cours. Ce n'est pas un thème que je vais aborder. être libéré 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 it 4 endroits qui vont et récupérer le lien complet pour le code. Lorsque cela change, je n’ai plus qu’à le changer. Je suis ouvert aux alternatives n'impliquant pas le champ d'application global.

    
posée JPollock 04.03.2013 - 07:23
la source

4 réponses

21

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

Lorsque vous essayez d'utiliser un mot clé global, vous devez d'abord spécifier le mot clé 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 n’est pas défini. Toutefois, cela fonctionnera :

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 des objets. Cela n'augmentera pas la vitesse (vous constaterez peut-être une faible diminution de la vitesse), vous obtiendrez une complexité supplémentaire et la nécessité de saisir de nombreuses déclarations globales inutiles.

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 avec des variables statiques (toujours mauvaises pour les mêmes raisons, mais un tout petit 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.

    
réponse donnée Tom J Nowell 04.03.2013 - 14:05
la source
18

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

Pourquoi ne pas utiliser les paramètres globaux

Parce que l'utilisation de globaux 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 un commentaire 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.
  • S'ils 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 la fonction.
  • Les globales n'ont pas de construction d'initialisation spécifique et vous ne pouvez donc jamais être sûr de pouvoir accéder à la valeur du global et vous n'obtiendrez aucune erreur lorsque vous tenterez d'accéder au global avant l'initialisation.
  • Quelqu'un d'autre (un plugin, par exemple) peut utiliser des globals portant le même nom, ruinant votre code, ou vous-même, en fonction de l'ordre d'initialisation.

Le noyau de WordPress a beaucoup trop utilisé les globals. En essayant de comprendre le fonctionnement de fonctions de base telles que the_content , vous réalisez soudainement que la variable $more n’est pas locale, mais globale. Vous devez donc rechercher dans l’ensemble des fichiers de base pour comprendre quand est-il défini sur true.

Alors, que peut-on faire en essayant d’arrêter de copier / coller 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;
}

L’avantage, c’est 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 la programmation orientée objet 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;

Ceci est un code plus maladroit, mais si vous souhaitez précalculer plusieurs valeurs car elles sont toujours utilisées, cela peut être une solution. Fondamentalement, il s’agit d’un objet contenant 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 (certaines personnes prétendent que c'est une mauvaise idée, YMMV)

Je n'aime pas accéder directement à un attribut d'objet. Par conséquent, dans mon code, il sera plus complexe

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);
    
réponse donnée Mark Kaplun 04.03.2013 - 08:09
la source
5

Votre question concerne le fonctionnement de php.

Prenez $ wpdb à titre d'exemple

$ wpdb est une variable globale bien connue.

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

Chaque page chargée , oui, 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. ça ne sera déclenché que lorsque le thème est activé.

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

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

    
réponse donnée Jesse 04.03.2013 - 10:04
la source
2

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
    
réponse donnée jgraup 25.11.2015 - 11:35
la source

Lire d'autres questions sur les étiquettes