Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The correct way of doing delegates or callbacks in PHP

I need to implement the following pattern in 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'));
    }

    ...

}    

what is the correct way to do so.

P.S.

I was using call_user_func for that purpose and believe it or not it was able to call private class members, but after few weeks of development i've found that it stopped working. Was it a bug in my code or was it some something else that made me think that 'call_user_func' is able call private class functions, I don't know, but now I'm looking for a simple, fast and elegant method of safely calling one's private class member from other class. I'm looking to closures right now, but have problems with '$this' inside closure...

like image 568
Lu4 Avatar asked Jan 03 '11 11:01

Lu4


People also ask

What is callback in PHP?

A callback function (often referred to as just "callback") is a function which is passed as an argument into another function. Any existing function can be used as a callback function.

Is Delegate same as callback?

The calling class sets the delegate to it's callback. The difference between a delegate and a callback is the perspective: The service class calls the delegate that is set to the calling classes callback.

What is delegate PHP?

This is delegation – a process by which one object implements a particular behavior by sending messages to another object which implements the same or a similar behavior. You are going to modify the DBQuery object to include all functions which work on a result resource from the DB object.

What is callable type in PHP?

callable is a php data type. It simply means anything which can be called i.e. a function type. If this function is a closure, static/regular method or something else doesn't matter as long as we can call the function.


1 Answers

Callbacks in PHP aren't like callbacks in most other languages. Typical languages represent callbacks as pointers, whereas PHP represents them as strings. There's no "magic" between the string or array() syntax and the call. call_user_func(array($obj, 'str')) is syntactically the same as $obj->str(). If str is private, the call will fail.

You should simply make your event handler public. This has valid semantic meaning, i.e., "intended to be called from outside my class."

This implementation choice has other interesting side effects, for example:

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'
}
like image 121
zildjohn01 Avatar answered Oct 13 '22 05:10

zildjohn01