PHP 5.4 was released this week, and one of the biggest new capabilities from a language perspective is traits, called mixins in some other languages. Traits are basically a way of creating a set of reusable methods and properties and adding them to class, almost like copy paste. In a way this is like inheritance, but a class can use multiple traits to add multiple capabilities. Whereas with inheritance you say something like ‘a Dog is an Animal’, with traits you say ‘a Dog can be observed’.

To try out traits I took inspiration from JavaScript, a language that I’ve been using quite a bit recently. Client-side javascript for complex applications is very event driven and accordingly makes heavy use of event listeners – both DOM events and custom events. One approach that I’ve been impressed with is Sencha’s Observable class/mixin that allows classes to easily fire events and notify any listeners without tightly coupling the listeners and the observed.

While PHP is significantly less event driven (user input only comes at the beginning of a script), I thought that implementing a similar Observable mechanism would be a good way to try out the new feature. I’ve added the trait to my growing library of utility classes on Github. Here’s how it works:

1. A class uses the ObservableTrait and then fires events whenever an important event occurs:

<?php
require_one('gUtils/ObservableTrait.php');
Class Dog {
	use gUtils\ObservableTrait;
	public $name;
 
	public function __construct($name) {
		$this->name = $name;
	}
 
	public function bark() {
		echo "woof woof\n";
		$this->fireEvent('barked', $this);
	}
 
	public function rollOver() {
		echo '(' . $this->name . " rolls over)\n";
		$this->fireEvent('didTrick', $this, 'roll over');
	}
 
	public function shake() {
		echo '(' . $this->name . " shakes hands)\n";
		$this->fireEvent('didTrick', $this, 'shake hands');
	}
}

The calls to fireEvent include the name of the event, and any additional parameters that should be passed to any listener.

2. On instantiation of an object, listeners can be attached to the object to be notified when particular events occur:

<?php
require('Dog.php');
$fido = new Dog('Fido');
$listeners = $fido->addListeners([
	'barked' => function($dog) {
		echo 'Shhh ' . $dog->name . "\n";
	},
	'didTrick' => function($dog, $trickName){
		echo 'Good dog, ' . $dog->name . " - I love it when you {$trickName}\n";
	}
]);
$fido->bark(); // Shhh Fido
$fido->rollOver(); // Good dog, Fido - I love it when you roll over
$fido->shake(); // Good dog, Fido - I love it when you shake hands
$fido->stopEvents();
echo "stopped listening for a while\n";
 
$fido->bark();
$fido->bark();
$fido->shake();
$fido->bark();
$fido->bark();
$fido->resumeEvents();
echo "listening again\n";
$fido->bark(); // Shhh Fido
$fido->removeListener($listeners[0]);
echo "removed bark listener\n";
$fido->bark();
$fido->rollOver(); // Good dog, Fido - I love it when you roll over

And that’s about it – you can:

  • Add Events
  • Add Listeners (one at a time or multiple)
  • Remove Listeners (one at a time or multiple)
  • Stop throwing events
  • Resume throwing events
  • Remove all listeners

So take a look and let me know what you think…