Mã này sẽ chạy bao nhiêu lần? (hoặc, bà giàu đến mức nào?)


20

Ví dụ giả thuyết nhưng khả năng ứng dụng trong thế giới thực (đối với người học, như tôi).

Cho mã này:

<?php

function send_money_to_grandma() {
     internetofThings("send grandma","$1");
}

add_action('init','send_money_to_grandma');
add_action('init','send_money_to_grandma');

ok, bây giờ tôi đưa lên trang WP của mình và đăng nhập. Tôi duyệt qua một vài trang trong Admin. Hành động 'init' bắn tổng cộng 100 lần trước khi pin laptop của tôi chết.

Câu hỏi đầu tiên: Chúng tôi đã gửi bao nhiêu tiền cho bà? Đó là $ 1, $ 2, $ 100 hay $ 200 (hoặc cái gì khác?)

Nếu bạn cũng có thể giải thích câu trả lời của bạn sẽ là tuyệt vời.

Câu hỏi thứ hai: Nếu chúng tôi muốn đảm bảo rằng chúng tôi chỉ gửi cho bà ngoại $ 1, cách tốt nhất để làm điều đó là gì? Biến toàn cầu (semaphore) được đặt 'true' lần đầu tiên chúng tôi gửi $ 1? Hoặc có một số thử nghiệm khác để xem nếu một hành động đã xảy ra và ngăn nó bắn nhiều lần?

Câu hỏi thứ ba: Đây có phải là điều mà các nhà phát triển plugin lo lắng? Tôi nhận ra ví dụ của tôi là ngớ ngẩn nhưng tôi đã nghĩ về cả vấn đề hiệu năng và các tác dụng phụ không mong muốn khác (ví dụ: nếu chức năng cập nhật / chèn vào cơ sở dữ liệu).


2
Phải thừa nhận, đây là một trong những câu hỏi hay nhất trong một thời gian dài ;-)
Pieter Goosen

Câu trả lời:


21

Dưới đây là một số suy nghĩ ngẫu nhiên về điều này:

Câu hỏi 1

Chúng tôi đã gửi bao nhiêu tiền cho bà?

Để tải 100 trang, chúng tôi đã gửi cho cô ấy 100 x $ 1 = 100 đô la.

Ở đây chúng tôi thực sự có nghĩa là 100 x do_action( 'init' )các cuộc gọi.

Chúng tôi đã thêm hai lần với:

add_action( 'init','send_money_to_grandma' );
add_action( 'init','send_money_to_grandma' );

bởi vì các cuộc gọi lạiưu tiên (mặc định 10) là giống hệt nhau .

Chúng ta có thể kiểm tra làm thế nào add_actionchỉ là một trình bao bọc để add_filterxây dựng $wp_filtermảng toàn cầu :

function add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
        global $wp_filter, $merged_filters;

        $idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority);
        $wp_filter[$tag][$priority][$idx] = array(
            'function'      => $function_to_add, 
            'accepted_args' => $accepted_args
        );
        unset( $merged_filters[ $tag ] );
        return true;
}

Tuy nhiên, nếu chúng tôi thay đổi mức độ ưu tiên:

add_action( 'init','send_money_to_grandma', 9 );
add_action( 'init','send_money_to_grandma', 10 );

sau đó chúng tôi sẽ gửi cho cô ấy 2 x $ 1 mỗi lần tải trang hoặc $ 200 cho 100 lần tải trang.

Tương tự nếu các cuộc gọi lại khác nhau:

add_action( 'init','send_money_to_grandma_1_dollar' );
add_action( 'init','send_money_to_grandma_also_1_dollar' );

Câu hỏi 2

Nếu chúng tôi muốn đảm bảo chúng tôi chỉ gửi cho bà ngoại $ 1

Nếu chúng tôi chỉ muốn gửi nó một lần cho mỗi lần tải trang , thì điều này sẽ làm điều đó:

add_action( 'init','send_money_to_grandma' );

bởi vì initmóc chỉ được bắn một lần. Chúng tôi có thể có các móc khác kích hoạt nhiều lần trên mỗi lần tải trang.

Hãy gọi:

add_action( 'someaction ','send_money_to_grandma' );

Nhưng điều gì xảy ra nếu someactionbắn 10 lần cho mỗi lần tải trang?

Chúng ta có thể điều chỉnh send_money_to_grandma()chức năng với

function send_money_to_grandma() 
{
    if( ! did_action( 'someaction' ) )
        internetofThings("send grandma","$1");
}

hoặc sử dụng biến tĩnh làm bộ đếm:

function send_money_to_grandma() 
{
    static $counter = 0;
    if( 0 === $counter++ )
        internetofThings("send grandma","$1");
}

Nếu chúng tôi chỉ muốn chạy nó một lần (bao giờ!), Thì chúng tôi có thể đăng ký một tùy chọn trong wp_optionsbảng thông qua API Tùy chọn :

function send_money_to_grandma() 
{
    if( 'no' === get_option( 'sent_grandma_money', 'no' ) )
    {
        update_option( 'sent_grandma_money', 'yes' );
        internetofThings( "send grandma","$1" );
    }
}

Nếu chúng tôi muốn gửi tiền cho cô ấy mỗi ngày một lần, thì chúng tôi có thể sử dụng API tạm thời

function send_money_to_grandma() 
{
    if ( false === get_transient( 'sent_grandma_money' ) ) )
    {
        internetofThings( "send grandma","$1" );
        set_transient( 'sent_grandma_money', 'yes', DAY_IN_SECONDS );
    }
}

hoặc thậm chí sử dụng wp-cron.

Lưu ý rằng bạn có thể có các cuộc gọi ajax. cũng.

Có nhiều cách để kiểm tra, ví dụ như với DOING_AJAX

Cũng có thể có các chuyển hướng, có thể làm gián đoạn dòng chảy.

Sau đó, chúng tôi có thể muốn giới hạn chỉ phụ trợ, is_admin()hoặc không : ! is_admin().

Câu hỏi số 3

Đây có phải là điều mà các nhà phát triển plugin lo lắng?

vâng điều này rất quan trọng

Nếu chúng tôi muốn làm cho bà của chúng tôi rất hạnh phúc, chúng tôi sẽ làm:

add_action( 'all','send_money_to_grandma' );

nhưng điều này sẽ rất tệ cho hiệu suất ... và ví của chúng tôi ;-)


wow - cảm ơn bạn đã phản hồi kỹ lưỡng như vậy; Điều này giúp rất nhiều!
CC

1
Bạn được chào đón - Tôi thực sự rất thích cách bạn đặt câu hỏi cho bạn ;-) @CC
birgire

2
Vào cuối ngày, chúng tôi muốn giữ cho ví và bà của mình hạnh phúc, vì vậy tất cả chỉ là tìm kiếm sự hài hòa / cân bằng hoàn hảo ;-)
Pieter Goosen

Câu trả lời rất hay +1, nhưng đáng nói là cách thêm một lần hành động cũng phụ thuộc vào id gọi lại và khi xử lý các đối tượng thì mọi thứ phức tạp hơn một chút ... Thật khó để giải thích rõ hơn về khái niệm ở đây, tôi ' sẽ viết một câu trả lời ...
gmazzap

cảm ơn @gmazzap - vâng, điều đó sẽ rất tuyệt, vì tôi đã không bao gồm khóa thứ ba $ idx và _wp_filter_build_unique_id (), chỉ hiển thị nó ;-)
birgire

8

Đây là một nhận xét cho câu trả lời rất hay của Birgire hơn là một câu trả lời hoàn chỉnh, nhưng phải viết mã, các bình luận không phù hợp.

Từ câu trả lời, có vẻ như lý do duy nhất tại sao hành động được thêm một lần vào mã mẫu OP, ngay cả khi add_action()được gọi hai lần, là thực tế là cùng một ưu tiên được sử dụng. Đo không phải sự thật.

Trong mã của add_filtermột phần quan trọng là _wp_filter_build_unique_id()chức năng gọi, tạo ra một id duy nhất cho mỗi cuộc gọi lại .

Nếu bạn sử dụng một biến đơn giản, như một chuỗi chứa tên hàm, ví dụ: "send_money_to_grandma"id sẽ bằng chính chuỗi đó, vì vậy nếu mức độ ưu tiên là như nhau, cũng giống như id, gọi lại được thêm một lần.

Tuy nhiên, mọi thứ không phải lúc nào cũng đơn giản như thế. Gọi lại có thể là bất cứ điều gì callabletrong PHP:

  • tên hàm
  • phương thức lớp tĩnh
  • phương thức lớp động
  • vật bất khả xâm phạm
  • đóng cửa (chức năng ẩn danh)

Hai chuỗi đầu tiên được biểu diễn tương ứng bằng một chuỗi và một mảng gồm 2 chuỗi ( 'send_money_to_grandma'array('MoneySender', 'send_to_grandma')) để id luôn giống nhau và bạn có thể chắc chắn rằng gọi lại được thêm một lần nếu mức độ ưu tiên là như nhau.

Trong tất cả 3 trường hợp khác, id phụ thuộc vào các thể hiện đối tượng (một hàm ẩn danh là một đối tượng trong PHP) vì vậy gọi lại chỉ được thêm một lần nếu đối tượng là cùng một thể hiện và điều quan trọng là phải lưu ý cùng một thể hiệncùng một lớp là hai điều khác nhau.

Lấy ví dụ này:

class MoneySender {

   public function sent_to_grandma( $amount = 1 ) {
     // things happen here
   }

}

$sender1 = new MoneySender();
$sender2 = new MoneySender();

add_action( 'init', array( $sender1, 'sent_to_grandma' ) );
add_action( 'init', array( $sender1, 'sent_to_grandma' ) );
add_action( 'init', array( $sender2, 'sent_to_grandma' ) );

Chúng tôi gửi bao nhiêu đô la cho mỗi lần tải trang?

Câu trả lời là 2, vì id WordPress tạo $sender1$sender2khác nhau.

Điều tương tự cũng xảy ra trong trường hợp này:

add_action( 'init', function() {
   sent_to_grandma();
} );

add_action( 'init', function() {
   sent_to_grandma();
} );

Ở trên tôi đã sử dụng hàm sent_to_grandmabên trong các bao đóng và ngay cả khi mã giống hệt nhau, 2 bao đóng là 2 \Closuređối tượng khác nhau , do đó WP sẽ tạo 2 id khác nhau, điều này sẽ khiến hành động được thêm hai lần, ngay cả khi mức độ ưu tiên là như nhau.


4

Bạn không thể thêm cùng một hành động vào cùng một hook hành động , với cùng mức độ ưu tiên .

Điều này được thực hiện để ngăn chặn nhiều plugin dựa trên hành động của plugin thứ ba xảy ra nhiều lần (nghĩ rằng thương mại điện tử và tất cả các plugin của bên thứ ba, như tích hợp thanh toán cổng, v.v.). Vì vậy, không chỉ định ưu tiên, bà vẫn nghèo:

add_action('init','print_a_buck');
add_action('init','print_a_buck');

function print_a_buck() {
    echo '$1</br>';
}
add_action('wp', 'die_hard');
function die_hard() {
    die('hard');
}

Tuy nhiên, nếu bạn thêm ưu tiên cho các hành động đó:

add_action('init','print_a_buck', 1);
add_action('init','print_a_buck', 2);
add_action('init','print_a_buck', 3);

Bà hiện chết với 4 đô la trong túi (1, 2, 3 và mặc định: 10).

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.