Làm thế nào để thiết lập và sử dụng các biến toàn cục? Hoặc tại sao không sử dụng chúng


27

CẬP NHẬT: Câu hỏi ban đầu của tôi đã được giải quyết, nhưng điều này đang chuyển thành một cuộc thảo luận hợp lệ về lý do tại sao không sử dụng các biến toàn cục, vì vậy tôi đang cập nhật câu hỏi để phản ánh điều đó. Giải pháp là <?php global $category_link_prop; echo esc_url( $category_link_prop ); ?>như @TomJNowell đề xuất.

CẬP NHẬT 2: Bây giờ tôi có nó làm chính xác những gì tôi muốn. Nhưng tôi vẫn đang sử dụng phạm vi toàn cầu và sẽ rất vui khi tìm thấy một cách tốt hơn.

Tôi đang cố gắng thiết lập một loạt các biến toàn cục cho permalinks đến các danh mục sẽ được sử dụng ở nhiều nơi trong chủ đề của tôi. Lý do chính cho việc này là để sử dụng trong cả điều hướng chính, cũng như trong một loạt các điều hướng phụ được chọn dựa trên danh mục bài đăng hiện tại. Đây không phải là chủ đề tôi sẽ phát hành để sử dụng cho người khác, nhưng được xây dựng cho một mục đích rất cụ thể.

Đây là cách tôi hiện đang tạo chúng (Tôi chỉ dán một vài biến).

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

Bây giờ tôi có thể thực hiện <?php global $prop; echo $prop; ?>int he 4 nơi mà đi và lấy lại toàn bộ liên kết cho mã. Khi điều đó thay đổi tôi chỉ cần thay đổi nó ở một nơi. Tôi mở cho các lựa chọn thay thế không liên quan đến phạm vi toàn cầu.


1
Liên kết nào thực hiện câu lệnh này echo esc_url ($ category_link_prop); màn hình? Liên kết dự kiến ​​của bạn là gì?
Vinod Dalvi

1
Tại sao bạn không chỉ sử dụng 'get_cat_ID (****)' khi bạn dự định sử dụng biến toàn cục. Tôi nghi ngờ sẽ có bất kỳ lợi thế tốc độ nào trong cách bạn làm điều đó. Từ quan điểm dễ đọc, 'get_cat_ID (****)' sẽ chiến thắng.
Chris Strutton

1
Bạn có thể tua lại? Tôi đã đọc câu hỏi của bạn và tôi vẫn không chắc chắn về những gì bạn muốn làm và tại sao bạn muốn làm điều đó. Lời khuyên chung của tôi là không sử dụng các biến toàn cầu và không gây ô nhiễm phạm vi toàn cầu
Tom J Nowell

1
này nghe có vẻ hơi giống một X / Y Vấn đề . có lẽ bạn nên sao lưu và giải thích chính xác kết quả mong muốn của bạn là gì. Tôi chắc chắn có một giải pháp tao nhã hơn nhiều so với việc thiết lập một loạt các vars toàn cầu để sau đó chỉ tham chiếu mã cứng đến chúng trong một hải quân ở nơi khác
Milo

2
tạo một hàm xuất ra menu của bạn dựa trên ngữ cảnh bạn truyền cho nó, theo cách đó bạn có thể giữ tất cả logic của menu và các vars liên quan được gói gọn ở một nơi.
Milo

Câu trả lời:


21

Mặc dù tôi thực sự khuyên bạn nên chống lại điều này và nó sẽ không tăng tốc, nhưng cách sử dụng của bạn không chính xác.

Khi bạn cố gắng sử dụng toàn cầu, trước tiên bạn phải xác định từ khóa toàn cầu. Bạn đã chỉ định nó ở đây khi xác định giá trị của nó, nhưng ngoài phạm vi đó, nó cần được xác định lại dưới dạng biến phạm vi toàn cục.

ví dụ: trong hàm.php:

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

Trong single.php, điều này sẽ không hoạt động:

echo $hello;

Bởi vì $ xin chào là không xác định. Điều này tuy nhiên sẽ hoạt động:

global $hello;
echo $hello;

Tất nhiên bạn không nên làm. WordPress đã cố gắng lưu trữ những thứ này trong bộ đệm đối tượng. Bạn sẽ thấy không tăng tốc độ khi làm điều này (bạn có thể thấy tốc độ giảm rất nhỏ), tất cả những gì bạn sẽ nhận được là sự phức tạp bổ sung và cần phải loại ra rất nhiều tuyên bố toàn cầu không cần thiết.

Bạn sẽ tốt hơn khi sử dụng dữ liệu có cấu trúc, chẳng hạn như các đối tượng hoặc nội xạ phụ thuộc hoặc trong trường hợp của bạn, một tập hợp các hàm.

Ví dụ, đây là một phương tiện để thực hiện một cái gì đó tương tự thông qua các biến tĩnh (vẫn xấu vì cùng lý do, nhưng chỉ cần một chút ít hơn và dễ gõ hơn), vd

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

Nếu bạn thực sự muốn tiết kiệm thời gian bằng cách lưu trữ dữ liệu ở đâu đó để sử dụng lại, hãy xem xét sử dụng WP_Cachehệ thống với wp_cache_getvv


Tôi biết đó là một chút hạt để sử dụng phạm vi toàn cầu, nhưng hầu hết, nếu không phải tất cả các biến này sẽ được sử dụng trên mỗi trang. Tôi đang mở cho những ý tưởng tốt hơn. Tôi sẽ chỉnh sửa câu hỏi để làm cho ý định của tôi rõ ràng hơn một chút. BTW nó hoạt động hoàn toàn tốt khi tôi làm <?php global $category_link_prop; echo esc_url( $category_link_prop ); ?>theo đề nghị của bạn. Cảm ơn!
JPollock

2
Ah nếu giải pháp của tôi hoạt động, bạn có thể đánh dấu là chấp nhận? Các biến toàn cục của bạn cũng nhanh như thực hiện cuộc gọi ban đầu, thay vào đó bạn có thể muốn thử sử dụng các hàm vì vậy bạn không cần phải gõ 2 dòng, tốt hơn nữa, một đơn, tốt hơn, làm cho tất cả các động đó và trong một phần mẫu được bao gồm thông qua get_template_part
Tom J Nowell

Được đánh dấu là chấp nhận như những gì tôi đang làm hiện tại mặc dù tôi có thể đi với một trong những chiến lược mà @MarkKaplun đang đề xuất dưới đây. Sử dụng get_template_part () là một ý tưởng thú vị, nhưng tôi không chắc chắn tôi muốn có một thư mục chứa đầy các tệp ngắn như thế ...
JPollock

oooh không không bạn sẽ không muốn một tập tin cho mỗi thể loại, bạn chỉ muốn một tập tin lấy tên danh mục hiện tại và sử dụng nó. Bạn không cần phải mã hóa bất cứ thứ gì, hãy tưởng tượng sự rắc rối của việc mã hóa tất cả
Tom J Nowell

Tôi đặt mã trong tệp con.php của tôi đang hoạt động. Nhưng tôi không thể truy cập vào biến trong tệp bao gồm php mà tôi gọi từ một bài đăng được tạo cơ sở dữ liệu "bình thường". Xin tư vấn cho tôi, tôi làm gì sai? (Tất nhiên, tôi xác định nó là toàn cầu.)
ycc_swe

19

Đừng sử dụng các biến toàn cục , đơn giản như vậy.

Tại sao không sử dụng toàn cầu

Bởi vì việc sử dụng toàn cầu khiến cho việc duy trì phần mềm trong thời gian dài trở nên khó khăn hơn.

  • Một toàn cầu có thể được khai báo ở bất cứ đâu trong mã, hoặc không ở đâu cả, do đó không có nơi nào bạn có thể nhìn vào bản năng để tìm một số nhận xét về những gì toàn cầu được sử dụng cho
  • Trong khi đọc mã, bạn thường cho rằng các biến là cục bộ của hàm và không hiểu rằng việc thay đổi giá trị của chúng trong hàm có thể có một sự thay đổi toàn hệ thống.
  • Nếu chúng không xử lý đầu vào, các hàm sẽ trả về cùng giá trị / đầu ra khi chúng được gọi với cùng tham số. Việc sử dụng toàn cầu trong một hàm giới thiệu các tham số bổ sung không phải là tài liệu trong khai báo hàm.
  • toàn cầu không có bất kỳ cấu trúc khởi tạo cụ thể nào và do đó bạn không bao giờ có thể chắc chắn khi nào bạn có thể truy cập giá trị của toàn cầu và bạn không gặp phải bất kỳ lỗi nào khi cố gắng truy cập toàn cầu trước khi khởi tạo.
  • Một số người khác (có thể là một plugin) có thể sử dụng các quả cầu có cùng tên, làm hỏng mã của bạn hoặc bạn làm hỏng mã tùy thuộc vào thứ tự khởi tạo.

Lõi WordPress có cách sử dụng nhiều trên toàn cầu. Trong khi cố gắng hiểu làm thế nào các chức năng cơ bản như the_contentcông việc, bạn đột nhiên nhận ra rằng$more biến không phải là cục bộ mà là toàn cầu và cần tìm kiếm toàn bộ các tệp cốt lõi để hiểu khi nào nó được đặt thành đúng.

Vì vậy, những gì có thể được thực hiện khi cố gắng dừng sao chép và dán một số dòng mã thay vì lưu trữ kết quả chạy đầu tiên trong toàn cầu? Có một số cách tiếp cận, chức năng và OOP.

Các chức năng làm ngọt. Nó chỉ đơn giản là một trình bao bọc / macro để lưu bản sao / dán

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

Lợi ích là bây giờ đã có tài liệu về những gì toàn cầu trước đây làm và bạn có một điểm rõ ràng để gỡ lỗi khi giá trị được trả về không phải là giá trị bạn mong đợi.

Một khi bạn có một chất làm ngọt, thật dễ dàng để lưu trữ kết quả nếu cần (chỉ thực hiện nếu bạn phát hiện ra rằng chức năng này mất nhiều thời gian để thực hiện)

function notaglobal($id) {
  static $cache;

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

Điều này mang lại cho bạn hành vi tương tự của toàn cầu nhưng với lợi thế là có một khởi tạo được đảm bảo mỗi khi bạn truy cập nó.

Bạn có thể có các mẫu tương tự với OOP. Tôi thấy rằng OOP thường không thêm bất kỳ giá trị nào trong plugin và chủ đề, nhưng đây là một cuộc thảo luận khác

class notaglobal {
   var latestfoo2;

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

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

Đây là một mã vụng về, nhưng nếu bạn có một vài giá trị mà bạn muốn tính toán trước bởi vì chúng luôn được sử dụng, đây có thể là một cách để đi. Về cơ bản đây là một đối tượng có chứa tất cả các quả cầu của bạn một cách có tổ chức. Để tránh biến một thể hiện của đối tượng này thành toàn cục (bạn muốn không phải là một thể hiện nếu không bạn tính toán lại các giá trị), bạn có thể muốn sử dụng một mẫu đơn (một số người cho rằng đó là một ý tưởng tồi, YMMV)

Tôi không muốn truy cập trực tiếp vào một thuộc tính đối tượng, vì vậy trong mã của tôi, nó sẽ làm cong thêm một số

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
Làm ơn đừng hét lên . Tâm trí để giải thích tại sao và cung cấp một số loại trích dẫn?
brasofilo

Tôi nghĩ rằng bạn đã hiểu nhầm câu trả lời. Nếu anh ta không cố gắng tối ưu hóa sớm bằng cách lưu trữ các giá trị trong các biến toàn cục thì mã của anh ta sẽ hoạt động. Tiếng hét là bởi vì tuân theo các nguyên tắc phát triển phần mềm được thiết lập cơ bản là điều không thể nhấn mạnh đủ. Những người không hiểu các nguyên tắc cơ bản đó (có sẵn tại google địa phương của bạn) không nên truyền bá mã qua mạng.
Đánh dấu Kaplun

1
IMO đây là một câu trả lời, những người đến đây từ google sẽ thấy rằng đó là một ý tưởng tồi để thậm chí nghĩ về việc sử dụng toàn cầu ngay lập tức.
Đánh dấu Kaplun

6
Không đủ để nói không làm X, bạn phải giải thích lý do tại sao hoặc bạn trông giống như bạn đang nói điều đó một cách bất chợt
Tom J Nowell

1
@TomJNowell, tôi thấy buồn cười vì tôi là người duy nhất hạ thấp câu hỏi, vì nó rõ ràng nằm ngoài phạm vi của WASE. Tôi không thấy giá trị của việc mở rộng về một chủ đề không nên bắt đầu ở đây.
Đánh dấu Kaplun

8

Câu hỏi của bạn liên quan đến cách php hoạt động.

Lấy $ wpdb làm ví dụ

$ wpdb là một biến toàn cầu nổi tiếng.

Bạn có biết khi nào nó sẽ được khai báo và gán với các giá trị không?

Mỗi trang được tải , vâng, mỗi khi bạn truy cập trang web wordpress của bạn.

Tương tự, bạn cần đảm bảo rằng các biến mà bạn muốn được toàn cầu hóa sẽ được khai báo và gán với các giá trị tương ứng mỗi trang được tải.

Mặc dù tôi không phải là nhà thiết kế chủ đề, tôi có thể nói after_setup_theme là hook một lần. nó sẽ chỉ được kích hoạt khi kích hoạt chủ đề.

Nếu tôi là bạn, tôi sẽ sử dụng init hoặc các hook khác. Không, nếu tôi là bạn, tôi sẽ không sử dụng biến toàn cục ...

Tôi thực sự không giỏi trong việc giải thích mọi thứ. Vì vậy, bạn nên chọn một cuốn sách nếu bạn muốn tìm hiểu sâu về PHP.


2

Bạn luôn có thể sử dụng một mẫu singleton thông qua các getters tĩnh.

<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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.