Bagaimana cara mengatur dan menggunakan variabel global? Atau mengapa tidak menggunakannya sama sekali

27

UPDATE: Pertanyaan asli saya telah dipecahkan, tetapi ini berubah menjadi diskusi yang valid tentang mengapa tidak menggunakan variabel global, jadi saya memperbarui pertanyaan untuk mencerminkan itu. Solusinya adalah <?php global $category_link_prop; echo esc_url( $category_link_prop ); ?>seperti yang disarankan @TomJNowell.

UPDATE 2: Saya sekarang melakukan apa yang saya inginkan. Tapi saya masih menggunakan lingkup global dan akan senang menemukan cara yang lebih baik.

Saya mencoba mengatur sejumlah variabel global untuk permalink ke kategori yang akan digunakan di berbagai tempat dalam tema saya. Alasan utama untuk ini adalah untuk digunakan di kedua navigasi utama, serta dalam serangkaian sub navigasi yang dipilih berdasarkan pada kategori apa posting saat ini masuk. Ini bukan tema saya akan merilis untuk digunakan oleh orang lain, tetapi dibangun untuk satu tujuan yang sangat spesifik.

Inilah cara saya membuat mereka saat ini (saya hanya menempelkan beberapa variabel).

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

Sekarang saya bisa melakukan <?php global $prop; echo $prop; ?>4 tempat yang masuk dan mendapatkan kembali seluruh tautan untuk kode. Ketika itu berubah, saya hanya perlu mengubahnya di satu tempat. Saya terbuka untuk alternatif yang tidak melibatkan lingkup global.

JPollock
sumber
1
Tautan mana yang digemakan oleh pernyataan ini esc_url ($ category_link_prop); menampilkan? Apa tautan yang Anda harapkan?
Vinod Dalvi
1
Mengapa Anda tidak menggunakan 'get_cat_ID (****)' di mana pun Anda berencana menggunakan variabel global. Saya ragu akan ada keuntungan kecepatan seperti cara Anda melakukannya. Dari sudut pandang keterbacaan, 'get_cat_ID (****)' menang dengan mudah.
Chris Strutton
1
Bisakah Anda menulis ulang? Saya membaca pertanyaan Anda dan saya masih ragu dengan apa yang ingin Anda lakukan dan mengapa Anda ingin melakukannya. Saran umum saya adalah tidak menggunakan variabel global, dan tidak mencemari ruang lingkup global
Tom J Nowell
1
ini terdengar sedikit seperti Y Soal X / . mungkin Anda harus membuat cadangan dan menjelaskan dengan tepat apa hasil yang Anda inginkan. Saya yakin ada solusi yang jauh lebih elegan daripada mengatur banyak var global untuk kemudian hanya referensi hardcode kepada mereka di nav di tempat lain
Milo
2
buat fungsi yang menampilkan menu Anda berdasarkan konteks yang Anda lewati, dengan cara itu Anda dapat menyimpan semua logika menu dan vars terkait yang dirangkum dalam satu tempat.
Milo

Jawaban:

21

Meskipun saya sangat menyarankan ini, dan itu tidak akan mempercepat, penggunaan Anda tidak benar.

Ketika Anda mencoba menggunakan global Anda harus menentukan kata kunci global terlebih dahulu. Anda telah menentukannya di sini saat menentukan nilainya, tetapi di luar cakupan itu perlu didefinisikan ulang sebagai variabel cakupan global.

misalnya di functions.php:

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

Di single.php, ini tidak akan berfungsi:

echo $hello;

Karena $ hello tidak terdefinisi. Namun ini akan berhasil:

global $hello;
echo $hello;

Tentu saja Anda tidak harus melakukan keduanya. WordPress sudah mencoba untuk men-cache hal-hal ini di cache objek. Anda tidak akan melihat peningkatan kecepatan dari melakukan ini (Anda mungkin melihat penurunan kecepatan kecil), semua Anda akan dapatkan kompleksitas tambahan dan kebutuhan untuk mengetikkan banyak deklarasi global yang tidak perlu.

Anda akan lebih baik menggunakan data terstruktur, seperti objek atau injeksi ketergantungan, atau dalam kasus Anda, satu set fungsi.

Sebagai contoh, berikut ini adalah cara melakukan sesuatu yang serupa melalui variabel statis (masih buruk karena alasan yang sama, tetapi hanya sedikit lebih sedikit, dan lebih mudah untuk mengetik) misalnya

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

Jika Anda benar-benar ingin menghemat waktu dengan menyimpan data di suatu tempat untuk digunakan kembali, pertimbangkan untuk menggunakan WP_Cachesistem dengan wp_cache_getdll

Tom J Nowell
sumber
Saya tahu ini sedikit gila untuk menggunakan lingkup global, tetapi kebanyakan, jika tidak semua variabel ini akan digunakan pada setiap halaman. Saya terbuka untuk ide yang lebih baik. Saya akan mengedit pertanyaan untuk memperjelas maksud saya. BTW berfungsi dengan baik ketika saya melakukan <?php global $category_link_prop; echo esc_url( $category_link_prop ); ?>sesuai saran Anda. Terima kasih!
JPollock
2
Ah, jika solusi saya berhasil, bisakah Anda menandai sebagai diterima? Variabel global Anda sama cepatnya dengan membuat panggilan asli, Anda mungkin ingin mencoba alih-alih menggunakan fungsi sehingga Anda tidak perlu mengetik 2 baris, lebih baik lagi, tunggal, lebih baik lagi, buat semua itu dinamis dan dalam bagian templat disertakan melalui get_template_part
Tom J Nowell
Ditandai sebagai diterima sebagai apa yang saya lakukan sekarang meskipun saya mungkin pergi dengan salah satu strategi @ MarkKaplun menyarankan di bawah ini. Menggunakan get_template_part () adalah ide yang menarik, tapi saya tidak yakin ingin memiliki direktori penuh dengan file pendek seperti itu ...
JPollock
oooh tidak, tidak, Anda tidak ingin file untuk setiap kategori, Anda hanya ingin yang mengambil nama kategori saat ini dan menggunakannya. Anda tidak perlu melakukan hardcode apa pun, bayangkan kerumitan hardcoding semuanya
Tom J Nowell
Saya meletakkan kode di child-functions.php saya yang aktif. Tapi saya tidak bisa mengakses variabel dalam file php-include yang saya panggil dari posting yang dibuat database "normal". Tolong beri tahu saya, apa yang saya lakukan salah? (Saya mendefinisikannya sebagai global, tentu saja.)
ycc_swe
19

Jangan gunakan variabel global , sesederhana itu.

Mengapa tidak menggunakan global

Karena penggunaan global mempersulit pemeliharaan perangkat lunak dalam jangka panjang.

  • Global dapat dideklarasikan di mana saja dalam kode, atau tidak ada sama sekali, karena itu tidak ada tempat di mana Anda dapat melihat secara naluriah untuk menemukan beberapa komentar tentang apa global digunakan untuk
  • Saat membaca kode Anda biasanya mengasumsikan bahwa variabel lokal untuk fungsi dan tidak mengerti bahwa mengubah nilai mereka dalam suatu fungsi mungkin memiliki perubahan sistem yang luas.
  • Jika mereka tidak menangani input, fungsi harus mengembalikan nilai / output yang sama ketika mereka dipanggil dengan parameter yang sama. Penggunaan global dalam suatu fungsi memperkenalkan parameter tambahan yang tidak didokumentasikan dalam deklarasi fungsi.
  • global tidak memiliki konstruk inisialisasi spesifik dan karenanya Anda tidak pernah dapat memastikan kapan Anda dapat mengakses nilai global, dan Anda tidak mendapatkan kesalahan apa pun ketika mencoba mengakses global sebelum inisialisasi.
  • Orang lain (mungkin sebuah plugin) mungkin menggunakan global dengan nama yang sama, merusak kode Anda, atau Anda merusaknya tergantung pada urutan inisialisasi.

Inti WordPress memiliki banyak cara untuk banyak menggunakan global. Saat mencoba memahami bagaimana fungsi dasar seperti the_contentbekerja, Anda tiba-tiba menyadari bahwa $morevariabelnya bukan lokal tetapi global dan perlu mencari seluruh file inti untuk memahami kapan itu disetel ke true.

Jadi, apa yang dapat dilakukan ketika mencoba menghentikan penyalinan & menempel beberapa baris kode alih-alih menyimpan hasil run pertama di global? Ada beberapa pendekatan, fungsional dan OOP.

Fungsi pemanis. Ini hanyalah pembungkus / makro untuk menyimpan copy / paste

// input: $id - the category id
// returns: the foo2 value of the category
function notaglobal($id) {
  $a = foo1($id);
  $b = foo2($a);
  return $b;
}

Keuntungannya adalah sekarang ada dokumentasi untuk apa yang dilakukan oleh global sebelumnya, dan Anda memiliki titik jelas untuk debugging ketika nilai yang dikembalikan bukan yang Anda harapkan.

Setelah Anda memiliki pemanis, mudah untuk men-cache hasil jika diperlukan (lakukan hanya jika Anda menemukan bahwa fungsi ini membutuhkan waktu lama untuk dijalankan)

function notaglobal($id) {
  static $cache;

  if (!isset($cache)) {
    $a = foo1($id);
    $b = foo2($a);
    $cache = $b;
  } 
  return $cache;
} 

Ini memberi Anda perilaku global yang sama tetapi dengan keuntungan memiliki inisialisasi yang terjamin setiap kali Anda mengaksesnya.

Anda dapat memiliki pola yang mirip dengan OOP. Saya menemukan bahwa OOP biasanya tidak menambah nilai dalam plugin dan tema, tetapi ini adalah diskusi yang berbeda

class notaglobal {
   var latestfoo2;

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

$v = new notaglobal($cat_id);
echo $v->latestfoo2;

Ini adalah kode clumsier, tetapi jika Anda memiliki beberapa nilai yang ingin Anda lakukan karena selalu digunakan, ini bisa menjadi cara untuk melakukannya. Pada dasarnya ini adalah objek yang berisi semua global Anda secara terorganisir. Untuk menghindari membuat instance objek ini menjadi global (Anda ingin satu instance jika tidak, Anda menghitung ulang nilai-nilai) Anda mungkin ingin menggunakan pola tunggal (beberapa orang berpendapat itu adalah ide yang buruk, YMMV)

Saya tidak suka mengakses atribut objek secara langsung, jadi dalam kode saya itu akan warpe lagi

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);
Mark Kaplun
sumber
7
Tolong, jangan berteriak . Pikiran untuk menjelaskan mengapa dan memberikan semacam kutipan?
brasofilo
Saya pikir Anda salah paham jawabannya. Jika dia tidak mencoba melakukan optimasi awal dengan menyimpan nilai-nilai dalam variabel global kodenya akan berhasil. Teriakan itu karena mengikuti prinsip-prinsip dasar pengembangan perangkat lunak yang sudah mapan adalah sesuatu yang tidak bisa ditekankan cukup. Orang yang tidak memahami prinsip dasar tersebut (tersedia di google lokal Anda) tidak boleh menyebarkan kode melalui internet.
Mark Kaplun
1
IMO ini adalah jawaban, orang-orang yang datang ke sini dari google harus melihat bahwa itu adalah ide yang buruk untuk berpikir tentang menggunakan global segera.
Mark Kaplun
6
Tidak cukup untuk mengatakan jangan lakukan X, Anda harus menjelaskan mengapa atau Anda sepertinya mengatakannya sambil lalu
Tom J Nowell
1
@ TomJNowell, saya merasa lucu bahwa saya adalah satu-satunya yang menolak pertanyaan itu sendiri, karena itu jelas di luar lingkup WASE. Saya tidak melihat nilai ekspansi pada subjek yang seharusnya tidak dimulai di sini sama sekali.
Mark Kaplun
8

Pertanyaan Anda terkait dengan cara kerja php.

Ambil $ wpdb sebagai contoh

$ wpdb adalah variabel global yang terkenal.

Apakah Anda tahu kapan itu akan dinyatakan dan ditugaskan dengan nilai-nilai?

Setiap halaman dimuat , ya, setiap kali Anda mengunjungi situs wordpress Anda.

Demikian pula, Anda perlu memastikan variabel-variabel yang ingin diglobalisasi akan dideklarasikan dan ditugaskan dengan nilai yang sesuai setiap halaman yang dimuat.

Meskipun saya bukan seorang desainer tema, saya dapat mengatakan bahwa after_setup_theme adalah pengait waktu. itu hanya akan dipicu ketika tema diaktifkan.

Jika saya jadi Anda, saya akan menggunakan init atau kait lainnya. Tidak, jika saya jadi Anda, saya tidak akan menggunakan variabel global sama sekali ...

Saya benar-benar tidak pandai menjelaskan banyak hal. Jadi, Anda harus mengambil buku jika ingin mempelajari PHP.

Jesse
sumber
2

Anda selalu dapat menggunakan pola tunggal melalui getter statis.

<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
jgraup
sumber