web-dev-qa-db-ja.com

グローバル変数を設定して使用する方法それともまったく使わないのか

更新: 私の最初の質問は解決されました、しかしこれはなぜグローバル変数を使わないのかについての有効な議論に変わりつつあるので、私はそれを反映するために質問を更新しています。 @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; ?>を実行して、コードへのリンク全体を元に戻すことができます。それが変わったとき、私はただ一箇所でそれを変える必要があります。私は地球規模の範囲を含まない代替案に寛容です。

27
JPollock

私はこれに対して強く勧めます、そしてそれは物事をスピードアップしませんが、あなたの用法は間違っています。

グローバルを使おうとするとき、最初に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などと一緒に使用して、再利用するためにデータをどこかに保存して時間を節約したい場合は、

21
Tom J Nowell

グローバル変数 は使わないでください。

なぜグローバルを使わないのか

グローバルを使用すると、ソフトウェアを長期的に保守することが難しくなります。

  • グローバルはコード内のどこにでも宣言できますし、どこにも宣言できません。そのため、グローバルが何のために使用されているのかについてコメントを見つけるために直感的に調べることができる場所はありません。
  • コードを読んでいる間は、通常、変数は関数に対してローカルであると想定しており、関数内で変数の値を変更するとシステム全体で変更される可能性があることを理解していません。
  • それらが入力を処理しない場合、それらが同じパラメータで呼び出されたとき、関数は同じ値/出力を返すべきです。関数内でグローバルを使用すると、関数宣言に記載されていない追加のパラメータが導入されます。
  • グローバルには特定の初期化コンストラクトがないため、グローバルの値にいつアクセスできるかを確実に判断することはできません。また、初期化の前にグローバルにアクセスしようとしてもエラーにはなりません。
  • 他の誰か(プラグインかもしれません)は、同じ名前のグローバルを使用しているかもしれません、あなたのコードを台無しにするか、あなたは初期化の順番に応じてそれを台無しにするでしょう。

WordPressコアには、グローバルを多用する方法がたくさんあります。 the_contentのような基本的な機能がどのように機能するかを理解しようとしている間に、$more変数がローカルではなくグローバルであることに突然気付きます。

それでは、最初の実行結果をグローバルに格納する代わりに、数行のコードをコピー&ペーストするのをやめようとしたときに何ができるでしょうか。機能的および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;

これは厄介なコードですが、いくつかの値があり、それらが常に使用されているために事前計算したい場合は、これを実行することができます。基本的にこれは組織的な方法であなたのグローバルのすべてを含むオブジェクトです。このオブジェクトのインスタンスをグローバルにしないようにするために(1つのインスタンスにはそうでなければ値を再計算します)、 シングルトンパターンを使用することをお勧めします (これは悪い考えだと主張する人もいます、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);
19
Mark Kaplun

あなたの質問はphpがどのように機能するかに関係しています。

例として $ wpdb を取ります。

$ wpdb は、よく知られているグローバル変数です。

いつ宣言され値が割り当てられるか知っていますか?

ロードされたすべてのページ または、あなたがワードプレスサイトにアクセスするたびに。

同様に、グローバル化したい変数が、ロードされるページごとに宣言され、対応する値で割り当てられるようにする必要があります。

私はテーマデザイナーではありませんが、after_setup_themeはワンタイムフックだと言えます。テーマが有効になったときにのみトリガーされます。

私があなただったら、initか他のフックを使います。いいえ、私があなただったら、グローバル変数はまったく使いません….

説明が苦手です。ですから、PHPについて詳しく知りたい場合は、本を拾う必要があります。

6
Jesse

あなたはいつでも静的な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
2
jgraup