यह कोड कितनी बार चलेगा? (या, दादी कितनी अमीर हैं?)


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 साइट लाऊंगा और लॉग इन करूंगा। मैंने एडमिन के कुछ पेजों को ट्रैस किया। मेरे लैपटॉप की बैटरी मरने से पहले 'इनिट' एक्शन कुल 100 बार फायर करता है।

पहला सवाल: हमने दादी को कितने पैसे भेजे? क्या यह $ 1, $ 2, $ 100 या $ 200 (या कुछ और) है?

यदि आप अपना उत्तर भी बता सकते हैं जो कि भयानक होगा।

दूसरा प्रश्न: अगर हम यह सुनिश्चित करना चाहते हैं कि हम केवल दादी $ 1 भेजें, तो ऐसा करने का सबसे अच्छा तरीका क्या है? वैश्विक चर (सेमाफोर) जो पहली बार $ 1 भेजने पर 'सही' हो जाता है? या यह देखने के लिए कि क्या कोई कार्रवाई पहले से ही हुई है और इसे कई बार फायरिंग से रोकना है?

तीसरा प्रश्न: क्या यह कुछ है जो प्लगइन डेवलपर्स के बारे में चिंता करता है? मुझे लगता है कि मेरा उदाहरण मूर्खतापूर्ण है, लेकिन मैं प्रदर्शन के मुद्दों और अन्य अप्रत्याशित दुष्प्रभावों के बारे में सोच रहा था (जैसे अगर फ़ंक्शन डेटाबेस में अपडेट / आवेषण करता है)।


2
स्वीकार करना चाहिए, यह एक लंबे समय में सबसे अच्छा सवाल है ;-)
पीटर गोएंस

जवाबों:


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 पेज $ 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 माध्यम से तालिका में एक विकल्प दर्ज कर सकते हैं :

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
दिन के अंत में, हम अपने बटुए और दादी को खुश रखना चाहते हैं, इसलिए यह बिल्कुल सही सद्भाव / संतुलन खोजने के बारे में है ;-)
पीटर गोएंस

बहुत अच्छा उत्तर +1, लेकिन यह कहने योग्य है कि किसी क्रिया को कितनी बार जोड़ा जाता है, यह कॉलबैक आईडी पर भी निर्भर करता है, और जब वस्तुओं के साथ काम करना थोड़ा अधिक जटिल होता है ... यहां अवधारणा को बेहतर ढंग से समझाने के लिए मुश्किल है, ' करूँगा एक जवाब लिखने ...
gmazzap

धन्यवाद @gmazzap - हाँ यह बहुत अच्छा होगा, क्योंकि मैंने तीसरी कुंजी $ idx को कवर नहीं किया था और _wp_filter_build_unique_id (), बस इसे प्रदर्शित किया ;-)
birgire

8

यह पूर्ण उत्तर की तुलना में बहुत अच्छे बीरगिर के उत्तर के लिए एक टिप्पणी है , लेकिन कोड लिखने के लिए, टिप्पणियां फिट नहीं हैं।

उत्तर से यह लग सकता है कि ओपी नमूना कोड में एक बार कार्रवाई को जोड़ने का एकमात्र कारण, भले ही add_action()दो बार कहा जाता है, यह तथ्य है कि एक ही प्राथमिकता का उपयोग किया जाता है। यह सच नहीं है।

add_filterएक महत्वपूर्ण भाग के कोड में _wp_filter_build_unique_id()फ़ंक्शन कॉल है, जो कॉलबैक प्रति एक अद्वितीय आईडी बनाता है ।

यदि आप एक साधारण चर का उपयोग करते हैं, जैसे एक स्ट्रिंग जो फ़ंक्शन नाम रखती है, जैसे "send_money_to_grandma", तो आईडी स्ट्रिंग के बराबर होगी, इसलिए यदि प्राथमिकता समान है, तो आईडी भी समान होने के नाते, कॉलबैक एक बार जोड़ा जाता है।

हालांकि, चीजें हमेशा सरल नहीं होती हैं। कॉलबैक कुछ भी हो सकता है callableजो PHP में है:

  • समारोह के नाम
  • स्थिर वर्ग विधियाँ
  • गतिशील वर्ग के तरीके
  • अमूल्य वस्तुएँ
  • क्लोजर (अनाम फ़ंक्शंस)

पहले दो को क्रमशः एक स्ट्रिंग और 2 स्ट्रिंग्स ( 'send_money_to_grandma'और array('MoneySender', 'send_to_grandma')) के एक सरणी द्वारा दर्शाया गया है, इसलिए आईडी हमेशा समान होती है, और आप सुनिश्चित कर सकते हैं कि प्राथमिकता एक ही होने पर कॉलबैक को एक बार जोड़ दिया जाए।

अन्य सभी 3 मामलों में, आईडी ऑब्जेक्ट इंस्टेंस पर निर्भर करता है (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 है, क्योंकि आईडी वर्डप्रेस जेनरेट करता है $sender1और $sender2अलग हैं।

इस मामले में भी ऐसा ही होता है:

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

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

ऊपर मैंने sent_to_grandmaक्लोजर के अंदर फ़ंक्शन का उपयोग किया , और भले ही कोड समान हो, 2 क्लोजर \Closureऑब्जेक्ट के 2 अलग-अलग उदाहरण हैं , इसलिए WP 2 अलग आईडी बना देगा, जिससे कार्रवाई दो बार जुड़ जाएगी, भले ही प्राथमिकता समान हो।


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) के साथ मर जाती है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.