2011-01-03 7 views
8

में प्रतिनिधियों या कॉलबैक करने का सही तरीका मैं php में निम्नलिखित पैटर्न लागू करने की आवश्यकता:पीएचपी

class EventSubscriber 
{ 
    private $userCode; 
    public function __construct(&$userCode) { $this->userCode = &$userCode; } 
    public function Subscribe($eventHandler) { $userCode[] = $eventHandler; } 
} 

class Event 
{ 
    private $subscriber; 
    private $userCode = array(); 

    public function __construct() 
    { 
     $this->subscriber = new Subscriber($this->userCode) 
    } 

    public function Subscriber() { return $this->subscriber; } 

    public function Fire() 
    { 
     foreach ($this->userCode as $eventHandler) 
     { 
      /* Here i need to execute $eventHandler */ 
     } 
    } 
} 

class Button 
{ 
    private $eventClick; 

    public function __construct() { $this->eventClick = new Event(); } 

    public function EventClick() { return $this->eventClick->Subscriber(); } 

    public function Render() 
    { 
     if (/* Button was clicked */) $this->eventClick->Fire(); 

     return '<input type="button" />'; 
    } 
} 

class Page 
{ 
    private $button; 

    // THIS IS PRIVATE CLASS MEMBER !!! 
    private function ButtonClickedHandler($sender, $eventArgs) 
    { 
     echo "button was clicked"; 
    } 

    public function __construct() 
    { 
     $this->button = new Button(); 
     $this->button->EventClick()->Subscribe(array($this, 'ButtonClickedHandler')); 
    } 

    ... 

}  

क्या ऐसा करने के लिए सही तरीका है।

पीएस

मैं उस उद्देश्य के लिए call_user_func का उपयोग कर रहा था और मानता हूं कि यह निजी वर्ग के सदस्यों को कॉल करने में सक्षम था, लेकिन विकास के कुछ सप्ताह बाद मुझे पता चला कि यह काम करना बंद कर दिया है। क्या यह मेरे कोड में एक बग था या यह कुछ और था जो मुझे लगता है कि 'call_user_func' कॉल निजी वर्ग के कार्यों को कॉल करने में सक्षम है, मुझे नहीं पता, लेकिन अब मैं सुरक्षित रूप से एक सरल, तेज़ और सुरुचिपूर्ण विधि की तलाश में हूं किसी के निजी वर्ग के सदस्य को दूसरे वर्ग से बुलाओ। मैं अभी बंद करने के लिए देख रहा हूं, लेकिन बंद होने के अंदर '$ this' के साथ समस्याएं हैं ...

+1

'$ this' क्लोजर (मैनुअल में उल्लेख किया) और निजी सदस्यों में समर्थित नहीं है, निजी हैं क्योंकि वे एक है, जो उन्हें निजी के रूप में घोषित किया, न कि उन्हें किसी भी वर्ग से किसी भी वस्तु से बुलाया जाना चाहिए। यह "निजी सदस्य" की परिभाषा है;) – KingCrunch

+0

हां, निजी सदस्य निजी हैं क्योंकि वे निजी हैं :) लेकिन कल्पना करें कि आप अपना बटन 'हे बटन' बता रहे हैं, "बटनक्लिड हैंडलर" में अपना निजी कोड निष्पादित करें जब आप ' । इस मामले में मुझे नहीं लगता कि बटन का जवाब क्यों देना चाहिए 'ओह, मैं आपका कोड निष्पादित नहीं करना चाहता, क्योंकि यह निजी है, इसे सार्वजनिक बनाएं, फिर मैं करूँगा ...' लेकिन या तो मुझे कोई नहीं दिखाई देता कारण मुझे अपना निजी कोड क्यों बनाना चाहिए - सार्वजनिक ... आशा है कि आपको अंक – Lu4

+4

PHP प्राप्त नहीं है। नेट। मूंगफली का मक्खन और चॉकलेट के विपरीत। PHP इन चीजों के साथ बेहतर स्वाद नहीं लेगा। इसके अलावा, जो भी आपके बाद आता है वह शायद आपके कोड को टॉस कर देगा और इसे सभी तरह से पुनर्निर्माण करेगा। – DampeS8N

उत्तर

4

वैसे भी, अगर कोई दिलचस्पी है, तो मुझे ReflectionMethod के माध्यम से एकमात्र संभावित समाधान मिला है। पीएचपी 5.3.2 के साथ इस विधि का उपयोग प्रदर्शन दंड देता है और क्लास सदस्य को कॉल करने से 2.3 गुना धीमा है, और कॉल_user_func विधि से केवल 1.3 गुना धीमा है। तो मेरे मामले में यह बिल्कुल स्वीकार्य है। अगर कोई दिलचस्पी लेता है तो कोड यहां दिया गया है:

class EventArgs { 

} 

class EventEraser { 

    private $eventIndex; 
    private $eventErased; 
    private $eventHandlers; 

    public function __construct($eventIndex, array &$eventHandlers) { 
     $this->eventIndex = $eventIndex; 
     $this->eventHandlers = &$eventHandlers; 
    } 

    public function RemoveEventHandler() { 
     if (!$this->eventErased) { 
      unset($this->eventHandlers[$this->eventIndex]); 

      $this->eventErased = true; 
     } 
    } 

} 

class EventSubscriber { 

    private $eventIndex; 
    private $eventHandlers; 

    public function __construct(array &$eventHandlers) { 
     $this->eventIndex = 0; 
     $this->eventHandlers = &$eventHandlers; 
    } 

    public function AddEventHandler(EventHandler $eventHandler) { 
     $this->eventHandlers[$this->eventIndex++] = $eventHandler; 
    } 

    public function AddRemovableEventHandler(EventHandler $eventHandler) { 
     $this->eventHandlers[$this->eventIndex] = $eventHandler; 

     $result = new EventEraser($this->eventIndex++, $this->eventHandlers); 

     return $result; 
    } 

} 

class EventHandler { 

    private $owner; 
    private $method; 

    public function __construct($owner, $methodName) { 
     $this->owner = $owner; 
     $this->method = new \ReflectionMethod($owner, $methodName); 
     $this->method->setAccessible(true); 
    } 

    public function Invoke($sender, $eventArgs) { 
     $this->method->invoke($this->owner, $sender, $eventArgs); 
    } 

} 

class Event { 

    private $unlocked = true; 
    private $eventReceiver; 
    private $eventHandlers; 
    private $recursionAllowed = true; 

    public function __construct() { 
     $this->eventHandlers = array(); 
    } 

    public function GetUnlocked() { 
     return $this->unlocked; 
    } 

    public function SetUnlocked($value) { 
     $this->unlocked = $value; 
    } 

    public function FireEventHandlers($sender, $eventArgs) { 
     if ($this->unlocked) { 
      //защита от рекурсии 
      if ($this->recursionAllowed) { 
       $this->recursionAllowed = false; 

       foreach ($this->eventHandlers as $eventHandler) { 
        $eventHandler->Invoke($sender, $eventArgs); 
       } 

       $this->recursionAllowed = true; 
      } 
     } 
    } 

    public function Subscriber() { 
     if ($this->eventReceiver == null) { 
      $this->eventReceiver = new EventSubscriber($this->eventHandlers); 
     } 

     return $this->eventReceiver; 
    } 

} 
4

PHP में कॉलबैक अन्य भाषाओं में कॉलबैक की तरह नहीं हैं। विशिष्ट भाषाएं पॉइंटर्स के रूप में कॉलबैक का प्रतिनिधित्व करती हैं, जबकि PHP उन्हें तारों के रूप में दर्शाती है। स्ट्रिंग या array() वाक्यविन्यास और कॉल के बीच कोई "जादू" नहीं है। call_user_func(array($obj, 'str')) वाक्य रचनात्मक रूप से $obj->str() जैसा ही है। यदि str निजी है, तो कॉल विफल हो जाएगा।

आपको बस अपना ईवेंट हैंडलर सार्वजनिक बनाना चाहिए। इसका वैध अर्थपूर्ण अर्थ है, यानी, "मेरी कक्षा के बाहर से बुलाया जाने वाला इरादा है।"

इस कार्यान्वयन विकल्प अन्य रोचक साइड इफेक्ट, उदाहरण के लिए:

class Food { 
    static function getCallback() { 
     return 'self::func'; 
    } 

    static function func() {} 

    static function go() { 
     call_user_func(self::getCallback()); // Calls the intended function 
    } 
} 

class Barf { 
    static function go() { 
     call_user_func(Food::getCallback()); // 'self' is interpreted as 'Barf', so: 
    }           // Error -- no function 'func' in 'Barf' 
} 
+0

धन्यवाद zildjohn01, असल में मैं इस दृष्टिकोण का उपयोग कर रहा था, दिलचस्प बात यह है कि php संदर्भ को कैसे संभालता है, क्योंकि call_user_func कक्षा के अंदर निजी वर्ग विधियों के साथ काम कर रहा है। लेकिन बाहर काम करना बंद कर देता है। मेरी घटना बनाने के बारे में हैंडलर्स सार्वजनिक, मुझे लगता है कि ओओपी के मामले में यह शुद्ध बुराई है, और मैं कक्षा के बाहर निजी वर्ग के सदस्यों को कॉल करने का एक तरीका ढूंढ रहा था, और यह प्रतिबिंब विधि की मदद से PHP में संभव है, नीचे दी गई पोस्ट देखें । वैसे भी जवाब देने के लिए परेशान करने के लिए धन्यवाद। – Lu4