UPPDATERING: Min ursprungliga fråga har lösts, men detta blir en giltig diskussion om varför inte använda globala variabler, så jag uppdaterar frågan för att återspegla det. Lösningen var <?php global $category_link_prop; echo esc_url( $category_link_prop ); ?>
som @TomJNowell föreslog.
UPPDATERING 2: Jag har nu gjort exakt vad jag ville. Men jag använder fortfarande globalt omfång och skulle gärna hitta ett bättre sätt.
Jag försöker skapa en hel massa globala variabler för permalänkar till kategorier som ska användas på olika platser i min tema. Den främsta anledningen till detta är för användning i både huvudnavigering och i en serie undernavigationer som väljs utifrån vilken kategori det aktuella inlägget är i. Detta är inte ett tema Jag kommer att släppa för användning av andra, men är byggd för ett mycket specifikt syfte.
Så här skapar jag dem just nu (jag har bara klistrat in några av variablerna).
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" );
Jag kan nu göra <?php global $prop; echo $prop; ?>
på de fyra platserna som går och få tillbaka hela länken för koden. När det ändras behöver jag bara ändra det på ett ställe. Jag är öppen för alternativ som inte omfattar det globala omfånget.
Kommentarer
- Vilken länk echar detta uttalande esc_url ($ category_link_prop); visar ? Vad är din förväntade länk?
- Varför skulle du inte bara använda ’ get_cat_ID (****) ’ var du någonsin planerat att använda den globala variabeln. Jag tvivlar på att det skulle vara någon hastighetsfördel hur du gör det. Ur läsbarhetssynpunkt ’ get_cat_ID (****) ’ vinner händer nedåt.
- Kan du omformulera? Jag läste din fråga och jag ’ är fortfarande osäker på vad du vill göra och varför du vill göra det. Mitt allmänna råd skulle vara att inte använda globala variabler och inte förorena det globala omfånget
- det låter lite som en X / Y-problem . kanske du bör säkerhetskopiera och förklara exakt vad ditt önskade resultat är. Jag ’ är säker t här ’ är en mycket mer elegant lösning än att ställa in en massa globala vars att bara ha hårddiskreferenser till dem i en nav någon annanstans
- skapa en funktion som matar ut din meny baserat på det sammanhang du skickar till det, så kan du hålla all menylogik och tillhörande vars inkapslade på ett ställe.
Svar
Medan jag rekommenderar starkt detta, kommer det inte att snabba upp saker, men din användning är felaktig.
WordPress cachar redan dessa saker i objektcachen, du behöver inte lagra resultatet och återanvända, WP gör det redan .
Det är mycket troligt att din kod går långsammare på grund av denna mikrooptimering, inte snabbare!
Så här använder du globaler
När du försöker använda en global måste du först ange sökordet global
. Du har specificerat det här när du definierar dess värde, men utanför det omfattningen måste det omdeklareras som en global omfattningsvariabel.
t.ex. i functions.php
:
function test() { global $hello; $hello = "hello world"; } add_action( "after_setup_theme", "test" );
I single.php
fungerar det inte:
echo $hello;
Eftersom $hello
är odefinierad. Detta dock kommer att fungera:
global $hello; echo $hello;
Naturligtvis borde du inte göra något av det. WordPress försöker redan att cacha dessa saker i objektcachen .
Nackdelar och faror med globala variabler
Du ser ingen hastighetsökning från att göra detta (du kan se en liten hastighetsminskning), allt du får är ytterligare komplexitet och behovet av att skriva ut många globala deklarationer som inte är nödvändiga.
Du kommer också att stöta på andra problem:
- kod som är omöjlig att skriva tester för
- kod som fungerar annorlunda varje gång den körs
- kolliderar i variabla namn från ett delat namnutrymme
- oavsiktliga fel från att glömma att förklara
global
- en fullständig brist på struktur till dina koder datalagring
- och många fler
Vad ska du använda istället?
Det är bättre att du använder strukturerad data, t.ex. som objekt eller beroendeberoende, eller i ditt fall, en uppsättning funktioner.
Statiska variabler
Statiska variabler är inte bra, men tänk på dem som den något mindre onda kusinen till globala variabler.Statiska variabler är globala variabler, vad lera täckt bröd är för cyanid.
Till exempel är här ett sätt att göra något liknande via statiska variabler t.ex.
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 är som statiska variabler, förutom att klassen innehåller en statisk variabel med en instans av den klassen . De är lika dåliga som globala variabler, bara med olika syntax. Undvik dem.
WP_Cache, det du försökte göra men WP gör det redan
Om du verkligen vill spara tid genom att lagra data någonstans för att återanvända, överväg att använda WP_Cache
-systemet med wp_cache_get
etc t.ex.
$value = wp_cache_get( "hello" ); if ( false === $value ) { // not found, set the default value wp_cache_set( "hello", "world" ); }
Nu cachas värdet under hela WordPress-begäran, visas i felsökningsverktyg och om du har ett objektcache kommer det ”att bestå över förfrågningar
Sidenote 1: Jag skulle notera att vissa människor försöker bestå data i globala variabler över förfrågningar, omedvetna om att det inte är så som PHP fungerar . Till skillnad från en nodapplikation laddar varje begäran en ny kopia av applikationen, som sedan dör när begäran är klar. Av denna anledning överlever globala variabler som ställts in på en begäran inte till nästa begäran
Sidenote 2: Att döma av den uppdaterade frågan ger dina globala variabler dig ingen prestationsvinster alls. Du borde bara skapa HTML när och när du behöver det och det skulle gå lika snabbt, kanske till och med lite snabbare. Detta är mikrooptimering.
Kommentarer
- Jag vet att det ’ är lite nötter att använda globalt omfång, men de flesta, om inte alla dessa variabler kommer att användas på varje sida. Jag ’ är öppen för bättre idéer. Jag kommer att redigera frågan för att göra min avsikt lite tydligare. BTW det fungerar helt bra när jag gör
<?php global $category_link_prop; echo esc_url( $category_link_prop ); ?>
enligt ditt förslag. Tack! - Ah om min lösning fungerar, kan du markera som accepterad? Dina globala variabler är lika snabba som att ringa det ursprungliga samtalet, du kanske vill prova istället att använda funktioner så att du inte behöver ’ att skriva ut två rader, ännu bättre, en singleton, ännu bättre, gör allt det dynamiska och i en mall del ingår via get_template_part
- Markerad som accepterad som det jag gör nu även om jag kan gå med en av de strategier som @MarkKaplun föreslår nedan. Att använda get_template_part () är en intressant idé, men jag ’ är inte säker på att jag vill ha en dir full av korta filer så …
- oooh nej nej du vill inte ’ t vill ha en fil för varje kategori, du ’ vill bara ha den som tar tag i det aktuella kategorinamnet och använder det . Du borde inte ’ inte behöva hårddiska någonting, föreställ dig besväret med hårdkodning av allt
- Jag lägger koden i mina barnfunktioner.php som är aktiv. Men jag kan inte komma åt variabeln i en php-include-fil som jag kallar från en ” normal ” databasgenererad post. Vänligen ge mig råd, vad gör jag fel? (Jag definierar det naturligtvis som globalt.)
Svar
Använd inte globala variabler , så enkelt som det.
Varför inte använd globaler
Eftersom användningen av globaler gör det svårare att underhålla programvaran på lång sikt.
- En global kan deklareras var som helst i koden, eller ingenstans alls, därför finns det ingen plats där du instinktivt kan titta på för att hitta en kommentar om vad det globala används för
- När du läser kod antar du vanligtvis att variabler är lokala för funktionen och förstår inte att ändring av deras värde i en funktion kan ha en systemomfattande förändring.
- Om de inte hanterar inmatning bör funktioner returnera samma värde / utgång när de kallas med samma parametrar. Användningen av globaler i en funktion introducerar ytterligare parametrar som inte är dokumenterade i funktionsdeklarationen .
- globaler har ingen specifik initialiseringskonstruktion och därför kan du aldrig vara säker på när du kan få tillgång till det globala värdet och du får inget fel när du försöker komma åt det globala innan initialisering .
- Någon annan (kanske ett plugin) kan använda globaler med samma namn, förstöra din kod eller förstöra dess beroende på initialiseringsordning.
WordPress-kärnan har sätt sätt mycket för mycket användning av globala. När du försöker förstå hur grundläggande funktioner som the_content
fungerar, inser du plötsligt att variabeln $more
inte är lokal utan global och måste söka hela av kärnfilerna för att förstå när det är satt till sant.
Så vad kan man göra när man försöker stoppa kopiering & klistra in flera rader kod istället för att lagra det första körningsresultatet i en global? Det finns flera tillvägagångssätt, funktionella och OOP.
Sötningsfunktionen. Det är helt enkelt ett omslag / makro för att spara kopiera / klistra in
// input: $id - the category id // returns: the foo2 value of the category function notaglobal($id) { $a = foo1($id); $b = foo2($a); return $b; }
Fördelarna är att det nu finns en dokumentation för vad den tidigare globala gör, och du ha en uppenbar punkt för felsökning när värdet som returneras inte är det du förväntar dig.
När du har en sötningsmedel är det enkelt att cache resultatet om det behövs (gör det bara om du upptäcker att den här funktionen tar lång tid att köra)
function notaglobal($id) { static $cache; if (!isset($cache)) { $a = foo1($id); $b = foo2($a); $cache = $b; } return $cache; }
Detta ger dig samma beteende hos en global men med fördelen att du har en säker initialisering varje gång du öppnar den.
Du kan ha liknande mönster med OOP. Jag tycker att OOP vanligtvis inte tillför något värde i plugins och teman, men det här är en annan diskussion
class notaglobal { var latestfoo2; __constructor($id) { $a = foo1($id); $this->latestfoo2 = foo2($a) } } $v = new notaglobal($cat_id); echo $v->latestfoo2;
Detta är en klumpigare kod, men om du har flera värden som du vill förberäkna eftersom de alltid används, detta kan vara ett sätt att gå. I grund och botten är detta ett objekt som innehåller alla dina globaler på ett organiserat sätt. För att undvika att göra en instans av detta objekt till ett globalt (du vill ha en instans annars beräknar du om värdena) du kanske vill använda ett singletonmönster (vissa hävdar att det är en dålig idé, YMMV)
Jag gillar inte att komma åt ett objektattribut direkt, så i min kod kommer det att skeva mer
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);
Kommentarer
- Snälla, låt ’ inte skrika . Tänk på att förklara varför och ge någon form av citat?
- Jag tror att du missförstod svaret. Om han inte ’ inte försökte göra tidig optimering genom att lagra värden i globala variabler skulle hans kod ha fungerat. Skriket beror på att följa grundläggande etablerade principer för mjukvaruutveckling är något som ’ inte kan betonas tillräckligt. Människor som inte förstår dessa grundläggande principer (finns på din lokala google) ska inte sprida koden över nätet.
- IMO detta är ett svar, människor som kommer hit från google bör se att det är en dålig idé att ens tänka på att använda globaler direkt.
- Det ’ är inte tillräckligt för att säga gör inte X, du måste förklara varför eller du ser ut som du ’ om jag säger det på ett infall
- @TomJNowell, jag tycker det är roligt att jag var den enda som röstade om själva frågan, eftersom det uppenbarligen var utanför ramen för WASE. Jag såg inte ’ värdet av att utvidga ett ämne som inte borde ha startats här alls.
Svar
Din fråga handlar om hur php fungerar.
Ta $ wpdb som exempel
$ wpdb är en välkänd global variabel.
Vet du när den kommer att deklareras och tilldelas värden?
Varje sida som laddas , ja, varje gång du besöker din WordPress-webbplats.
På samma sätt måste du se till att de variabler som du vill att ska globaliseras kommer att deklareras och tilldelas motsvarande värden varje sida laddas.
Även om jag inte är temadesigner kan jag säga att after_setup_theme är en tidskrok. det ”kommer bara att utlösas när temat aktiveras.
Om jag var du, använder jag init eller andra krokar. Nej, om jag var du skulle jag inte använda globala variabler alls …
Jag är verkligen inte bra på att förklara saker. Så du bör hämta en bok om du vill gräva i PHP.
Svar
Du kan alltid använda ett singletonmönster via statiska 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