如何设置和使用全局变量?或者为什么根本不使用它们


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); 显示?您期望的链接是什么?
Vinod Dalvi

1
为什么您不打算在打算使用全局变量的地方仅使用“ get_cat_ID(****)”。我怀疑您的操作方式是否会带来速度优势。从可读性的角度来看,'get_cat_ID(****)'实在是太难了。
克里斯·斯特鲁顿

1
你能改写吗?我阅读了您的问题,但仍不确定您想做什么以及为什么要这样做。我的一般建议是不要使用全局变量,也不要污染全局范围
Tom J Nowell

1
这听起来有点像X / Y问题。也许您应该备份并确切说明您期望的结果是什么。我敢肯定,比设置一堆全局变量然后在其他地方的导航中硬编码对它们的引用,还有一种更为优雅的解决方案
Milo

2
创建一个函数,该函数根据传递给它的上下文输出菜单,这样就可以将所有菜单逻辑和关联的var封装在一个地方。
米洛

Answers:


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_getetc一起使用


我知道使用全局范围有点麻烦,但是大多数(如果不是全部的话)这些变量将在每个页面上使用。我愿意接受更好的主意。我将编辑问题以使我的意图更加清楚。顺便说一句,我<?php global $category_link_prop; echo esc_url( $category_link_prop ); ?>按照您的建议做的很好。谢谢!
JPollock

2
啊,如果我的解决方案有效,您能否标记为已接受?您的全局变量与进行原始调用一样快,您可能想尝试使用函数,这样您就无需键入两行,更好的是,单例的,更好的是,使所有这些动态化,并且通过get_template_part包含的模板部分
Tom J Nowell

尽管我可能会采用@MarkKaplun提出的以下策略之一,但现在被标记为我现在正在做的事情。使用get_template_part()是一个有趣的主意,但我不确定我是否希望像这样的短文件充满目录...
JPollock 2013年

哦,不,您不希望每个类别都有一个文件,您只需要一个获取当前类别名称并使用该名称的文件即可。您无需进行任何硬编码,想象一下对所有内容进行硬编码的麻烦
Tom J Nowell

我将代码放在有效的child-functions.php中。但是我无法从“正常”数据库生成的帖子中调用的php-include文件中访问变量。请告诉我,我做错了什么?(我当然将其定义为全局)
。– ycc_swe

19

不要使用全局变量那么简单。

为什么不使用全局变量

因为全局变量的使用使长期维护软件变得更加困难。

  • 可以在代码中的任何地方或根本没有地方声明全局变量,因此没有地方可以本能地查找有关全局变量用途的注释。
  • 在阅读代码时,您通常会假设变量是函数的局部变量,并且不了解在函数中更改其值可能会导致系统范围的更改。
  • 如果它们不处理输入,则在使用相同参数调用函数时,它们应该返回相同的值/输出。在函数中使用全局变量会引入其他参数,这些参数不在函数声明中记录。
  • 全局变量没有任何特定的初始化构造,因此,您永远无法确定何时可以访问全局变量的值,并且在初始化之前尝试访问全局变量时也不会出现任何错误。
  • 其他人(可能是一个插件)可能使用具有相同名称的全局变量,从而破坏了代码,或者根据初始化顺序破坏了代码。

WordPress核心拥有大量使用全局变量的方式。在尝试了解基本功能的the_content工作方式时,您突然意识到该$more变量不是局部变量而是全局变量,因此需要搜索整个核心文件以了解何时将其设置为true。

那么,当尝试停止复制和粘贴几行代码而不是将第一次运行的结果存储在全局变量中时,该怎么办?有几种方法,功能性和OOP。

甜味剂功能。它只是用于保存副本/粘贴内容的包装器/宏

// 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来到这里的人们应该看到,甚至立即考虑使用globals是一个坏主意。
马克·卡普伦

6
仅仅说“不做X”还不够,您必须解释为什么还是看起来像是一时兴起
Tom J Nowell

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.