Як встановити та використовувати глобальні змінні? Або чому взагалі їх не використовувати


27

ОНОВЛЕННЯ: Моє оригінальне запитання вирішено, але це перетворюється на обґрунтовану дискусію про те, чому б не використовувати глобальні змінні, тому я актуалізую питання, щоб це відобразити. Рішення було <?php global $category_link_prop; echo esc_url( $category_link_prop ); ?>таким, як запропонував @TomJNowell.

ОНОВЛЕННЯ 2: У мене зараз це саме те, що я хотів. Але я все ще використовую глобальну сферу і буду радий знайти кращий шлях.

Я намагаюся створити цілу купу глобальних змінних для посилань на категорії, які будуть використовуватися в різних місцях моєї теми. Основною причиною цього є використання як в основній навігації, так і в ряді допоміжних навігацій, які вибираються залежно від того, в якій категорії знаходиться поточна публікація. Це не тема, яку я випускатиму для використання іншими, але побудований для однієї дуже конкретної мети.

Ось так я зараз їх створюю (я вставив лише декілька змінних).

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

Зараз я можу зробити у <?php global $prop; echo $prop; ?>нього 4 місця, які можна отримати, і отримати повне посилання на код. Коли це змінюється, мені потрібно змінити його лише в одному місці. Я відкритий до альтернатив, які не передбачають глобальної сфери.


1
За яким посиланням відповідає цей вираз esc_url ($ category_link_prop); дисплеї? Яке очікуване посилання?
Вінод Далві

1
Чому б ви не просто використовували "get_cat_ID (****)" там, де коли-небудь планували використовувати глобальну змінну. Я сумніваюся, що було б якесь перевагу швидкості у тому, як ви це робите. З точки зору читабельності, "get_cat_ID (****)" виграє руки вниз.
Chris Strutton

1
Ви можете переробити слово? Я читаю ваше запитання, і я все ще не впевнений, що ви хочете зробити і чому ви хочете це зробити. Моя загальна порада: не використовувати глобальні змінні та не забруднювати глобальну сферу
Tom J Nowell

1
це звучить трохи як X / Y проблеми . можливо, вам слід створити резервну копію та пояснити, який саме ваш бажаний результат. Я впевнений, що є куди більш елегантне рішення, ніж встановити купу глобальних варіантів, а потім просто посилання на них у жорсткому коді в іншому місці
Milo

2
створити функцію, яка виводить ваше меню на основі контексту, який ви переходите до нього, таким чином ви зможете зберегти всю логіку меню та пов'язані варси в одному місці.
Міло

Відповіді:


21

Хоча я настійно раджу проти цього, і це не прискорить роботу, ваше використання неправильне.

Коли ви намагаєтесь використовувати глобальний, ви повинні спочатку вказати глобальне ключове слово. Ви вказали його тут, визначаючи його значення, але поза цим діапазоном його потрібно передекларувати як глобальну змінну області.

наприклад, у function.php:

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

У Single.php це не буде працювати:

echo $hello;

Тому що $ hello не визначено. Однак це спрацює:

global $hello;
echo $hello;

Звичайно, ви не повинні робити жодного. WordPress вже намагається кешувати ці речі в об'єктному кеші. Ви не побачите збільшення швидкості від цього (можливо, ви побачите невелике зниження швидкості), все, що ви отримаєте, - це додаткова складність і необхідність набрати багато глобальних декларацій, які не потрібні.

Вам краще використовувати структуровані дані, такі як об'єкти або введення залежності, або у вашому випадку, набір функцій.

Наприклад, тут є засіб зробити щось подібне за допомогою статичних змінних (все-таки погано з тих же причин, але просто трохи менше і простіше вводити), наприклад

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

Якщо ви дійсно хочете заощадити час, зберігаючи дані де-небудь для повторного використання, подумайте про використання WP_Cacheсистеми з wp_cache_getтощо


Я знаю, що використати глобальну сферу застосування трохи не можна, але більшість, якщо не всі ці змінні, будуть використовуватися на кожній сторінці. Я відкритий до кращих ідей. Я збираюся редагувати питання, щоб зробити свій намір трохи зрозумілішим. До речі, це працює чудово, коли я роблю <?php global $category_link_prop; echo esc_url( $category_link_prop ); ?>згідно з вашою пропозицією. Спасибі!
JPollock

2
Ах, якщо моє рішення працює, ви можете позначити його як прийняте? Ваші глобальні змінні настільки ж швидкі, як і вихідний дзвінок, ви можете спробувати замість цього використовувати функції, тому вам не потрібно вводити 2 лінії, ще краще, сингл, ще краще, зробити все це динамічним частина шаблону включена через get_template_part
Tom J Nowell

Позначено як прийняте як те, що я зараз роблю, хоча я можу піти з однією із стратегій @MarkKaplun пропонує нижче. Використання get_template_part () - цікава ідея, але я не впевнений, що хочу мати
реєр,

oooh ні ні, ви не хочете, щоб файл для кожної категорії, ви хочете лише той, який захоплює ім'я поточної категорії і використовує це. Вам не доведеться нічого жорстко кодувати, уявіть собі клопоти з жорстким кодуванням все це
Tom J Nowell

Я ставлю код у свою дочірню-function.php, яка активна. Але я не можу отримати доступ до змінної у файлі, що включає php, який я дзвоню з "нормальної" публікації бази даних. Підкажіть, будь ласка, що я роблю не так? (Я, безумовно, визначаю це як глобальне.)
ycc_swe

19

Не використовуйте глобальні змінні , настільки прості, як це.

Чому б не використовувати глобали

Оскільки використання глобальних мереж ускладнює підтримку програмного забезпечення в довгостроковій перспективі.

  • Глобальний може бути оголошений в будь-якому місці коду або взагалі ніде, для цього немає місця, де можна було б інтенсивно подивитися, щоб знайти коментар щодо того, для чого використовується глобальний
  • Під час читання коду ви зазвичай припускаєте, що змінні є локальними для функції, і ви не розумієте, що зміна їх значення у функції може змінити загальну систему.
  • Якщо вони не обробляють введення, функції повинні повертати те саме значення / вихід, коли вони викликаються з тими ж параметрами. Використання глобалів у функції вводить додаткові параметри, які не є документами у декларації функції.
  • глобалі не мають жодної конкретної конструкції ініціалізації, і тому ви ніколи не можете бути впевнені, коли можете отримати доступ до значення глобального рівня, і ви не отримаєте помилок при спробі доступу до глобального перед ініціалізацією.
  • Хтось інший (можливо, плагін) може використовувати глобали з тим самим іменем, руйнуючи ваш код, або ви руйнуєте його залежно від порядку ініціалізації.

Ядро WordPress має шлях, який дозволяє значно використовувати глобальні кулі. Намагаючись зрозуміти, як працюють базові функції the_content, ви раптом розумієте, що $moreзмінна не локальна, а глобальна, і вам потрібно шукати цілі основні файли, щоб зрозуміти, коли вона встановлена ​​на істину.

Отже, що можна зробити, намагаючись зупинити копіювання та вставлення декількох рядків коду, а не зберегти результат першого запуску в глобальному? Існує кілька підходів, функціональний та ООП.

Функція підсолоджувача. Це просто обгортка / макрос для збереження копії / вставки

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

Переваги полягають у тому, що зараз є документація щодо того, що робить колишній глобальний, і у вас є очевидний момент для налагодження, коли повернене значення не є таким, яке ви очікуєте.

Якщо у вас є підсолоджувач, ви зможете кешувати результат, якщо це потрібно (зробіть це лише в тому випадку, якщо ви виявите, що ця функція потребує тривалого часу)

function notaglobal($id) {
  static $cache;

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

Це дає вам таку саму поведінку глобального, але з перевагою мати впевнену ініціалізацію кожного разу, коли ви отримуєте доступ до нього.

Ви можете мати подібні зразки з OOP. Я вважаю, що OOP зазвичай не додає ніяких значень у плагінах та темах, але це інша дискусія

class notaglobal {
   var latestfoo2;

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

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

Це незграбний код, але якщо у вас є кілька значень, які ви хотіли б попередньо обчислити, оскільки вони завжди використовуються, це може бути шлях. В основному це об'єкт, який організовано містить усі ваші глобальні кулі. Щоб не зробити примірник цього об’єкта глобальним (ви хочете, щоб один екземпляр інакше перерахували значення), можливо, ви хочете використовувати однотонний шаблон (деякі люди стверджують, що це погана ідея, YMMV)

Мені не подобається безпосередньо звертатися до атрибута об'єкта, тому в моєму коді це ще більше викривиться

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
Будь ласка, не кричи . Думаєте пояснити, чому і надавати якесь цитування?
brasofilo

Я думаю, що ви неправильно зрозуміли відповідь. Якби він не намагався зробити ранню оптимізацію, зберігаючи значення в глобальних змінних, його код спрацював би. Крик полягає в тому, що дотримання основних встановлених принципів розробки програмного забезпечення - це те, чого не можна підкреслити достатньо. Люди, які не розуміють цього основного принципу (доступний у вашому локальному Google), не повинні поширювати код по мережі.
Марк Каплун

1
IMO - це відповідь, люди, які приїжджають сюди з google, повинні бачити, що це погана ідея навіть думати про використання глобальних одразу.
Марк Каплун

6
Мало сказати, що не роби X, ти повинен пояснити, чому або ти схожий на те, що ти говориш це на примху
Том Дж. Ноуелл

1
@TomJNowell, мені здається смішним, що я був єдиним, хто заборонив саме це питання, оскільки це, очевидно, виходило за рамки ВАСУ. Я не бачив значення розширення теми, яку взагалі не слід було починати.
Марк Каплун

8

Ваше запитання пов'язане з тим, як працює php.

Візьміть $ wpdb як приклад

$ wpdb - відома глобальна змінна.

Чи знаєте ви, коли це буде оголошено і присвоєно значенням?

Кожна завантажена сторінка , так, кожного разу, коли ви відвідуєте ваш сайт Wordpress.

Так само вам потрібно переконатися, що ті змінні, які ви хочете бути глобалізованими, будуть оголошені та присвоєні відповідним значенням кожної завантаженій сторінці.

Хоча я не дизайнер тем, я можу сказати, що after_setup_theme - це один раз гак. він буде запущений лише тоді, коли тема активована.

Якби я був ти, я буду використовувати ініт або інші гачки. Ні, якби я був ти, я взагалі не буду використовувати глобальні змінні ...

Мені справді непогано пояснювати речі. Отже, вам слід забрати книгу, якщо ви хочете заглибитись у PHP.


2

Ви завжди можете використовувати однотонний візерунок за допомогою статичних геттерів.

<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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.