Advertisement
  1. Code
  2. PHP

How to Use the Symfony Event Dispatcher for PHP

Scroll to top
Read Time: 9 min

Today, we're going to learn how to use the Symfony event dispatcher component, which allows you to create events and listeners in your PHP applications. Thus, different components of your application can talk to each other with loosely coupled code.

What Is the Symfony Event Dispatcher Component?

You may be familiar with the event-observer pattern, which allows you to define listeners for system-generated events so that they are executed when the event is triggered. Similarly, the Symfony EventDispatcher component allows you to set up a system in which you could create custom events and listeners. In that way, you allow components in your application to react if something happens in a system.

In fact, the event dispatcher component provides three elements that you could build your app architecture around: event, listener, and dispatcher. The whole system is orchestrated by the dispatcher class, which raises events at appropriate points in an application and calls listeners associated with those events.

Let's assume that you want to allow other components in your application to react when the cache is cleared. In that case, you need to define the clear cache event in the first place. After the cache is cleared, you can use the dispatcher to raise the clear cache event, and that notifies all listeners that are listening to this event. This gives listeners the opportunity to purge component-specific caches.

In this article, we'll explore the basics of the event dispatcher component. We'll start with installation and configuration, and we'll also create a few real-world examples to demonstrate all the concepts mentioned above.

Installing and Configuring the Event Dispatcher

In this section, we're going to install the event dispatcher component. I assume that you've already installed Composer on your system, because we'll need it to install the EventDispatcher component.

Once you've installed Composer, go ahead and install the EventDispatcher component using the following command.

1
$composer require symfony/event-dispatcher

That should have created the composer.json file, which should look like this:

1
{
2
    "require": {
3
        "symfony/event-dispatcher": "^5.4"
4
    }
5
}

Let's further edit the composer.json file to look like the following:

1
{
2
    "require": {
3
        "symfony/event-dispatcher": "^5.4"
4
    },
5
    "autoload": {
6
         "psr-4": {
7
             "EventDispatchers\\": "src"
8
         },
9
         "classmap": ["src"]
10
     }
11
}

As we've added a new classmap entry, go ahead and update the Composer autoloader by running the following command.

1
$composer dump -o

Now, you can use the EventDispatchers namespace to autoload classes under the src directory.

So that's the installation part, but how are you supposed to use it? In fact, it's just a matter of including the autoload.php file created by Composer in your application, as shown in the following snippet.

1
<?php
2
require_once './vendor/autoload.php';
3
 
4
// application code

5
?>

How to Create, Dispatch, and Listen to Events

In this section, we'll go through an example which demonstrates how you could create a custom event and set up a listener for that event.

The Event Class

To start with, go ahead and create the src/Events/DemoEvent.php file with the following contents.

1
<?php
2
namespace EventDispatchers\Events;
3
 
4
use Symfony\Contracts\EventDispatcher\Event;
5
 
6
class DemoEvent extends Event
7
{
8
    const NAME = 'demo.event';
9
 
10
    protected $foo;
11
 
12
    public function __construct()
13
    {
14
        $this->foo = 'bar';
15
    }
16
 
17
    public function getFoo()
18
    {
19
        return $this->foo;
20
    }
21
}

Our custom DemoEvent class extends the core Event class of the EventDispatcher component. The NAME constant holds the name of our custom eventdemo.event. It's used when you want to set up a listener for this event.

The Listener Class

Next, let's create the listener class src/Listeners/DemoListener.php with the following contents.

1
<?php
2
namespace EventDispatchers\Listeners;
3
 
4
use Symfony\Contracts\EventDispatcher\Event;
5
 
6
class DemoListener
7
{
8
    public function onDemoEvent(Event $event)
9
    {
10
      // fetch event information here

11
      echo "DemoListener is called!\n";
12
      echo "The value of the foo is: ".$event->getFoo()."\n";
13
    }
14
}

The DemoListener class implements the onDemoEvent method which is triggered when the system dispatches the DemoEvent event. Of course, it won't happen automatically yet, as we need to register the DemoListener listener to listen to the demo.event event using the EventDispatcher class.

So far, we've created event and listener classes. Next, we'll see how to tie all these pieces together.

An Example File

Let's create the basic_example.php file with the following contents.

1
<?php
2
// basic_example.php

3
 
4
require_once './vendor/autoload.php';
5
use Symfony\Component\EventDispatcher\EventDispatcher;
6
use EventDispatchers\Events\DemoEvent;
7
use EventDispatchers\Listeners\DemoListener;
8
 
9
// init event dispatcher

10
$dispatcher = new EventDispatcher();
11
 
12
// register listener for the 'demo.event' event

13
$listener = new DemoListener();
14
$dispatcher->addListener('demo.event', array($listener, 'onDemoEvent'));
15
 
16
// dispatch

17
$dispatcher->dispatch(new DemoEvent(), DemoEvent::NAME);

The EventDispatcher class is the most important element in the EventDispatcher component—it allows you to bind listeners to events they want to listen to. We've used the addListener method of the EventDispatcher class to listen to the demo.event event.

The first argument of the addListener method is the PHP callable which is triggered when the registered event is dispatched, and the second argument is an event name. In our case, we've provided the DemoListener object as a listener along with the onDemoEvent method.

1
$dispatcher->addListener('demo.event', array($listener, 'onDemoEvent'));

Finally, we've used the dispatch method of the EventDispatcher class to dispatch the demo.event event.

1
$dispatcher->dispatch(DemoEvent::NAME, new DemoEvent());

When you run the basic_example.php file, it should produce the following output.

1
$php basic_example.php
2
DemoListener is called!
3
The value of the foo is: bar

As expected, the onDemoEvent method of the DemoListener class is called, and that in turn calls the getFoo method of the DemoEvent class to fetch the event-related information.

What Is an Event Subscriber?

In the previous section, we built an example which demonstrated how to create a custom event and a custom listener. We also discussed how to bind a listener to the specific event using the EventDispatcher class.

That was a simple example, as we only wanted to set up a listener for a single event. On the other hand, if you want to set up listeners for multiple events or you want to logically group event handling logic in a single class, you should consider using event subscribers because they allow you to keep everything in one place.

In this section, we'll revise the example which was created in the previous section.

The Subscriber Class

The first thing that we need to do is to create a subscriber class which implements the EventSubscriberInterface interface. Go ahead and create the src/Subsribers/DemoSubscriber.php class as shown in the following snippet.

1
<?php
2
namespace EventDispatchers\Subscribers;
3
 
4
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
5
use EventDispatchers\Events\DemoEvent;
6
 
7
class DemoSubscriber implements EventSubscriberInterface
8
{
9
    public static function getSubscribedEvents()
10
    {
11
        return array(
12
            DemoEvent::NAME => 'onDemoEvent',
13
        );
14
    }
15
 
16
    public function onDemoEvent(DemoEvent $event)
17
    {
18
      // fetch event information here

19
      echo "DemoListener is called!\n";
20
      echo "The value of the foo is :".$event->getFoo()."\n";
21
    }
22
}

Since the class DemoSubscriber implements the EventSubscriberInterface interface, it must implement the getSubscribedEvents method. The getSubscribedEvents method should return an array of events that you want to subscribe to. You need to provide the event name in an array key and the method name in an array value which is called when the event is triggered.

The last thing is to implement the listener method in the same class. In our case, we need to implement the onDemoEvent method, and we've already done that.

An Example File

It's time to test our subscriber! Let's quickly create the subscriber_example.php file with the following contents.

1
<?php
2
require_once './vendor/autoload.php';
3
use Symfony\Component\EventDispatcher\EventDispatcher;
4
use EventDispatchers\Subscribers\DemoSubscriber as DemoSubscriber;
5
use EventDispatchers\Events\DemoEvent;
6
 
7
// init event dispatcher

8
$dispatcher = new EventDispatcher();
9
 
10
// register subscriber

11
$subscriber = new DemoSubscriber();
12
$dispatcher->addSubscriber($subscriber);
13
 
14
// dispatch

15
$dispatcher->dispatch(new DemoEvent(), DemoEvent::NAME);

You need to use the addSubscriber method of the EventDispatcher class to subscribe your custom subscriber, and the EventDispatcher class handles the rest. It fetches events to be subscribed from the getSubscribedEvents method and sets up listeners for those events. Apart from that, everything is the same, and it should work as expected with no surprises.

Let's test it!

1
$php subscriber_example.php
2
DemoListener is called!
3
The value of the foo is: bar

And that was an event subscriber at your disposal! That also brings us to the end of this article.

How to Stop Event Propagation

Sometimes, multiple listeners are listening to the same event. In that case, you might want to stop event propagation to the next follow-up listeners. In this section, we'll see how you could achieve it with the help of a listener.

Let's revisit the listener class which we created earlier.

1
<?php
2
namespace EventDispatchers\Listeners;
3
 
4
use Symfony\Contracts\EventDispatcher\Event;
5
 
6
class DemoListener
7
{
8
    public function onDemoEvent(Event $event)
9
    {
10
      // fetch event information here

11
      echo "DemoListener is called!\n";
12
      echo "The value of the foo is: ".$event->getFoo()."\n";
13
      $event->stopPropagation();
14
    }
15
}

As you can see, we've used the stopPropagation method to stop event propagation. It means that listeners that are listening to the demo.event event and are not yet called, won't be called. So this is the last listener which is called for this event. You can also use the isPropagationStopped method to detect if the event propagation was stopped by any listener.

How to Use PHP Closures as Listeners

So far, we've discussed how to add PHP objects as listeners. In fact, you can also use PHP closures instead of PHP objects.

Let's quickly revise the earlier example.

1
<?php
2
require_once './vendor/autoload.php';
3
use Symfony\Component\EventDispatcher\EventDispatcher;
4
use EventDispatchers\Events\DemoEvent;
5
 
6
// init event dispatcher

7
$dispatcher = new EventDispatcher();
8
 
9
// register closure listener for the 'demo.event' event

10
$dispatcher->addListener('demo.event', function (DemoEvent $event) {
11
    echo "DemoListener is called!\n";
12
    echo "The value of the foo is: ".$event->getFoo()."\n";
13
});
14
 
15
// dispatch

16
$dispatcher->dispatch(new DemoEvent(), 'demo.event');

As you can see, we've used the PHP closure in the second argument of the addListener method.

Conclusion

Today, we explored the Symfony event dispatcher component, which allows you to set up events and listeners in your PHP applications. By using this library, you can create a loosely coupled system which allows components of your application to communicate with each other effortlessly.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.