PHP

2011-01-03 26 views
8

delegeleri veya geri aramalar yapmanın doğru yolu ben php aşağıdaki deseni uygulamak gerekir:PHP

bunu doğru yolu nedir
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')); 
    } 

    ... 

}  

.

P.S.

Bu amaçla call_user_func kullanıyordum ve özel sınıf üyelerini arayabileceğine inanıyorum ya da inanmıyordum, ancak geliştirme birkaç hafta sonra çalışmayı durdurduğunu gördüm. Kodumda bir hata mıydı, yoksa bana 'call_user_func' özel sınıf işlevlerini çağırabildiğini düşündüğüm bir şey miydi, bilmiyorum, ama şimdi basit, hızlı ve zarif bir yöntemi güvenle arıyorum özel sınıf üyesini diğer sınıftan çağırmak. Şu anda kapanışlara bakıyorum ama kapağın içinde '$ this' ile ilgili problemlerim var ...

+1

'Kilitler (kılavuzda belirtildiği gibi) ve özel üyeleri desteklenmez $ this', özeldir çünkü onlar biri, kim onları özel olarak ilan etti, farklı bir sınıftan herhangi bir nesneden çağrılmasını istemiyorlar. Bu, "özel üye" tanımıdır;) – KingCrunch

+0

Evet, özel üyeler özel oldukları için gizlidir :) Ancak, düğmelerinize "Hey düğmesinin" tıklandığınızı hayal edin, düğmeyi tıklattığınızda "ButtonClickedHandler" içindeki özel kodumu çalıştırın ' . Bu durumda düğmenin niçin cevap vereceğini anlamıyorum 'Ah, kodunuzu yürütmek istemiyorum, çünkü bu özel, herkese açık hale getirsin, sonra yapacağım ...' Nedeni neden özel kodumu yapmalıyım - public ... Umarım puan – Lu4

+4

PHP değildir. Net. Fıstık ezmesi ve çikolatanın aksine. PHP, bu şeylerin içine adanmış olanlarla daha iyi tadamayacak. Ayrıca, muhtemelen sizden sonra gelen herkes, kodunuzu çıkarır ve tüm bunları aklı başında yeniden inşa eder. – DampeS8N

cevap

4

Her neyse, eğer birisi ilgilenirse, ReflectionMethod ile mümkün olan tek çözümü buldum. Php 5.3.2 ile bu yöntemin kullanılması, performans cezası verir ve sınıf üyesini doğrudan çağırmaktan 2,3 kat daha yavaşdır ve call_user_func yönteminden sadece 1,3 kat daha yavaştır. Yani benim durumumda kesinlikle kabul edilebilir. İlgilendiğiniz kişi kodu:

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'deki geri bildirimler, birçok dilde geri arama gibi değildir. Tipik diller geri bildirimleri işaretçi olarak gösterirken, PHP bunları dizge olarak gösterir. Dize veya array() sözdizimi ile çağrı arasında "sihirli" yoktur. call_user_func(array($obj, 'str')), sözdizimsel olarak $obj->str() ile aynıdır. str özelse, çağrı başarısız olur.

Yalnızca olay işleyicinizi herkese açık hale getirmelisiniz. Bunun geçerli anlamsal bir anlamı vardır, yani "sınıfımın dışından çağrılması amaçlanır."

Bu uygulama seçim örneğin diğer ilginç yan etkileri vardır:

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

Teşekkür ederim zildjohn01, aslında bu yaklaşımı daha önce kullanıyordum, ilginç olan şey php'nin içeriği nasıl ele almasıdır, çünkü call_user_func, sınıfın kendi içinde özel sınıf yöntemleri ile çalışıyor gibi görünüyor. Ama dışarıda çalışmayı keser. EventHandlers'ımı halka açmaya gelince, bunun OOP açısından saf bir kötülük olduğunu düşünüyorum ve kendi sınıfının dışındaki özel sınıf üyelerini aramak için bir yol arıyordum ve bu, ReflectionMethod'un yardımıyla PHP'de mümkün. . Her neyse cevap vermekten rahatsız olduğun için teşekkürler. – Lu4