이 코드는 몇 번이나 실행됩니까? (또는 할머니는 얼마나 부유합니까?)


20

가상의 예이지만 실제 적용 가능 (나 같은 사람이 배우는 경우)

이 코드가 주어지면 :

<?php

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

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

이제 WP 사이트를 불러와 로그인합니다. 관리자에서 몇 페이지를 탐색합니다. 'init'동작은 랩탑 배터리가 완전히 방전되기 전에 총 100 번 발생합니다 .

첫 번째 질문 : 할머니에게 얼마나 많은 돈을 보냈습니까? $ 1, $ 2, $ 100 또는 $ 200 (또는 다른 것)입니까?

당신은 또한 당신의 대답을 설명 할 수 있다면 그것은 대단 할 것입니다.

두 번째 질문 : 할머니에게 $ 1 만 보내려면 최선의 방법은 무엇입니까? 처음 $ 1을 보낼 때 'true'로 설정되는 전역 변수 (세마포어)? 아니면 어떤 동작이 이미 발생했는지 확인하고 여러 번 실행되지 않도록하는 다른 테스트가 있습니까?

세 번째 질문 : 플러그인 개발자가 걱정하는 것입니까? 내 예제가 어리 석다는 것을 알고 있지만 성능 문제와 기타 예기치 않은 부작용 (예 : 함수가 데이터베이스에 업데이트 / 삽입되는 경우)을 생각하고있었습니다.


2
인정하십시오, 이것은 오랫동안 최고의 질문 중 하나입니다 ;-)
Pieter Goosen

답변:


21

이것에 대한 임의의 생각은 다음과 같습니다.

질문 1

우리는 할머니에게 얼마나 많은 돈을 보냈습니까?

100 페이지로드의 경우 100 x $ 1 = $ 100를 보냈습니다.

여기서 우리는 실제로 100 x do_action( 'init' )전화를 의미 합니다.

다음과 같이 두 번 추가 한 것은 중요하지 않습니다.

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

때문에 콜백우선 순위 (10 기본값) 동일합니다 .

우리는 어떻게 전역 배열 을 구성 add_action하는 래퍼 인지 확인할 수 있습니다 .add_filter$wp_filter

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;
}

그러나 우선 순위를 변경 한 경우 :

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

그런 다음 페이지로드 당 2 x 1 달러 또는 100 페이지로드시 200 달러를 보냅니다.

콜백이 다른 경우 동일합니다.

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

질문 # 2

할머니 만 보내려면 1 달러

페이지로드 당 한 번만 보내려면 다음과 같이하십시오.

add_action( 'init','send_money_to_grandma' );

init후크는 한 번만 발사 되기 때문 입니다. 페이지로드 당 여러 번 발생하는 다른 후크가있을 수 있습니다.

전화합시다 :

add_action( 'someaction ','send_money_to_grandma' );

그러나 someaction페이지로드 당 10 번 발생하면 어떻게됩니까 ?

우리는 send_money_to_grandma()기능을 조정할 수 있습니다

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

또는 정적 변수를 카운터로 사용하십시오.

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

한 번만 실행 wp_options하려면 옵션 API 를 통해 테이블에 옵션을 등록 할 수 있습니다 .

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

매일 한 번씩 돈을 보내려면 Transient API를 사용할 수 있습니다

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

또는 wp-cron을 사용하십시오.

아약스 호출이있을 수 있습니다. 게다가.

예를 들어 DOING_AJAX

흐름을 방해 할 수있는 리디렉션이있을 수도 있습니다.

그런 다음 백엔드로만 제한 is_admin()하거나 제한 하지 않을 수 ! is_admin()있습니다.

질문 # 3

이것이 플러그인 개발자들이 걱정하는 것입니까?

예, 이것이 중요합니다.

할머니를 매우 행복하게하려면 다음과 같이하십시오.

add_action( 'all','send_money_to_grandma' );

그러나 이것은 성능이 매우 나쁠 것입니다 ... 그리고 지갑 ;-)


와우-철저한 답변에 감사드립니다. 이것은 엄청나게 도움이됩니다!
CC

1
천만에요-난 정말 당신이 당신의 질문을 표현하는 방법을 즐겼습니다 ;-) @CC
birgire

2
마지막 날, 우리는 지갑과 할머니를 행복하게 유지하고 싶기 때문에 완벽한 조화 / 균형을 찾는 것이 전부입니다. ;-)
Pieter Goosen

매우 좋은 대답 +1이지만 액션이 추가되는 시간도 콜백 ID에 따라 다르며 객체를 처리 할 때 상황이 조금 더 복잡합니다 ... 여기서 개념을 더 잘 설명하기가 어렵습니다. 답변을 드리겠습니다 ...
gmazzap

감사 @gmazzap - 나는 세 번째 키 $의 IDX 및 _wp_filter_build_unique_id ()을 포함하지 않았기 때문에, 좋은 것 예는, 그냥 ;-) 표시
birgire

8

이것은 완전한 답변보다 아주 좋은 Birgire의 답변에 대한 의견이지만 코드를 작성해야하지만 의견이 맞지 않습니다.

대답에서 OP 샘플 코드에서 조치가 한 번 추가되는 유일한 이유 add_action()는 두 번 호출 되더라도 동일한 우선 순위가 사용된다는 것입니다. 그건 사실이 아니야.

add_filter중요한 부분 의 코드에는 콜백_wp_filter_build_unique_id() 당 고유 ID를 만드는 함수 호출 이 있습니다 .

함수 이름 (예 :)을 보유한 문자열과 같은 간단한 변수를 사용하는 경우 "send_money_to_grandma"id는 문자열 자체와 동일하므로 우선 순위가 동일하고 id도 동일하면 콜백이 한 번 추가됩니다.

그러나 그런 것이 항상 간단한 것은 아닙니다. 콜백은 callablePHP에 있는 것일 수 있습니다 .

  • 기능 이름
  • 정적 클래스 메소드
  • 동적 클래스 메소드
  • 호출 할 수없는 객체
  • 클로저 (익명 함수)

처음 두 개는 각각 문자열과 2 개의 문자열 ( 'send_money_to_grandma'array('MoneySender', 'send_to_grandma')) 배열로 표시 되므로 id는 항상 동일하므로 우선 순위가 동일한 경우 콜백이 한 번 추가 될 수 있습니다.

다른 세 가지 경우 모두 id는 객체 인스턴스에 의존하므로 (익명 함수는 PHP의 객체입니다) 객체가 동일한 인스턴스 인 경우에만 콜백이 한 번 추가되며 동일한 인스턴스동일한 클래스 를 주목하는 것이 중요합니다 서로 다른 두 가지입니다.

이 예제를 보자 :

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

페이지로드 당 몇 달러를 보내나요?

대답은 2 입니다. WordPress에서 생성하는 ID $sender1$sender2다르기 때문입니다.

이 경우에도 마찬가지입니다.

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

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

위의 함수는 sent_to_grandma클로저 내부 에서 함수를 사용했으며 코드가 동일하더라도 2 클로저는 2 개의 다른 \Closure객체 인스턴스 이므로 WP는 2 개의 서로 다른 ID를 생성하므로 우선 순위가 동일한 경우에도 액션이 두 번 추가됩니다.


4

우선 순위동일한 동일한 작업 후크에 동일한 작업 을 추가 할 수 없습니다 .

이는 타사 플러그인의 행동에 의존하는 여러 플러그인이 두 번 이상 발생하는 것을 방지하기 위해 수행됩니다 (woocommerce 및 게이트웨이 지불 통합과 같은 모든 타사 플러그인이라고 생각하십시오). 따라서 우선 순위를 지정하지 않으면 할머니는 여전히 가난합니다.

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

그러나 해당 조치에 우선 순위를 추가하는 경우 :

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

할머니는 이제 주머니에 $ 4로 죽습니다 (1, 2, 3 및 기본값 : 10).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.