当前位置: 首页>>技术解读>>正文


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

webfans 技术解读 , , , 去评论

问题描述

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

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

我现在可以在4个地方做<?php global $prop; echo $prop; ?>并返回代码的整个链接。当改变时我只需要在一个地方改变它。我对那些不涉及全球范围的替代方案持开放态度。

最佳解决办法

虽然我强烈建议不要这样做,但它不会加速,你的使用是不正确的。

当您尝试使用全局时,必须首先指定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

如果您真的想通过将数据存储到re-use来节省时间,请考虑将WP_Cache系统与wp_cache_get等一起使用

次佳解决办法

不要使用全局变量,就这么简单。

为什么不使用全局变量

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

  • 可以在代码中的任何地方声明全局,或者根本没有声明,因此没有地方可以直观地查找关于全局用于什么的一些注释

  • 在阅读代码时,您通常会认为变量是函数的本地变量,并且不理解在函数中更改它们的值可能会发生系统范围的更改。

  • 如果它们不处理输入,则在使用相同参数调用函数时,函数应返回相同的值/输出。在函数中使用全局变量会引入其他参数,这些参数不是函数声明中的文档。

  • globals没有任何特定的初始化构造,因此您永远无法确定何时可以访问全局值,并且在初始化之前尝试访问全局时不会出现任何错误。

  • 其他人(可能是插件)可能会使用具有相同名称的全局变量,破坏您的代码,或者根据初始化顺序破坏它。

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;

这是一个笨拙的代码,但是如果你想要预先计算几个值,因为它们总是被使用,这可能是一种方法。基本上这是一个以有组织的方式包含所有全局变量的对象。为了避免使这个对象的实例成为全局(你想要一个实例,否则你重新计算值)你可能想要使用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);

第三种解决办法

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

以$ wpdb为例

$ wpdb是一个well-known全局变量。

你知道什么时候会被宣布并分配价值吗?

每次访问wordpress网站时,每个页面都会加载。

同样,您需要确保声明那些要全局化的变量,并在每个页面加载时为其分配相应的值。

虽然我不是主题设计师,但我可以告诉after_setup_theme是一次性挂钩。它只会在主题激活时触发。

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

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

第四种办法

您始终可以通过静态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

参考资料

本文由朵颐IT整理自网络, 文章地址: https://duoyit.com/article/2577.html,转载请务必附带本地址声明。