add_action एक वर्ग का संदर्भ देता है


38

क्या 'add_action' में एक फ़ंक्शन के बजाय एक वर्ग को संदर्भित करना संभव है? यह पता लगाने के लिए प्रतीत नहीं कर सकते। यहाँ प्रश्न में फ़ंक्शन का केवल एक मूल उदाहरण है।

add_action( 'admin_init', 'MyClass' );
class MyClass {
     function __construct() {
          .. This is where stuff gets done ..
     }
}

तो हाँ, यह काम नहीं करता है। मैंने भी कोशिश की है:

$var = new MyClass();
add_action( 'admin_init', array( &$var ) );

तथा:

$var = new MyClass();
add_action( 'admin_init', array( &$var, '__construct' ) );

और भी:

add_action( 'admin_init', 'MyClass::__construct' );

क्या वैसे भी मैं एक अलग फ़ंक्शन बनाने के लिए ऐसा कर सकता हूं जो कक्षा को लोड करता है? मैं add_action के माध्यम से सिर्फ क्लास कंस्ट्रक्टर को चलाने में सक्षम होना चाहता हूं। गेंद लुढ़कने के लिए बस इतना ही चाहिए।

जवाबों:


69

नहीं, आप सीधे नहीं, बल्कि हुक के माध्यम से क्लास को 'इनिशियलाइज़' कर सकते हैं या उसे तत्काल शुरू नहीं कर सकते। कुछ अतिरिक्त कोड की हमेशा आवश्यकता होती है (और यह ऐसा करने में सक्षम होने के लिए एक वांछनीय बात नहीं है, क्योंकि आप अपने लिए कीड़े का एक कैन खोल रहे हैं।

यहाँ यह करने का एक बेहतर तरीका है:

class MyClass {
     function __construct() {
          add_action( 'admin_init',array( $this, 'getStuffDone' ) );
     }
     function getStuffDone() {
          // .. This is where stuff gets done ..
     }
}
$var = new MyClass();

निश्चित रूप से एक सामान्य वर्ग के लिए इसे और भी सरल बनाने के लिए एक इंटरफ़ेस वर्ग बना सकता है:

class IGetStuffDone {
    function IGetStuffDone(){
        add_action( 'admin_init',array( $this, 'getStuffDone' ) );
    }
    public abstract function getStuffDone();
}

ध्यान दें कि एक इंटरफ़ेस के रूप में, आप सीधे इस प्रकार का ऑब्जेक्ट नहीं बना सकते हैं, लेकिन आप एक सब-क्लास बना सकते हैं, जिससे आप कह सकते हैं:

class CDoingThings extends IGetStuffDone {
    function getStuffDone(){
        // doing things
    }
}
$var = new CDoingThings();

जो तब स्वचालित रूप से सभी हुक जोड़ देगा, आपको बस यह परिभाषित करने की आवश्यकता है कि वास्तव में उपवर्ग में क्या किया जा रहा है और फिर इसे बनाएं!

कंस्ट्रक्टर्स पर

मैं एक हुक फ़ंक्शन के रूप में एक निर्माता नहीं जोड़ूंगा, यह खराब अभ्यास है, और ओटी को बहुत सारे असामान्य घटनाओं का नेतृत्व कर सकता है। अधिकांश भाषाओं में भी एक कंस्ट्रक्टर उस वस्तु को लौटाता है जिसे इंस्टेंट किया जा रहा है, इसलिए यदि आपके हुक को किसी फ़िल्टर की तरह कुछ वापस करना है, तो वह फ़िल्टर किए गए वैरिएबल को वैसा नहीं लौटाएगा जैसा आप चाहते हैं, लेकिन इसके बजाय वह क्लास ऑब्जेक्ट लौटाएगा।

एक निर्माता या विध्वंसक को बुलाना बहुत, बहुत, बहुत बुरा प्रोग्रामिंग अभ्यास है, कोई फर्क नहीं पड़ता कि आप किस भाषा में हैं और कभी भी नहीं किया जाना चाहिए ।

कन्स्ट्रक्टर्स को वस्तुओं का निर्माण करना चाहिए, उन्हें उपयोग के लिए तैयार करना, वास्तविक काम के लिए नहीं। ऑब्जेक्ट द्वारा किया जाने वाला कार्य एक अलग फ़ंक्शन में होना चाहिए।

स्टैटिक क्लास के तरीके, और तुरंत / शुरू में इसकी जरूरत नहीं

यदि आपकी कक्षा विधि एक स्थिर वर्ग विधि है, तो आप $thisनीचे दिखाए गए के बजाय उद्धरणों में कक्षा का नाम पास कर सकते हैं:

class MyClass {
     public static function getStuffDone() {
          // .. This is where stuff gets done ..
     }
}
add_action( 'admin_init', array('MyClass','getStuffDone' ) );

क्लोजर और पीएचपी 5.3

अफसोस की बात है कि आप नई क्लास बनाने वाली लाइन से बच नहीं सकते। इसे लंघन करने के लिए केवल अन्य समाधान में बॉयलर प्लेट कोड शामिल होगा जिसमें अभी भी वह रेखा है, और इसके लिए PHP 5.3+ की आवश्यकता होगी:

add_action('admin_init',function(){
    $var = new MyClass();
    $var->getStuffDone();
});

किस बिंदु पर आप कक्षा को छोड़ सकते हैं, और बस एक फ़ंक्शन का उपयोग कर सकते हैं:

add_action('admin_init',function(){
    // do stuff
});

लेकिन ध्यान रखें कि आपने अब गुमनाम फ़ंक्शंस के दर्शक को पेश किया है। उपरोक्त कार्रवाई का उपयोग करने का कोई तरीका नहीं है remove_action, और यह उन डेवलपर्स के लिए बहुत दर्द पैदा कर सकता है जिन्हें अन्य लोगों के कोड के साथ काम करना पड़ता है।

Ampersands पर

आप इस तरह की क्रियाओं को देख सकते हैं:

array( &$this, 'getStuffDone' );

यह बुरा है&PHP 4 में वापस जोड़ा गया था जब वस्तुओं को मूल्यों के रूप में पारित किया गया था, न कि संदर्भ के रूप में। PHP 4 एक दशक से अधिक पुराना है, और बहुत लंबे समय में वर्डप्रेस द्वारा समर्थित नहीं किया गया है।

नहीं है कोई कारण नहीं है का उपयोग करने के &thisलिए जब हुक और फिल्टर जोड़ने, और संदर्भ में कोई समस्या का कारण होगा दूर करने, और यहां तक कि पीएचपी के भविष्य के संस्करणों के साथ संगतता में सुधार हो सकता

इसके बजाय इसका उपयोग करें:

array( $this, 'getStuffDone' );

ठीक है। उस सब से धन्यवाद; वास्तव में काफी कुछ सीखा है। मैं वास्तव में केवल वर्ग आधारित PHP में अब सहज हो रहा हूं। यह वही है जो मैंने किया है, और यह काम करता है, लेकिन क्या आप मुझे बता सकते हैं कि यह किसी भी तरह से बुरा व्यवहार / गलत है? मैंने कक्षा को एक स्थिर फ़ंक्शन के अंदर, कक्षा के भीतर ही शुरू किया है। फिर add_action में स्थिर फ़ंक्शन का संदर्भ दिया। इस लिंक को देखें: pastebin.com/0idyPwwY
मैथ्यू रूडी 5'12

हाँ, आप इसे इस तरह से कर सकते हैं, हालांकि मैं $classआपके चर नाम के रूप में उपयोग करने से बच सकता हूं , वे शब्द आरक्षित हैं। मुझे लगता है कि आप $x = new Y();वैश्विक दायरे में कुछ समान कहने से बचने के लिए अपने रास्ते से बाहर जा रहे हैं , और आप जटिलता जोड़ रहे हैं जहां कोई भी आवश्यक नहीं है। लिखे गए कोड की मात्रा को कम करने के आपके प्रयास में अधिक कोड लिखना शामिल है!
टॉम जम्मू नॉवेल

मैं उपरोक्त सभी मामलों में इंगित करता हूं, आप एक वर्ग के बजाय एक फ़ंक्शन का उपयोग करना बेहतर होगा, क्योंकि उस वर्ग को वैसे भी त्याग दिया जाएगा और उसी उद्देश्य को पूरा करेगा। यह संसाधनों की बर्बादी है। याद रखें, किसी वस्तु को बनाने और नष्ट करने की लागत है, आप कुछ वस्तुओं को चाहते हैं, और आप चाहते हैं कि वे लंबे समय तक जीवित
रहें

अच्छी बात। जिस तरह से मैं इसे देख रहा हूँ बदल दिया है। मुझे लगता है कि मैं अतिरिक्त कोड से बचने के बजाय इसे वैश्विक दायरे में बुलाऊंगा।
मैथ्यू रुडी

1
मैं यह जोड़ना चाहूंगा कि यदि आप अपनी कक्षा को किसी नाम स्थान पर रखते हैं, तो आपको वह भी जोड़ना होगा या add_action () / add_filter () नहीं मिलेगा - जैसे:add_action( 'admin_init', array('MyNamespace\MyClass','getStuffDone' ) );
jschrab

10

उदाहरण वर्ग

टिप्पणियाँ:

  • केवल एक बार कक्षा में प्रवेश करें
    • प्राथमिकता 0 पर कॉल करें, ताकि आप बाद में डिफ़ॉल्ट प्राथमिकता के साथ उसी हुक का उपयोग कर सकें
    • ! class_existsइसे दो बार कॉल करने से बचने के लिए लपेटें और इनिट कॉलर को अंदर रखें
  • initफ़ंक्शन और वर्ग संस्करण बनाएंstatic
  • जब आप क्लास को बुलाते हैं, तो अपने इनिट के अंदर से कंस्ट्रक्टर को कॉल करें new self

यहाँ एक उदाहरण है

if ( ! class_exists( 'WPSESampleClass' ) )
{
    // Init the class on priority 0 to avoid adding priority inside the class as default = 10
    add_action( 'init', array ( 'WPSESampleClass', 'init' ), 0 );

class WPSESampleClass
{
    /**
     * The Class Object
     */
    static private $class = null;

    public static function init()
    {
        if ( null === self::$class ) 
            self :: $class = new self;

        return self :: $class;
    }

    public function __construct()
    {
        // do stuff like add action calls:
        add_action( 'init', array( $this, 'cb_fn_name' ) );
    }

    public function cb_fn_name()
    {
        // do stuff 
    }
} // END Class WPSESampleClass

} // endif;

Php 5+

कृपया , &बाहर निकलें। हम पहले से ही php4 से आगे हैं। :)


2
if (!class_exists("AllInOneWoo")){
    class AllInOneWoo {
        function __construct(){
            add_action('admin_menu', array($this, 'all_in_one_woo') );
        }
        function all_in_one_woo(){
            $page_title = 'All In One Woo';
            $menu_title = 'All In One Woo';
            $capability = 'manage_options';
            $menu_slug  = 'all-in-one-woo-menu';
            $function   = array($this, 'all_in_one_woo_menu');
            $icon_url   = 'dashicons-media-code';
            $position   = 59;

            add_menu_page($page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, $position);
        }
        function all_in_one_woo_menu(){?>
            <div class="wrap">
                <h1><?php _e('All In One Woo', 'all_in_one_woo'); ?></h1>
            </div>
        <?php }
    }// end class
}// end if

if (class_exists("AllInOneWoo")){       
    $all_in_one_woo = new AllInOneWoo();
}

कृपया संपादित आपका जवाब है, और एक विवरण जोड़ें: क्यों कि समस्या का समाधान कर सकता है?
FUXIA

0

आप इसे शुरू में लोड करने की आवश्यकता के बिना अपनी कक्षा में घटनाओं को ट्रिगर कर सकते हैं । यह आसान है यदि आप पूरी कक्षा को सामने से लोड नहीं करना चाहते हैं, लेकिन वर्डप्रेस फ़िल्टर और कार्यों तक पहुंचने की आवश्यकता है।

यहाँ एक बहुत ही सरल उदाहरण है

<?php
class MyClass
{
    public static function init()
    {
        add_filter( 'the_content', array('MyClass', 'myMethod') );
    }

    public static function myMethod($content)
    {
        $content = $content . 'Working without loading the object';
    }
}

MyClass::init();

यह कैसर के उत्तर का एक बहुत ही सरल संस्करण है लेकिन सरल शब्दों में व्यवहार को दर्शाता है। पहली बार इस शैली को देखने वालों के लिए उपयोगी हो सकता है।

यदि आवश्यक हो तो अन्य विधियाँ अभी भी वस्तु को आरंभ कर सकती हैं। मैं इस विधि का उपयोग व्यक्तिगत रूप से स्क्रिप्ट्स को अलग करने के लिए अपने प्लगइन के वैकल्पिक भागों की अनुमति देने के लिए कर रहा हूं, लेकिन केवल AJAX अनुरोध पर ऑब्जेक्ट को ट्रिगर करना।


0

यह मेरे लिए काम करता है:

class foo
{
    public static function bar()
    {
        echo 'it works!';
    }
}

add_action('foo_bar', array('foo', 'bar'));

0

आम तौर पर बोलते हुए, आप एक हुक करने के लिए पूरी कक्षा नहीं जोड़ेंगे । add_action()/ add_filter()हुक कॉलबैक उम्मीद कार्यों , जो कर सकते हैं से संदर्भित किया एक वर्ग के भीतर

मान लीजिए कि init()आपकी कक्षा के अंदर एक फ़ंक्शन है, जिसे आप वर्डप्रेस initहुक में हुक करना चाहते हैं ।

अपनी add_action()कॉल को अपनी कक्षा के अंदर रखें , और फिर कॉलबैक की पहचान करें जैसे:

add_action( 'init', array( $this, 'init' ) );

(नोट: मैं मान रहा हूं कि आपकी कक्षा ठीक से नामांकित है; अन्यथा, आपके कॉलबैक कार्यों को नामांकित करना सुनिश्चित करें।)


यदि वर्तमान वर्ग पहले से ही आरंभ नहीं किया गया है तो क्या होगा? मैं वास्तव में आरंभ करने के लिए add_action का उपयोग करने की कोशिश कर रहा था, इसलिए मुझे $ var = new MyClass () नहीं जोड़ना है; पहले से कहीं और।
मैथ्यू रूडी

क्या आप अपनी कक्षा को init(या जहाँ भी आपको इसकी आवश्यकता हो) को तुरंत रद्द करने के लिए कॉलबैक नहीं लिख सकते हैं ?
चिप बेनेट

0

आपको तात्कालिक वस्तु के बजाय कक्षा के नाम को पास करने में सक्षम होना चाहिए:

add_action( 'init', array( 'MyClass', '__construct' ) );

(सिद्धांत में, आपके अन्य समाधान को भी काम करना चाहिए

$var = new MyClass();
add_action( 'admin_init', array( $var, '__construct' ) );

यह सुनिश्चित नहीं है कि सिर क्यों नहीं है। शायद अगर आप संदर्भ से नहीं बुलाते हैं?)


पहला काम नहीं करता है। बस पेज खाली हो जाता है। दूसरा काम करता है, लेकिन केवल इसलिए कि पहली पंक्ति में कक्षा शुरू की गई है। यह कार्रवाई को जोड़ने के उद्देश्य को पराजित करता है, क्योंकि वर्ग पहले ही शुरू किया जा चुका है। लेकिन यह वह नहीं करता है जो मैं करने की कोशिश कर रहा हूं, जो कार्रवाई के माध्यम से कक्षा शुरू करता है। मैं जिस वास्तविक कोड पर काम कर रहा हूं, वह क्रिया 'admin_init' नहीं है, बल्कि किसी अन्य वर्ग के भीतर एक कस्टम क्रिया है। यदि दूसरी कक्षा में कार्रवाई नहीं होती है तो मैं 'MyClass' फंक्शन शुरू नहीं करना चाहता। क्षमा करें अगर मुझे कुछ याद आ रहा है; जैसा कि मैंने जाना
मैथ्यू रुडी

हाँ, मैं गलत था। यह केवल तभी काम करता है जब आप एक स्टैटिक initविधि कह रहे हों । देखें wordpress.stackexchange.com/a/48093/14052
बूने दर्रों
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.