Jak ustawić i używać zmiennych globalnych? Albo dlaczego w ogóle ich nie używać

UPDATE: Moje pierwotne pytanie zostało rozwiązane, ale zmienia się to w ważną dyskusję o tym, dlaczego nie używać zmiennych globalnych, więc aktualizuję pytanie, aby to odzwierciedlić. Rozwiązaniem było <?php global $category_link_prop; echo esc_url( $category_link_prop ); ?> zgodnie z sugestią @TomJNowell.

UPDATE 2: Teraz robię dokładnie to, czego chciałem. Ale nadal używam zasięgu globalnego i byłbym szczęśliwy, gdyby znalazł lepszy sposób.

Próbuję ustawić całą masę zmiennych globalnych dla linków bezpośrednich do kategorii, które będą używane w różnych miejscach w moim temat. Głównym tego powodem jest użycie zarówno w głównej nawigacji, jak i w serii pod-nawigacji, które są wybierane na podstawie kategorii, w której znajduje się bieżący post. To nie jest motyw Będę udostępniać do użytku innych, ale jest zbudowany w jednym, bardzo konkretnym celu.

Obecnie tworzę je w ten sposób (wkleiłem tylko kilka zmiennych).

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

Mogę teraz wykonać <?php global $prop; echo $prop; ?> w 4 miejscach i odzyskać cały link do kodu. Kiedy to się zmieni, wystarczy, że zmienię to w jednym miejscu. Jestem otwarty na alternatywy, które nie obejmują zakresu globalnego.

Komentarze

  • Który link zawiera to stwierdzenie echo esc_url ($ category_link_prop); wyświetla ? Jaki jest twój oczekiwany link?
  • Dlaczego nie użyjesz po prostu ' get_cat_ID (****) ' wszędzie tam, gdzie planowałeś użyć zmiennej globalnej. Wątpię, czy sposób, w jaki to robisz, przyniesie jakikolwiek przewagę szybkości. Z punktu widzenia czytelności ' get_cat_ID (****) ' bez wątpienia wygrywa.
  • Czy możesz przeformułować? Przeczytałem twoje pytanie i ' nadal nie jestem pewien, czego chcesz to zrobić i dlaczego chcesz to zrobić. Moja ogólna rada jest taka, aby nie używać zmiennych globalnych i nie zanieczyszczać zasięgu globalnego.
  • brzmi to trochę jak Problem X / Y . być może powinieneś wykonać kopię zapasową i dokładnie wyjaśnić, jaki jest twój pożądany rezultat. ' na pewno t tutaj ' jest o wiele bardziej eleganckim rozwiązaniem niż ustawienie zestawu zmiennych globalnych, aby następnie tylko odniesienia do nich na stałe w nawigacji w innym miejscu
  • utworzyć funkcję, która wyprowadza twoje menu w oparciu o kontekst, który mu przekazujesz, w ten sposób możesz zachować całą logikę menu i powiązane zmienne w jednym miejscu.

Odpowiedź

Chociaż stanowczo odradzam, a to nie przyśpieszy działanie, Twoje użycie jest niepoprawne.

WordPress już buforuje te rzeczy w pamięci podręcznej obiektów, nie musisz zapisywać wyniku i używać go ponownie, WP robi to już .

Jest bardzo prawdopodobne, że Twój kod działa wolniej w wyniku tej mikro-optymalizacji, a nie szybciej!

Jak korzystać z danych globalnych

Kiedy próbujesz użyć globalnego, musisz najpierw określić słowo kluczowe global. Podałeś ją tutaj podczas definiowania wartości, ale poza tym zakresem musi zostać ponownie zadeklarowana jako zmienna o zasięgu globalnym.

np. in functions.php:

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

W single.php to nie zadziała:

  echo $hello;  

Ponieważ $hello jest niezdefiniowane. To jednak zadziała:

  global $hello; echo $hello;  

Oczywiście nie powinieneś tego robić. WordPress już próbuje buforować te rzeczy w pamięci podręcznej obiektów .

Wady i niebezpieczeństwa zmiennych globalnych

Dzięki temu nie zauważysz wzrostu szybkości (możesz zauważyć niewielki spadek prędkości), otrzymasz jedynie dodatkową złożoność i konieczność wypisania wielu globalnych deklaracji, które nie są potrzebne.

Napotkasz także inne problemy:

  • kod, którego nie da się napisać testów dla
  • kodu, który zachowuje się inaczej za każdym razem, gdy jest uruchamiany
  • kolizje w nazwach zmiennych ze wspólnej przestrzeni nazw
  • przypadkowe błędy wynikające z zapomnienia o zadeklarowaniu global
  • całkowitego braku struktury do przechowywania danych kodów
  • i wiele innych

Czego zamiast tego użyć?

Lepiej byłoby używać danych strukturalnych, takich jako obiekty lub wstrzyknięcie zależności, lub w twoim przypadku jako zestaw funkcji.

Zmienne statyczne

Zmienne statyczne nie są dobre, ale myśl o nich jako o nieco mniej złych kuzynach zmiennych globalnych.Zmienne statyczne są dla zmiennych globalnych, czym jest błotnisty chleb dla cyjanku.

Na przykład tutaj jest sposób na zrobienie czegoś podobnego poprzez zmienne statyczne, np.

  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  

Pojedyncze

Singletony są jak zmienne statyczne, z tą różnicą, że klasa zawiera zmienną statyczną z instancją tej klasy . Są tak samo złe jak zmienne globalne, tylko mają inną składnię. Unikaj ich.

WP_Cache, rzecz, którą próbowałeś zrobić, ale WP już to robi

Jeśli naprawdę chcesz oszczędzaj czas, przechowując dane w innym miejscu, rozważ użycie systemu WP_Cache z wp_cache_get itp. np.

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

Teraz wartość będzie przechowywana w pamięci podręcznej przez WordPress przez cały czas trwania żądania, pojawi się w narzędziach do debugowania i jeśli masz obiektową pamięć podręczną, będzie ona utrzymywana w żądaniach


Uwaga 1: Chciałbym zauważyć, że niektórzy ludzie próbują utrwalać dane w zmiennych globalnych w żądaniach, nieświadomi, że PHP tak nie działa . W przeciwieństwie do aplikacji Node, każde żądanie ładuje nową kopię aplikacji, która następnie umiera po zakończeniu żądania. Z tego powodu zmienne globalne ustawione w jednym żądaniu nie zachowują się do następnego żądania

Uwaga 2: Sądząc po zaktualizowanym pytaniu, zmienne globalne nie dają żadnego wzrostu wydajności. Powinieneś po prostu wygenerować kod HTML wtedy, gdy go potrzebujesz, a będzie działał równie szybko, być może nawet odrobinę szybciej. To jest mikro-optymalizacja.

Komentarze

  • Wiem, że ' to małe orzechy w używaniu zasięg globalny, ale większość z tych zmiennych, jeśli nie wszystkie, będzie używana na każdej stronie. Jestem ' otwarty na lepsze pomysły. Zamierzam zredagować pytanie, aby mój zamiar był trochę jaśniejszy. Swoją drogą, działa doskonale, kiedy <?php global $category_link_prop; echo esc_url( $category_link_prop ); ?> zgodnie z twoją sugestią. Dzięki!
  • Ach, jeśli moje rozwiązanie działa, czy możesz oznaczyć jako zaakceptowane? Twoje zmienne globalne są tak samo szybkie, jak wywołanie pierwotnego wywołania. Zamiast tego możesz spróbować użyć funkcji, więc nie ' nie musisz wpisywać 2 wierszy, a najlepiej pojedynczego, jeszcze lepiej, uczyń to wszystko dynamicznym i częścią szablonu zawartą przez get_template_part
  • Oznaczone jako zaakceptowane jako to, co teraz robię, chociaż mogę wybrać jedną ze strategii, którą @MarkKaplun sugeruje poniżej. Używanie get_template_part () to ciekawy pomysł, ale ' nie jestem pewien, czy chcę mieć katalog pełen takich krótkich plików …
  • oooh nie nie, nie ' nie chcesz pliku dla każdej kategorii, ' nie chcesz tylko tego, który przechwytuje bieżącą nazwę kategorii i używa jej . Nie powinieneś ' niczego zakodować na stałe, wyobraź sobie kłopot z zakodowaniem tego wszystkiego na sztywno
  • Umieściłem kod w moim child-functions.php, który jest aktywny. Ale nie mogę uzyskać dostępu do zmiennej w pliku dołączanym php, który wywołuję z ” normalnego ” postu wygenerowanego w bazie danych. Proszę o poradę, co mam zrobić źle? (Oczywiście określam to jako globalne).

Odpowiedź

Nie używaj zmiennych globalnych , tak prostych.

Dlaczego nie używaj globalnych

Ponieważ używanie globałów utrudnia utrzymanie oprogramowania w dłuższej perspektywie.

  • Globalny można zadeklarować w dowolnym miejscu kodu lub nigdzie, dlatego nie ma miejsca, w którym można by instynktownie spojrzeć, aby znaleźć komentarz na temat tego, do czego służy global
  • Czytając kod, zwykle zakładasz, że zmienne są lokalne dla funkcji i nie rozumiem, że zmiana ich wartości w funkcji może spowodować zmianę w całym systemie.
  • Jeśli nie obsługują danych wejściowych, funkcje powinny zwracać tę samą wartość / wyjście, są wywoływane z tymi samymi parametrami.Użycie zmiennych globalnych w funkcji wprowadza dodatkowe parametry, które nie są udokumentowane w deklaracji funkcji .
  • globalne nie mają żadnej konkretnej konstrukcji inicjalizacyjnej i dlatego nigdy nie możesz być pewien, kiedy możesz uzyskać dostęp do wartości globalnej, i nie otrzymasz żadnego błędu podczas próby uzyskania dostępu do globalnego przed inicjalizacją .
  • Ktoś inny (może wtyczka) może użyć globali o tej samej nazwie, zrujnując twój kod lub zrujnujesz jego w zależności od kolejności inicjalizacji.

Rdzeń WordPressa ma o wiele za dużo używania globals. Próbując zrozumieć, jak działają podstawowe funkcje, takie jak the_content, nagle zdajesz sobie sprawę, że zmienna $more nie jest lokalna, ale globalna i musisz przeszukać cały podstawowych plików, aby zrozumieć, kiedy jest ustawiona na true.

Więc co można zrobić, próbując zatrzymać kopiowanie & wklejając kilka wierszy kodu zamiast przechowywać wynik pierwszego uruchomienia w postaci globalnej? Istnieje kilka podejść, funkcjonalnych i OOP.

Funkcja słodzika. Jest to po prostu opakowanie / makro do zapisywania kopiowania / wklejania

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

Korzyści są takie, że teraz istnieje dokumentacja tego, co robi poprzedni globalny, a ty masz oczywisty punkt do debugowania, gdy zwracana wartość nie jest tą, której oczekujesz.

Gdy masz już słodzik, łatwo jest zapisać wynik w pamięci podręcznej w razie potrzeby (zrób to tylko wtedy, gdy odkryjesz, że ta funkcja długi czas na wykonanie)

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

Daje to takie samo zachowanie jak globalne, ale z tą zaletą, że ma zapewnioną inicjalizację za każdym razem, gdy do niego uzyskujesz dostęp.

Możesz mieć podobne wzorce z OOP. Uważam, że OOP zwykle nie dodaje żadnej wartości do wtyczek i motywów, ale to jest inna dyskusja

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

To jest bardziej niezgrabny kod, ale jeśli ma kilka wartości, które chciałbyś obliczyć wstępnie, ponieważ są one zawsze używane, może to być dobry sposób. Zasadniczo jest to obiekt, który zawiera wszystkie twoje obiekty globalne w zorganizowany sposób. Aby uniknąć tworzenia instancji tego obiektu jako globalnej (chcesz na jednej instancji, w przeciwnym razie ponownie obliczysz wartości) możesz chcieć użyć wzorca pojedynczego (niektórzy twierdzą, że to zły pomysł, YMMV)

Nie lubię mieć bezpośredniego dostępu do atrybutu obiektu, więc w moim kodzie będzie on trochę bardziej wypaczony

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

Komentarze

  • Proszę, nie ' nie krzycz . Masz ochotę wyjaśnić dlaczego i podać jakieś cytaty?
  • Myślę, że źle zrozumiałeś odpowiedź. Gdyby nie ' t próbował dokonać wczesnej optymalizacji poprzez przechowywanie wartości w zmiennych globalnych, jego kod by zadziałał. Krzyczy się to, ponieważ przestrzeganie podstawowych, ustalonych zasad tworzenia oprogramowania jest czymś, na co ' nie można wystarczająco podkreślić. Osoby, które nie rozumieją tych podstawowych zasad (dostępnych w lokalnym google), nie powinny rozpowszechniać kodu w sieci.
  • IMO to jest odpowiedź, osoby, które przychodzą tutaj z Google, powinny zobaczyć, że to zły pomysł nawet od razu pomyśleć o użyciu globali.
  • To ' nie wystarczy powiedzieć nie rób X, musisz wyjaśnić dlaczego lub wyglądasz jak ty ' mówię to z kaprysu
  • @TomJNowell, to zabawne, że tylko ja przegłosowałem samo pytanie, ponieważ było to oczywiście poza zakresem WASE. Nie ' nie widziałem wartości rozwinięcia tematu, który w ogóle nie powinien był tu zaczynać.

Odpowiedź

Twoje pytanie dotyczy sposobu działania php.

Weźmy $ wpdb jako przykład

$ wpdb to dobrze znana zmienna globalna.

Czy wiesz, kiedy zostanie zadeklarowana i przypisana wartościom?

Każda strona ładowana , tak, za każdym razem, gdy odwiedzasz swoją witrynę WordPress.

Podobnie, musisz się upewnić, że zmienne, które chcesz zglobalizować, zostaną zadeklarowane i przypisane do odpowiednich wartości na każdej załadowanej stronie.

Chociaż nie jestem projektantem motywów, mogę powiedzieć, że after_setup_theme to jeden hak czasu. będzie uruchamiany tylko po aktywacji motywu.

Na twoim miejscu użyję init lub innych hooków. Nie, na twoim miejscu nie użyłbym w ogóle zmiennych globalnych …

Naprawdę nie jestem dobry w wyjaśnianiu rzeczy. Więc powinieneś sięgnąć po książkę, jeśli chcesz zagłębić się w PHP.

Odpowiedź

Zawsze możesz użyć pojedynczego wzorca poprzez statyczne metody pobierające.

<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 

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *