Tilman Werthschulte wechselt zu AntTrail

Tilman Werthschulte FotoTilman Werthschulte wird ab sofort das Hamburger AntTrail Team verstärken. Der studierte Kommunikations- und Multimediadesigner war zuvor vier Jahre als Projektmanager für das Aachener Unternehmen Powerflasher tätig, bevor sich dieses zur Interactive Pioneers GmbH umfirmierte. Der 29jährige übernahm dann für Interactive Pioneers in Hamburg den Posten des Team- und Projektleiters. Er verantwortete in dieser Funktion digitale Kampagnen, unter anderem für Kunden wie Heine, Nike, Converse und Yellostrom.

Tilman Werthschulte ist Experte für Social Media Tools, Social Apps, Mediaschaltung auf Facebook und Social Video Distribution. Er bringt eine große Expertise aus komplexen Projekten und vor allem technologisches Know-how mit. Für AntTrail wird er Social Media Kampagnen entwickeln, Kunden strategisch beraten und Partnerschaften mit Werbeagenturen aufbauen. Als Senior Account Manager berichtet er an den Geschäftsführer Marco Luschnat.

„Das AntTrail-Team freut sich sehr über den Zuwachs. Mit Tilman haben wir einen erfahrenen Social Media Experten gewonnen. Die Kombination aus technischem und kreativem Know-how ist unser USP. Tilman vereint beides und wir freuen uns auf erste tolle Kampagnen“ kommentiert Marco Luschnat, Geschäftsführer der AntTrail GmbH.

(diese Meldung auf anttrail.de)

PHP event dispatcher

PHP event dispatcher


Dispatching and listening to events is a common concept with many advantages in a lot of applications but is hardly used nor natively supported in PHP. In this article I present you my own, very simple yet powerful implementation mimicking JavaScripts event bubbling on DOM-elements.

I stumbled across a nice article on phphatesme.com lately which made me think about event based programming in PHP. In jQuery or almost any of the Google Javascript-APIs, at least, events and event listeners are a concept widely spread, used and accepted.

I did some more research regarding event based concepts in PHP and found that symfony components has (as usual) its own solution which is quite similar to what phphatesme.com developed. A closer look showed that although working nicely both solutions seemed a bit limited in their possibilities because both allow listeners to be attached to an exactly named event only. So what I had in mind was more or less an event tree, behaving very similar to browser event bubbling.

Components of an event dispatcher in PHP

„Event“ class

As I tend to use object oriented programming whereever possible I started with a very small class as a skeleton for all types of events. An event only consists of a „name“ property and an array of „parameters“, both private. The magic method __get is used to the otherwise private properties publicly readable only.

			<?php
			class Event {
				private $name;
				private $parameters = array();

				public function __construct($name, array $parameters = array()) {
					$this->name       = $name;
					$this->parameters = $parameters;
				}

				public function __get($property) {
					if(isset($this->$property)) {
						return $this->$property;
					}
				}
			}
			?>

„Dispatcher“ class

Afterwards I started building the skeleton for the so called dispatcher which is used to bind listeners to events and notify them when an event is triggered.

			<?php
			class Dispatcher {
				private $callbacks = array();
				private $events    = null;

				public function __construct() {  }
				public function addListener($callback, $event) {  }
				public function notify(Event &$event) {  }
			?>

If you read carefully you might have noticed the word „tree“ and this is exactly what will be used throughout the class to store and manage all events. So the class constructor will initialize the private property „events“ to be a SimpleXMLElement:

			<?php
			class Dispatcher {
				...

				public function __construct() {
					$this->events = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8" standalone="yes"?><events></events>');
				}

				...
			?>

After that I continued with the „addListener“ method. Notice the parameter „$event“ which is a string in this case and uses „/“ as a separator for the tree/path structure.

			<?php
			class Dispatcher {
				...

				public function addListener($callback, $event) {
					$return = false;

					if(is_callable($callback) === true) {
						if(is_array($callback)) {
							$id = md5(get_class($callback[0]) . json_encode($callback));
						} else {
							$id = md5(json_encode($callback));
						}

						$matches =& $this->_getEvent($event);

						foreach($matches as $match) {
							$status = $match->xpath('./listener[@id=\'' . $id . '\']');
							$status = ($status === false || count($status) === 0) ? false : true;

							if($status === false) {
								$listener       = $match->addChild('listener');
								$listener['id'] = $id;

								unset($listener);
							}
						}

						if(!isset($this->callbacks[$id])) {
							$this->callbacks[$id] =& $callback;
						}

						$return = true;
					}

					return $return;
				}

				// fetches all existing events matching the passed event name
				private function &_getEvent($node) {
					$matches = $this->events->xpath('/events/' . $node . '[not(@id)]');

					if($matches === false || count($matches) === 0) {
						$matches = $this->_build($node);
					}

					return $matches;
				}

				// adds an event to the class events property and returns it as a pointer
				private function _build($node) {
					$nodes   =  explode('/', $node);
					$pointer =& $this->events;

					foreach($nodes as $node) {
						if(!isset($pointer->$node)) {
							$pointer->addChild($node);
						}

						$pointer =& $pointer->$node;
					}

					return array($pointer);
				}

				...
			?>

Being able to add listeners from here on only one thing is missing: a method to trigger an event or, to be precise, notify all registered listeners that an event was triggered.

			<?php
			class Dispatcher {
				...

				public function notify(Event &$event) {
					$return = false;

					if($this->events !== null) {
						$matches    =& $this->_getEvent($event->name);
						$expression =  '/events/' . $event->name . '[not(@id)]/listener[@id]|/events/' . $event->name . '[not(@id)]/ancestor::*/listener[@id]';
						$matches    =  $this->events->xpath($expression);

						if(is_array($matches)) {
							foreach($matches as $match) {
								call_user_func_array($this->callbacks[(string) $match['id']], $event->parameters);
							}
						}

						$return = true;
					}

					return $return;
				}

				...
			?>

Practical usage of the dispatcher

Usage of the event dispatcher is really simple, just to give you an example:

			<?php
			$dispatcher = new Dispatcher();
			$dispatcher->addListener('exampleCallback', 'example')

			// trigger the event directly...
				$event = new Event('example', array('exampleParam1', 'exampleParam2'));
				$dispatcher->notify($event);

			// or make use of "bubbling"
				$event = new Event('example/subevent', array('exampleParam1', 'exampleParam2'));
				$dispatcher->notify($event);

			function exampleCallback($exampleParam1, $exampleParam2) {
				echo $exampleParam1 . ', ' . $exampleParam2;
			}
			?>