更新:我原来的问题已经解决,但这正在变成关于为什么不使用全局变量的有效讨论,因此我正在更新问题以反映这一点。解决方案是@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; ?>,然后取回代码的整个链接。当这种变化发生时,我只需要在一个地方进行更改。我愿意接受不涉及全球范围的替代方案。

评论

该语句回显了哪个链接esc_url($ category_link_prop);显示?您期望的链接是什么?

为什么您不打算在计划使用全局变量的地方仅使用“ get_cat_ID(****)”。我怀疑您这样做的方式是否会带来速度优势。从可读性的角度来看,'get_cat_ID(****)'毫无疑问。

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

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

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

#1 楼

虽然我强烈建议您这样做,但这样做不会加快速度,但您的用法是错误的。

WordPress已经将这些内容缓存在对象缓存中,您无需存储结果并重复使用, WP已经做到了。

由于这种微优化,您的代码运行速度可能很慢,而不是更快!

如何使用全局变量

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

例如在functions.php中:

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


single.php中,这将不起作用:

     echo $hello;
 


因为$hello是未定义的。但是,这将起作用:

     global $hello;
    echo $hello;
 


当然,您都不应该这样做。 WordPress已经尝试将这些内容缓存到对象缓存中。

全局变量的缺点和危险

这样做不会使速度提高(您可能会看到很小的速度)减少),您将得到的只是额外的复杂性,并且需要键入很多不必要的全局声明。

您还将遇到其他问题:


无法编写测试的代码
每次运行时行为都会不同的代码
共享名称空间中的变量名称发生冲突
忘记声明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
 


Singletons

Singletons类似于静态变量,只是该类包含带有该类实例的静态变量。它们和全局变量一样糟糕,只是语法不同。避免使用它们。

WP_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的工作方式。与Node应用程序不同,每个请求都加载该应用程序的新副本,然后在请求完成时死亡。因此,在一个请求上设置的全局变量无法保留到下一个请求。

侧注2:从更新后的问题来看,您的全局变量根本无法提高性能。您只需要在需要时生成HTML,它就会以同样快的速度运行,甚至可能快一点。这是微优化。

评论


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

–JPollock
13 Mar 5 '13 at 0:34



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

– Tom J Nowell♦
13年5月5日在9:59

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

–JPollock
13年6月6日在10:12

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

– Tom J Nowell♦
13年6月6日在10:45

我将代码放入了活跃的child-functions.php中。但是我无法从“正常”数据库生成的帖子中调用的php-include文件中访问变量。请告诉我,我该怎么办? (当然,我将其定义为全局)。

–cvr
18年6月3日在14:37

#2 楼

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

为什么不使用全局变量

,因为使用全局变量会使长期维护该软件更加困难。


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


您具有与全局相同的行为,但是其优点是每次访问它时都可以确保进行初始化。

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


评论


求求你,不要喊。介意解释原因并提供某种引用?

–brasofilo
13年4月4日在8:04

我认为您误解了答案。如果他不打算通过将值存储在全局变量中来进行早期优化,那么他的代码将会奏效。大声疾呼是因为遵循已建立的基本软件开发原则是一件不够强调的事情。不了解这些基本原理的人(可在您当地的google上找到)不应将代码传播到网上。

–马克·卡普伦
13年4月4日在12:11

IMO这是一个答案,从Google来到这里的人们应该看到,甚至立即考虑使用globals是一个坏主意。

–马克·卡普伦
13年4月4日在12:43

仅仅说“不做X”还不够,您必须说明原因,或者看起来像是一时兴起

– Tom J Nowell♦
13年4月4日13:00

@TomJNowell,我觉得自己是唯一一个对问题本身不满意的人,这很有趣,因为它显然超出了WASE的范围。我没有看到扩展本不应该在这里开始的主题的价值。

–马克·卡普伦
13年5月5日在8:27

#3 楼

您的问题与php的工作方式有关。

以$ wpdb为例

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

你知道什么时候声明和分配它有值吗?

每次访问您的wordpress网站时,都是加载页面。

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

尽管我不是主题设计者,但我可以说after_setup_theme是一次钩子。仅在激活主题时才会触发。

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

我真的不擅长解释事物。因此,如果您想深入研究PHP,就应该读一本书。

#4 楼

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

<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