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

时间:2013-03-04 作者:JPollock

UPDATE: 我原来的问题已经解决了,但这变成了一个关于为什么不使用全局变量的有效讨论,所以我正在更新这个问题以反映这一点。解决方案是<?php global $category_link_prop; echo esc_url( $category_link_prop ); ?> 正如@TomJNowell所建议的那样。

UPDATE 2: 我现在让它完全按照我的要求来做。但我仍在使用global scope,我很乐意找到更好的方法。

我正在尝试为permalinks to类别设置一整套全局变量,以便在我的主题的各个地方使用<这样做的主要原因是用于主导航,以及根据当前帖子所属类别选择的一系列子导航

这就是我目前创建它们的方式(我只粘贴了几个变量)。

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个地方,可以找到代码的完整链接。当这种情况改变时,我只需要在一个地方改变它。我对不涉及全球范围的备选方案持开放态度。

4 个回复
最合适的回答,由SO网友:Tom J Nowell 整理而成

我强烈建议不要这样做not 加快速度,你的用法不正确。

WordPress already caches these things in the object cache/memory so it doesn\'t have to fetch it multiple times in the same request, you don\'t need to store the result and reuse, WP does that already out of the box.

很可能您的代码正在运行slower由于这一微观优化,而不是更快!

如何使用全局变量当您尝试使用全局变量时,必须指定global 关键字优先。您在定义其值时在此处指定了它,但在该范围之外,需要将其重新声明为全局范围变量。

e、 g.英寸functions.php :

    function test() {
        global $hello;
        $hello = \'hello world\';
    }
    add_action( \'after_setup_theme\', \'test\' );
在里面single.php, 这将不起作用:

    echo $hello;
因为$hello 未定义。然而,这will 工作:

    global $hello;
    echo $hello;
当然你两个都不应该做。WordPress already attempts to cache these things in the object cache.

全局变量的缺点和危险

这样做不会增加速度(速度可能会略有下降),只会增加复杂性,需要键入大量不必要的全局声明。

您还将遇到其他问题:

无法为每次运行时表现不同的代码编写测试的代码在共享名称空间中的变量名冲突导致忘记声明意外错误global您最好使用结构化数据,例如对象或依赖项注入,或者在您的情况下,使用一组函数。

静态变量

静态变量并不好,但可以认为它们是全局变量中稍微不那么邪恶的近亲。静态变量之于全局变量,就像泥面包之于氰化物。

例如,这里有一种通过静态变量执行类似操作的方法,例如:。

    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\\u Cache,您尝试过但WP已经做到了这一点如果您真的想通过将数据存储到某个地方以供重用来节省时间,请考虑使用WP_Cache 系统与wp_cache_get 等等,例如。

$value = wp_cache_get( \'hello\' );
if ( false === $value ) {
    // not found, set the default value
    wp_cache_set( \'hello\', \'world\' );
}
现在,WordPress将在请求的整个生命周期内缓存该值,并显示在调试工具中,如果您有对象缓存,它将在多个请求之间持久存在

旁注1:我要指出的是,有些人试图跨请求将数据持久化到全局变量中,却没有意识到这不是PHP的工作方式。与节点应用程序不同,每个请求都会加载应用程序的一个新副本,该副本在请求完成后会消失。因此,在一个请求上设置的全局变量不会保留到下一个请求

旁注2:从更新后的问题来看,您的全局变量没有给您带来任何性能提升。您应该在需要的时候生成HTML,它的运行速度也一样快,甚至可能快一点。这是微观优化。

SO网友:Mark Kaplun

Don\'t use global variables, 就这么简单。

Why not to use globals

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

global可以在代码中的任何地方声明,也可以在任何地方声明,因此没有任何地方可以让您本能地查看以找到有关global用于什么的注释。在阅读代码时,您通常假设变量是函数的局部变量,并且不理解在函数中更改它们的值可能会导致系统范围的更改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;
} 
这为您提供了全局的相同行为,但其优点是每次访问它时都有一个可靠的初始化。

使用OOP可以有类似的模式。我发现OOP通常不会在插件和主题中增加任何价值,但这是一个不同的讨论

class notaglobal {
   var latestfoo2;

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

$v = new notaglobal($cat_id);
echo $v->latestfoo2;
这是一个比较笨拙的代码,但如果您有几个值要预计算,因为它们总是被使用,那么这可能是一种方法。基本上,这是一个以有组织的方式包含所有全局变量的对象。为了避免将此对象的实例设为全局实例(您只需要一个实例,否则将重新计算值),您可能需要使用singleton pattern (有些人认为这是个坏主意,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);

SO网友:Jesse

您的问题涉及php的工作原理。

$wpdb 作为示例

$wpdb 是一个众所周知的全局变量。

你知道什么时候它会被声明和赋值吗?

Every page loaded, 是的,每次你访问wordpress网站。

类似地,您需要确保要全球化的那些变量将在每个加载的页面上声明并分配相应的值。

虽然我不是一个主题设计师,但我可以断定after\\u setup\\u主题是一次性挂钩。它只会在主题激活时触发。

如果我是你,我会使用init或其他挂钩。不,如果我是你,我根本不会使用全局变量。。。

我真的不善于解释事情。因此,如果你想深入研究PHP,你应该读一本书。

SO网友:jgraup

您始终可以通过静态getter使用单例模式。

<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

结束