Come impostare e utilizzare le variabili globali? O perché non usarli affatto


27

AGGIORNAMENTO: La mia domanda originale è stata risolta, ma questo si sta trasformando in una discussione valida sul perché non usare le variabili globali, quindi sto aggiornando la domanda per riflettere ciò. La soluzione era <?php global $category_link_prop; echo esc_url( $category_link_prop ); ?>come suggerito da @TomJNowell.

AGGIORNAMENTO 2: Ora ho fatto esattamente quello che volevo. Ma sto ancora usando l'ambito globale e sarei felice di trovare un modo migliore.

Sto cercando di impostare un sacco di variabili globali per i permalink alle categorie da utilizzare in vari punti del mio tema. Il motivo principale di ciò è da utilizzare sia nella navigazione principale, sia in una serie di navigazioni secondarie scelte in base alla categoria in cui si trova il post corrente. Questo non è un tema che rilascerò per l'uso da parte di altri, ma è costruito per uno scopo molto specifico.

Ecco come li sto attualmente creando (ho incollato solo alcune variabili).

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' );

Ora posso fare in <?php global $prop; echo $prop; ?>4 posti che vanno e recuperare l'intero link per il codice. Quando ciò cambia, devo solo cambiarlo in un posto. Sono aperto a alternative che non coinvolgono l'ambito globale.


1
Quale link contiene questa istruzione echo esc_url ($ category_link_prop); visualizza? Qual è il tuo link previsto?
Vinod Dalvi

1
Perché non dovresti usare 'get_cat_ID (****)' dove mai hai pianificato di usare la variabile globale. Dubito che ci sarebbe qualche vantaggio di velocità nel modo in cui lo fai. Dal punto di vista della leggibilità, 'get_cat_ID (****)' vince a mani basse.
Chris Strutton,

1
Puoi riformulare? Ho letto la tua domanda e non sono ancora sicuro di cosa tu voglia fare e perché tu voglia farlo. Il mio consiglio generale sarebbe di non usare le variabili globali e di non inquinare l'ambito globale
Tom J Nowell

1
questo suona un po 'come un X / Y problema . forse dovresti eseguire il backup e spiegare esattamente quale sia il risultato desiderato. Sono certo che ci sia una soluzione molto più elegante che impostare un gruppo di variegati globali per poi solo hardcodificare i riferimenti ad essi in una nav altrove
Milo

2
creare una funzione che emetta il menu in base al contesto che si passa ad esso, in questo modo è possibile mantenere tutta la logica del menu e le variabili associate incapsulate in un unico posto.
Milo

Risposte:


21

Anche se sconsiglio vivamente questo e non accelererà le cose, il tuo utilizzo non è corretto.

Quando si tenta di utilizzare un globale, è necessario specificare prima la parola chiave globale. È stato specificato qui quando si definisce il suo valore, ma al di fuori di tale ambito deve essere dichiarato nuovamente come variabile di ambito globale.

ad es. in Functions.php:

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

In single.php, questo non funzionerà:

echo $hello;

Perché $ hello non è definito. Questo però sarà funzionerà:

global $hello;
echo $hello;

Ovviamente non dovresti fare nessuno dei due. WordPress tenta già di memorizzare queste cose nella cache degli oggetti. In questo modo non vedrai aumentare la velocità (potresti vedere una leggera diminuzione della velocità), tutto ciò che otterrai sarà ulteriore complessità e la necessità di scrivere molte dichiarazioni globali che non sono necessarie.

Sarebbe meglio usare dati strutturati, come oggetti o iniezione di dipendenza, o nel tuo caso, un insieme di funzioni.

Ad esempio, ecco un modo per fare qualcosa di simile tramite variabili statiche (ancora male per gli stessi motivi, ma solo un po 'meno e più facile da digitare) ad es.

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

Se vuoi davvero risparmiare tempo archiviando i dati da qualche parte per riutilizzarli, considera l'utilizzo del WP_Cachesistema con wp_cache_getecc


So che è un po 'matto usare l'ambito globale, ma la maggior parte, se non tutte, queste variabili verranno utilizzate su ogni pagina. Sono aperto a idee migliori. Ho intenzione di modificare la domanda per rendere il mio intento un po 'più chiaro. A proposito, funziona perfettamente quando faccio <?php global $category_link_prop; echo esc_url( $category_link_prop ); ?>come da tuo suggerimento. Grazie!
JPollock

2
Ah, se la mia soluzione funziona, potresti contrassegnarla come accettata? Le tue variabili globali sono veloci come effettuare la chiamata originale, potresti provare invece a utilizzare le funzioni, quindi non è necessario digitare 2 righe, meglio ancora, un singleton, meglio ancora, rendere tutto ciò dinamico e in un parte del modello inclusa tramite get_template_part
Tom J Nowell

Contrassegnato come accettato come quello che sto facendo ora, anche se potrei seguire una delle strategie suggerite da @MarkKaplun di seguito. L'uso di get_template_part () è un'idea interessante, ma non sono sicuro di voler avere una directory piena di file brevi come quello ...
JPollock

oooh no no non vorresti un file per ogni categoria, vorresti solo quello che prende il nome della categoria corrente e lo usa. Non dovresti hardcodificare nulla, immagina la seccatura di hardcoding tutto
Tom J Nowell

Ho inserito il codice nel mio child-Functions.php che è attivo. Ma non riesco ad accedere alla variabile in un file php-include che chiamo da un post "normale" generato dal database. Per favore avvisami, cosa devo fare di sbagliato? (Lo definisco globale, ovviamente.)
ycc_swe

19

Non usare variabili globali , così semplici.

Perché non usare i globali

Perché l'uso dei globi rende più difficile mantenere il software a lungo termine.

  • Un globale può essere dichiarato ovunque nel codice, o in nessun luogo, per cui non c'è posto in cui puoi istintivamente guardare per trovare qualche commento su ciò che il globale è usato per
  • Durante la lettura del codice di solito si presuppone che le variabili siano locali per la funzione e non si capisca che la modifica del loro valore in una funzione potrebbe avere un cambiamento a livello di sistema.
  • Se non gestiscono l'input, le funzioni dovrebbero restituire lo stesso valore / output quando vengono chiamate con gli stessi parametri. L'uso di globi in una funzione introduce parametri aggiuntivi che non sono documentati nella dichiarazione di funzione.
  • i globi non hanno alcun costrutto di inizializzazione specifico e pertanto non si può mai essere sicuri di poter accedere al valore del globale e non si ottiene alcun errore quando si tenta di accedere al globale prima dell'inizializzazione.
  • Qualcun altro (forse un plug-in) potrebbe utilizzare i globuli con lo stesso nome, rovinando il codice o rovinandone il contenuto a seconda dell'ordine di inizializzazione.

Il core di WordPress ha molto da fare per un uso molto globale. Mentre cerchi di capire come funzionano le funzioni di base the_content, improvvisamente ti rendi conto che la $morevariabile non è locale ma globale e devi cercare in tutti i file core per capire quando è impostata su true.

Quindi cosa si può fare quando si tenta di interrompere la copia e incollare diverse righe di codice invece di archiviare il risultato della prima esecuzione in un globale? Esistono diversi approcci, funzionali e OOP.

La funzione dolcificante. È semplicemente un wrapper / macro per salvare la copia / incolla

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

I vantaggi sono che ora c'è una documentazione su ciò che fa il precedente globale e hai un ovvio punto per il debug quando il valore restituito non è quello che ti aspetti.

Una volta che hai un dolcificante, è facile memorizzare nella cache il risultato, se necessario (fallo solo se scopri che questa funzione richiede molto tempo per essere eseguita)

function notaglobal($id) {
  static $cache;

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

Questo ti dà lo stesso comportamento di un globale ma con il vantaggio di avere un'inizializzazione sicura ogni volta che accedi ad esso.

Puoi avere modelli simili con OOP. Trovo che OOP di solito non aggiunga alcun valore a plugin e temi, ma questa è una discussione diversa

class notaglobal {
   var latestfoo2;

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

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

Questo è un codice più goffo, ma se hai diversi valori che vorresti precompilare perché vengono sempre usati, questo può essere un modo per andare. Fondamentalmente questo è un oggetto che contiene tutti i tuoi globi in modo organizzato. Per evitare di rendere un'istanza di questo oggetto un globale (si desidera su un'istanza altrimenti si ricalcolano i valori) si potrebbe voler usare un modello singleton (alcune persone sostengono che sia una cattiva idea, YMMV)

Non mi piace accedere direttamente all'attributo di un oggetto, quindi nel mio codice si deformerà un po 'di più

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);

7
Per favore, non urlare . Ti dispiace spiegare perché e fornire qualche tipo di citazione?
brasofilo,

Penso che tu abbia frainteso la risposta. Se non stesse cercando di eseguire l'ottimizzazione anticipata memorizzando i valori nelle variabili globali, il suo codice avrebbe funzionato. Le urla sono perché seguire i principi di sviluppo del software stabiliti di base è qualcosa che non può essere enfatizzato abbastanza. Le persone che non comprendono questi principi di base (disponibili sul tuo google locale) non dovrebbero diffondere il codice in rete.
Mark Kaplun

1
IMO questa è una risposta, le persone che vengono qui da Google dovrebbero vedere che è una cattiva idea persino pensare di usare subito i globi.
Mark Kaplun

6
Non basta dire non fare X, devi spiegare perché o sembri che lo dici per capriccio
Tom J Nowell

1
@ TomJNowell, trovo divertente il fatto che io sia stato l'unico a sottovalutare la domanda stessa, dato che ovviamente era al di fuori dell'ambito di WASE. Non ho visto il valore dell'espansione su un argomento che non avrebbe dovuto essere iniziato affatto qui.
Mark Kaplun,

8

La tua domanda riguarda il funzionamento di php.

Prendi $ wpdb come esempio

$ wpdb è una variabile globale ben nota.

Sai quando verrà dichiarato e assegnato con valori?

Ogni pagina caricata , sì, ogni volta che visiti il ​​tuo sito wordpress.

Allo stesso modo, è necessario assicurarsi che le variabili che si desidera vengano globalizzate vengano dichiarate e assegnate con i valori corrispondenti ogni pagina caricata.

Anche se non sono un disegnatore di temi, posso dire che after_setup_theme è un tutt'uno. verrà attivato solo quando il tema è attivato.

Se fossi in te, userò init o altri hook. No, se fossi in te, non userò affatto le variabili globali ...

Non sono davvero bravo a spiegare le cose. Quindi, dovresti prendere un libro se vuoi approfondire PHP.


2

È sempre possibile utilizzare un modello singleton tramite getter statici.

<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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.