Как установить и использовать глобальные переменные? Или почему бы не использовать их вообще

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 местах и ​​получить всю ссылку на код. Когда это изменится, мне нужно только изменить его в одном месте. Я открыт для альтернатив, которые не связаны с глобальным охватом.

JPollock
источник
1
По какой ссылке этот оператор выдает echo esc_url ($ category_link_prop); отображает? Какая ваша ожидаемая ссылка?
Винод Дальви
1
Почему бы вам не использовать 'get_cat_ID (****)' там, где вы планировали использовать глобальную переменную. Я сомневаюсь, что у тебя будет какое-то преимущество в скорости. С точки зрения читабельности get_cat_ID (****) выигрывает.
Крис Струттон
1
Вы можете перефразировать? Я прочитал ваш вопрос, и я все еще не уверен, что вы хотите сделать и почему вы хотите это сделать. Мой общий совет - не использовать глобальные переменные и не загрязнять глобальный охват
Том Дж. Новелл
1
это звучит немного как X / Y проблемы . возможно, вам следует вернуться назад и точно объяснить, каков будет ваш желаемый результат. Я уверен, что есть гораздо более элегантное решение, чем установка нескольких глобальных переменных, а затем просто указывать ссылки на них в навигационной системе в другом месте
Milo
2
создайте функцию, которая выводит ваше меню на основе контекста, который вы ему передаете, таким образом вы можете хранить всю логику меню и связанные с ней переменные в одном месте.
Мило

Ответы:

21

Хотя я настоятельно советую против этого, и это не ускорит процесс, ваше использование некорректно.

Когда вы пытаетесь использовать глобальный, вы должны сначала указать ключевое слово global. Вы указали его здесь при определении его значения, но за пределами этой области его необходимо повторно объявить как глобальную переменную области.

например, в functions.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
Том Дж. Новелл
Отмечено как принятое, как то, что я делаю сейчас, хотя я могу использовать одну из стратегий, предложенных @MarkKaplun ниже. Использование get_template_part () - интересная идея, но я не уверен, что хочу иметь
каталог,
оооо, нет, вам не нужен файл для каждой категории, вам нужен только тот, который захватывает имя текущей категории и использует его. Вам не нужно ничего кодировать жестко, представьте, как все это нужно жестко
Том Дж. Новелл
Я поместил код в мой child-functions.php, который активен. Но я не могу получить доступ к переменной в файле php-include, который я вызываю из "обычной" записи, сгенерированной базой данных. Посоветуйте пожалуйста, что я делаю не так? (Я определяю это как глобальный, конечно.)
ycc_swe
19

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

Почему бы не использовать глобалы

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

  • Глобальный может быть объявлен где-нибудь в коде, или вообще нигде, поэтому нет места, в котором вы можете инстинктивно посмотреть, чтобы найти какой-то комментарий о том, для чего используется глобал
  • При чтении кода вы обычно предполагаете, что переменные являются локальными для функции, и не понимаете, что изменение их значения в функции может привести к общесистемным изменениям.
  • Если они не обрабатывают ввод, функции должны возвращать одинаковое значение / вывод при вызове с одинаковыми параметрами. Использование глобальных переменных в функции вводит дополнительные параметры, которые не задокументированы в объявлении функции.
  • глобальные переменные не имеют какой-либо конкретной конструкции инициализации, и поэтому вы никогда не можете быть уверены, когда сможете получить доступ к значению глобальной переменной, и вы не получите никакой ошибки при попытке доступа к глобальной переменной перед инициализацией.
  • Кто-то другой (возможно, плагин) может использовать глобалы с тем же именем, разрушая ваш код, или вы разрушаете его в зависимости от порядка инициализации.

Ядро WordPress имеет много общего с глобальным использованием. Пытаясь понять, как работают основные функции, такие как the_content, вы внезапно понимаете, что $moreпеременная не локальная, а глобальная, и вам нужно выполнить поиск по всем основным файлам, чтобы понять, когда для нее установлено значение true.

Итак, что можно сделать, пытаясь остановить копирование и вставку нескольких строк кода вместо сохранения результата первого запуска в глобальном формате? Существует несколько подходов, функциональных и ООП.

Функция подсластителя. Это просто оболочка / макрос для сохранения копии / вставки

// 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;
} 

Это дает вам то же поведение глобального, но с преимуществом гарантированной инициализации каждый раз, когда вы получаете к нему доступ.

Вы можете иметь похожие шаблоны с ООП. Я считаю, что ООП обычно не добавляет никакой ценности в плагины и темы, но это другое обсуждение

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
Я думаю, что вы не поняли ответ. Если бы он не пытался провести раннюю оптимизацию, сохраняя значения в глобальных переменных, его код работал бы. Кричать это потому, что следовать базовым устоявшимся принципам разработки программного обеспечения невозможно. Люди, которые не понимают этот основной принцип (доступный в вашем местном гугле), не должны распространять код по сети.
Марк Каплун
1
IMO, это ответ, люди, которые приходят сюда из Google, должны видеть, что это плохая идея - даже подумать об использовании глобальных переменных сразу.
Марк Каплун
6
Недостаточно сказать «не делай Х», ты должен объяснить, почему, или ты выглядишь так, будто говоришь это по прихоти
Том Дж. Новелл
1
@ TomJNowell, я нахожу забавным, что я был единственным, кто отрицал сам вопрос, так как он явно выходил за рамки WASE. Я не видел смысла расширяться на предмет, который не должен был быть начат здесь вообще.
Марк Каплун
8

Ваш вопрос связан с тем, как работает PHP.

Возьми $ wpdb качестве примера

$ wpdb - известная глобальная переменная.

Вы знаете, когда он будет объявлен и назначен со значениями?

Каждая страница загружена , да, каждый раз, когда вы посещаете ваш WordPress сайт.

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

Хотя я не дизайнер тем, я могу сказать, что after_setup_theme - одноразовый хук. он будет срабатывать только при активации темы.

Если бы я был тобой, я бы использовал init или другие хуки. Нет, на вашем месте я вообще не буду использовать глобальные переменные ...

Я действительно не очень хорошо объясняю вещи. Итак, вы должны взять книгу, если вы хотите углубиться в 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
jgraup
источник