グローバル変数を設定および使用する方法は?または、それらをまったく使用しない理由


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); ディスプレイ?予想されるリンクは何ですか?
ヴィノッドダルビ

1
グローバル変数を使用する予定のある場所で「get_cat_ID(****)」を使用しないのはなぜですか。私はあなたがそれを行う方法の速度の利点があるとは思わない。読みやすさの観点から、「get_cat_ID(****)」が勝ちます。
クリスストラットン

1
言い換えることはできますか?私はあなたの質問を読みましたが、あなたが何をしたいのか、なぜあなたがそれをしたいのかまだわかりません。私の一般的なアドバイスは、グローバル変数を使用しないことであろう、そしてグローバルスコープ汚染しない
トム・J Nowell

1
これは、X / Y問題のように聞こえます。おそらく、バックアップして、希望する結果を正確に説明する必要があります。グローバル変数の束を設定して、他のナビゲーションに参照をハードコードするよりもはるかにエレガントなソリューションがあると確信しています
ミロ

2
メニューに渡すコンテキストに基づいてメニューを出力する関数を作成します。これにより、すべてのメニューロジックと関連する変数を1か所にカプセル化できます。
ミロ

回答:


21

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

グローバルを使用しようとするときは、最初にグローバルキーワードを指定する必要があります。値を定義するときにここで指定しましたが、そのスコープ外では、グローバルスコープ変数として再宣言する必要があります。

例えば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_Cachewp_cache_getetcなどでシステムを使用することを検討してください


グローバルスコープを使用するのは少し難しいことですが、これらの変数のすべてではなくてもほとんどがすべてのページで使用されます。私はより良いアイデアを受け入れています。質問を編集して、意図をもう少し明確にします。ところで、私が<?php global $category_link_prop; echo esc_url( $category_link_prop ); ?>あなたの提案に従ってすれば、それは完全にうまく機能します。ありがとう!
-JPollock

2
ああ、私の解決策がうまくいったら、受け入れられたとマークできますか?グローバル変数は元の呼び出しと同じくらい速いので、代わりに関数を使用して、2行を入力する必要がないようにすることができます。 get_template_partを介して含まれるテンプレートパーツ
トムJノウェル

@MarkKaplunが提案している戦略の1つを使用することもできますが、私が現在行っていることとして受け入れられているとマークされています。get_template_part()を使用するのは興味深いアイデアですが、そのような短いファイルでいっぱいのディレクトリが欲しいかどうかは
わかりません...-JPollock

いいえ、各カテゴリのファイルは必要ありません。現在のカテゴリ名を取得して使用するファイルだけが必要です。あなたはすべてのそれをハードコーディングの手間を想像し、打ち何もする必要はありません
トム・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;

これは扱いにくいコードですが、常に使用されているために事前に計算したい値がいくつかある場合、これは進むべき方法です。基本的に、これは組織化された方法ですべてのグローバルを含むオブジェクトです。このオブジェクトのインスタンスがグローバルにならないようにするには(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);

7
叫んはいけません。理由を説明し、ある種の引用を提供することに注意してください。
ブラソフィロ

あなたは答えを誤解したと思います。グローバル変数に値を保存することで初期の最適化を試みていなかった場合、彼のコードは機能していました。叫び声は、基本的な確立されたソフトウェア開発の原則に従うことは十分に強調できないものだからです。これらの基本原則を理解していない人(地元のグーグルで入手可能)は、コードをネット上に広めてはいけません。
マークカプルン

1
IMOこれは答えです。グーグルからここに来た人は、すぐにグローバルを使用することを考えるのも悪い考えだと思うはずです。
マークカプルン

6
Xをしてはいけないというだけでは不十分です。理由を説明する必要があるか、気まぐれに言っているように見える
トムJノウェル

1
@TomJNowell、私は質問自体をダウン票した唯一の人だったのはおもしろいと思います。明らかにそれはWASEの範囲外でした。ここで始めてはならない主題を拡張する価値はありませんでした。
マークカプルン

8

あなたの質問はphpの仕組みに関係しています。

テイク$ wpdbを例として

$ wpdbはよく知られたグローバル変数です。

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

ワードプレスサイトにアクセスするたびに、すべてのページが読み込まれます。

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

私はテーマデザイナーではありませんが、after_setup_themeは1回限りのフックであると言えます。テーマがアクティブになったときにのみトリガーされます。

私があなただったら、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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.