Hoe globale variabelen instellen en gebruiken? Of waarom zou u ze helemaal niet gebruiken

UPDATE: Mijn oorspronkelijke vraag is opgelost, maar dit wordt een geldige discussie over waarom geen globale variabelen moeten worden gebruikt, dus ik werk de vraag bij om dat weer te geven. De oplossing was <?php global $category_link_prop; echo esc_url( $category_link_prop ); ?> zoals @TomJNowell suggereerde.

UPDATE 2: Ik laat het nu precies doen wat ik wilde. Maar ik gebruik nog steeds globaal bereik en zou graag een betere manier vinden.

Ik probeer een hele reeks globale variabelen in te stellen voor de permalinks naar categorieën die op verschillende plaatsen in mijn thema. De belangrijkste reden hiervoor is voor gebruik in zowel de hoofdnavigatie als in een reeks subnavigaties die worden gekozen op basis van de categorie waarin het huidige bericht zich bevindt. Dit is geen thema Ik zal vrijgeven voor gebruik door anderen, maar is gebouwd voor een heel specifiek doel.

Dit is hoe ik ze momenteel aan het maken ben (ik heb maar een paar variabelen geplakt).

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

Ik kan nu <?php global $prop; echo $prop; ?> doen op de 4 plaatsen die naartoe gaan en de hele link voor de code terughalen. Als dat verandert, hoef ik het maar op één plek te veranderen. Ik “sta open voor alternatieven die geen betrekking hebben op het globale bereik.

Opmerkingen

  • Welke link echoën esc_url ($ category_link_prop); ? Wat is je verwachte link?
  • Waarom zou je niet ‘ get_cat_ID (****) ‘ waar je ooit van plan was om de globale variabele te gebruiken. Ik betwijfel of er een snelheidsvoordeel zou zijn op de manier waarop je het doet. Vanuit het oogpunt van leesbaarheid, ‘ get_cat_ID (****) ‘ wint zonder meer.
  • Kun je het anders formuleren? Ik heb je vraag gelezen en ‘ weet nog steeds niet wat je wil doen en waarom je het wilt doen. Mijn algemene advies zou zijn om geen globale variabelen te gebruiken en de globale scope niet te vervuilen
  • dit klinkt een beetje als een X / Y-probleem . misschien moet u een back-up maken en precies uitleggen wat uw gewenste resultaat is. Ik ‘ ben er zeker van hier ‘ is een veel elegantere oplossing dan het instellen van een aantal globale variabelen om vervolgens verwijzingen ernaar hard te coderen in een nav ergens anders
  • maak een functie die je menu uitvoert op basis van de context die je eraan doorgeeft, kun je op die manier alle menulogica en bijbehorende variabelen op één plaats samenvatten.

Answer

Hoewel ik dit sterk afraad, en het niet de zaken versnelt, is uw gebruik onjuist.

WordPress slaat deze dingen al op in de objectcache, je hoeft het resultaat niet op te slaan en opnieuw te gebruiken, WP doet dat al .

Het is zeer waarschijnlijk dat uw code langzamer werkt als resultaat van deze micro-optimalisatie, niet sneller!

Hoe Globals te gebruiken

Als je een global probeert te gebruiken, moet je eerst het global trefwoord specificeren. Je hebt het hier gespecificeerd bij het definiëren van zijn waarde, maar buiten dat bereik moet het opnieuw worden gedeclareerd als een globale bereikvariabele.

bijv. in functions.php:

  function test() { global $hello; $hello = "hello world"; } add_action( "after_setup_theme", "test" );  

In single.php zal dit niet werken:

  echo $hello;  

Omdat $hello niet gedefinieerd is. Dit zal echter werken:

  global $hello; echo $hello;  

Natuurlijk mag u geen van beide doen. WordPress probeert al deze dingen in de objectcache te cachen.

Nadelen en gevaren van globale variabelen

Je zult geen snelheidstoename zien door dit te doen (je ziet misschien een kleine snelheidsafname), alles wat je krijgt is extra complexiteit en de noodzaak om veel globale declaraties uit te typen die niet nodig zijn.

Je zult ook andere problemen tegenkomen:

  • code die onmogelijk is om tests voor te schrijven
  • code die zich anders gedraagt elke keer dat hij wordt uitgevoerd
  • botst in variabelenamen uit een gedeelde naamruimte
  • onbedoelde bugs door het vergeten global
  • een volledig gebrek aan structuur in uw codegegevensopslag
  • en nog veel meer

Wat moet u in plaats daarvan gebruiken?

U kunt beter gestructureerde gegevens gebruiken, zoals als objecten of afhankelijkheidsinjectie, of in jouw geval een set functies.

Statische variabelen

Statische variabelen zijn niet goed, maar beschouw ze als de iets minder slechte neef van globale variabelen.Statische variabelen zijn voor globale variabelen, wat met modder bedekt brood is voor cyanide.

Hier is bijvoorbeeld een manier om iets soortgelijks te doen via statische variabelen, bijv.

  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  

Singletons

Singletons zijn als statische variabelen, behalve dat de klasse een statische variabele bevat met een instantie van die klasse . Ze zijn net zo slecht als globale variabelen, alleen met verschillende syntaxis. Vermijd ze.

WP_Cache, het ding dat je probeerde te doen, maar WP doet het al

Als je het echt wilt bespaar tijd door gegevens ergens op te slaan om ze opnieuw te gebruiken, overweeg om het WP_Cache -systeem te gebruiken met wp_cache_get enz. bijv.

 $value = wp_cache_get( "hello" ); if ( false === $value ) { // not found, set the default value wp_cache_set( "hello", "world" ); }  

Nu wordt de waarde in de cache opgeslagen gedurende de levensduur van het verzoek door WordPress, wordt weergegeven in foutopsporingsprogrammas en als je een objectcache hebt, zal het blijven bestaan bij verzoeken


Sidenote 1: ik zou willen opmerken dat sommige mensen proberen om gegevens in globale variabelen over verzoeken te bewaren, niet wetende dat dit niet is hoe PHP werkt . In tegenstelling tot een Node-applicatie laadt elk verzoek een nieuwe kopie van de applicatie, die vervolgens sterft wanneer het verzoek is voltooid. Om deze reden overleven globale variabelen die op het ene verzoek zijn ingesteld, het volgende verzoek niet.

Sidenote 2: Te oordelen naar de bijgewerkte vraag, leveren uw globale variabelen u helemaal geen prestatiewinst op. Je moet gewoon de HTML genereren wanneer je hem nodig hebt en hij zou net zo snel werken, misschien zelfs een klein beetje sneller. Dit is micro-optimalisatie.

Reacties

  • Ik weet het ‘ zijn kleine noten om de globaal bereik, maar de meeste, zo niet al deze variabelen zullen op elke pagina worden gebruikt. Ik ‘ sta open voor betere ideeën. Ik ga de vraag bewerken om mijn bedoeling een beetje duidelijker te maken. Het werkt trouwens prima als ik <?php global $category_link_prop; echo esc_url( $category_link_prop ); ?> doe volgens uw suggestie. Bedankt!
  • Ah als mijn oplossing werkt, kunt u dan markeren als geaccepteerd? Uw globale variabelen zijn net zo snel als het maken van de oorspronkelijke aanroep, misschien wilt u in plaats daarvan proberen functies te gebruiken, zodat u niet ‘ 2 regels hoeft uit te typen, beter nog, een singleton, beter nog, maak dat allemaal dynamisch en in een sjabloongedeelte opgenomen via get_template_part
  • Gemarkeerd als geaccepteerd omdat het is wat ik nu aan het doen ben, hoewel ik misschien ga met een van de strategieën die @MarkKaplun hieronder suggereert. Het gebruik van get_template_part () is een interessant idee, maar ik ‘ weet niet zeker of ik zon map vol korte bestanden wil hebben …
  • oooh nee nee je zou niet ‘ willen een bestand voor elke categorie, je ‘ zou alleen het bestand willen dat de huidige categorienaam pakt en dat gebruikt . Je hoeft niet ‘ iets hard te coderen, stel je het gedoe voor om alles hard te coderen.
  • Ik heb de code in mijn child-functions.php geplaatst die actief is. Maar ik krijg geen toegang tot de variabele in een php-include-bestand dat ik aanroep vanuit een ” normal ” database-gegenereerde post. Vertel me alstublieft, wat moet ik doen? (Ik definieer het natuurlijk als globaal.)

Antwoord

Gebruik geen globale variabelen , zo simpel is het.

Waarom niet use globals

Omdat het gebruik van globals het moeilijker maakt om de software op lange termijn te onderhouden.

  • Een globaal kan overal in de code worden gedeclareerd, of helemaal nergens, daarom is er geen plaats waar je direct naar een opmerking kunt kijken over waar de globale voor wordt gebruikt
  • Bij het lezen van code ga je er meestal van uit dat variabelen zijn lokaal voor de functie en begrijpen niet dat het veranderen van hun waarde in een functie een systeembrede verandering kan hebben.
  • Als ze geen invoer afhandelen, moeten functies dezelfde waarde / uitvoer teruggeven als ze worden aangeroepen met dezelfde parameters Het gebruik van globals in een functie introduceert extra parameters die niet zijn gedocumenteerd in de functiedeclaratie .
  • globals hebben geen specifieke initialisatieconstructie en daarom weet je nooit zeker wanneer je toegang hebt tot de waarde van de globale, en krijg je geen foutmelding als je probeert toegang te krijgen tot de globale voor initialisatie. .
  • Iemand anders (misschien een plug-in) gebruikt mogelijk globals met dezelfde naam, waardoor je code verpest of je de code verpest, afhankelijk van de volgorde van initialisatie.

WordPress core heeft veel veel te veel gebruik van globals. Terwijl je probeert te begrijpen hoe basisfuncties zoals the_content werken, realiseer je je plotseling dat de variabele $more niet lokaal maar globaal is en dat je in zijn geheel moet zoeken van de kernbestanden om te begrijpen wanneer deze is ingesteld op true.

Dus wat kan er worden gedaan als je probeert te stoppen met het kopiëren van & door verschillende regels code te plakken in plaats van het resultaat van de eerste run op te slaan in een globaal? Er zijn verschillende benaderingen, functioneel en OOP.

De zoetstoffunctie. Het is gewoon een wrapper / macro om de kopie / plak op te slaan.

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

De voordelen zijn dat er nu een documentatie is over wat de vorige global doet, en u hebben een duidelijk punt voor foutopsporing wanneer de waarde die wordt geretourneerd niet degene is die u verwacht.

Als u eenmaal een zoetstof heeft, is het gemakkelijk om het resultaat in de cache te plaatsen indien nodig (doe het alleen als u ontdekt dat deze functie een lange tijd om uit te voeren)

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

Dit geeft u hetzelfde gedrag van een globaal, maar met het voordeel dat u elke keer dat u er toegang toe krijgt een gegarandeerde initialisatie heeft.

U kunt vergelijkbare patronen hebben met OOP. Ik vind dat OOP meestal geen waarde toevoegt aan plug-ins en themas, maar dit is een andere discussie

class notaglobal { var latestfoo2; __constructor($id) { $a = foo1($id); $this->latestfoo2 = foo2($a) } } $v = new notaglobal($cat_id); echo $v->latestfoo2; 

Dit is een onhandige code, maar als je verschillende waarden hebben die u vooraf wilt berekenen, omdat ze altijd worden gebruikt. Dit kan een goede keuze zijn. In feite is dit een object dat al uw globalen op een georganiseerde manier bevat. Om te voorkomen dat een instantie van dit object een globale (u wilt één instantie anders berekent u de waarden opnieuw) u wilt misschien een singleton-patroon gebruiken (sommige mensen beweren dat het een slecht idee is, YMMV)

Ik hou er niet van om rechtstreeks toegang te krijgen tot een objectattribuut, dus in mijn code zal het wat meer warpen

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

Reacties

  • Alsjeblieft, niet ‘ schreeuwen . Wil je uitleggen waarom en een soort citaat geven?
  • Ik denk dat je het antwoord verkeerd hebt begrepen. Als hij niet ‘ had geprobeerd om vroege optimalisatie uit te voeren door waarden op te slaan in globale variabelen, zou zijn code hebben gewerkt. Het geschreeuw is omdat het volgen van gevestigde basisprincipes voor softwareontwikkeling iets is dat niet ‘ genoeg kan worden benadrukt. Mensen die deze basisprincipes (beschikbaar bij uw lokale Google) niet begrijpen, mogen geen code over het net verspreiden.
  • IMO dit is een antwoord, mensen die hier van Google komen, zouden moeten inzien dat het een slecht idee is om zelfs meteen na te denken over het gebruik van globale waarden.
  • Het ‘ is niet genoeg om te zeggen: doe X niet, je moet uitleggen waarom of je lijkt op jou ‘ zegt het in een opwelling
  • @TomJNowell, ik vind het grappig dat ik de enige was die de vraag zelf naar beneden stemde, aangezien het duidelijk buiten het bereik van WASE. Ik heb ‘ de waarde niet ingezien van het uitbreiden van een onderwerp dat hier helemaal niet had moeten beginnen.

Antwoord

Uw vraag heeft te maken met hoe php werkt.

Neem $ wpdb als voorbeeld

$ wpdb is een bekende globale variabele.

Weet u wanneer deze “gedeclareerd en toegewezen zal worden met waarden?

Elke pagina geladen , ja, elke keer dat u uw WordPress-site bezoekt.

Evenzo moet u ervoor zorgen dat de variabelen waarvan u wilt dat ze geglobaliseerd worden, worden gedeclareerd en toegewezen met overeenkomstige waarden elke pagina die wordt geladen.

Hoewel ik geen thema-ontwerper ben, kan ik wel zeggen dat after_setup_theme er een is. tijd haak. het wordt alleen geactiveerd als het thema is geactiveerd.

Als ik jou was, zal ik init of andere hooks gebruiken. Nee, als ik jou was, zou ik helemaal geen globale variabelen gebruiken …

Ik ben echt niet goed in het uitleggen van dingen. Dus je moet een boek pakken als je je in PHP wilt verdiepen.

Answer

Je kunt altijd een singleton-patroon gebruiken via statische getters.

<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 

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *