-
-
Save xsist10/824b559c4effaf43ddb3 to your computer and use it in GitHub Desktop.
<?php | |
// Version 1 | |
// Minified | |
// class Dispatch{function add($e,$l){$this->l[$e][]=$l;}function trigger($e,$d){foreach ($this->l[$e] as $l)call_user_func_array($l, $d);}} | |
class Dispatch{ | |
function add($e, $l) { | |
$this->l[$e][] = $l; | |
} | |
function trigger($e, $d) { | |
foreach ($this->l[$e] as $l) { | |
call_user_func_array($l, $d); | |
} | |
} | |
} | |
class Greeter { | |
public function greet($name) { | |
echo "Hello $name\n"; | |
} | |
} | |
$dispatch = new Dispatch(); | |
$dispatch->add('greet', array(new Greeter, 'greet')); | |
$dispatch->trigger('greet', array('Bob')); |
<?php | |
// Version 2 | |
// Minified | |
// class Dispatch{function add($e,$l){$this->l[$e][]=$l;}function trigger($e,$d){foreach($this->l[$e] as$l)$l($d);}} | |
class Dispatch { | |
function add($e, $l) { $this->l[$e][]=$l; } | |
function trigger($e, $d) { foreach ($this->l[$e] as $l) $l($d); } | |
} | |
$dispatch = new Dispatch(); | |
$dispatch->add('greet', function ($name) { | |
echo "Hello $name\n"; | |
}); | |
$dispatch->trigger('greet', 'Bob'); |
I've updated my version: I removed the foreach
brackets. This created some space for the event data parameter.
And as suggested by @wouterj I also removed some whitespace in the foreach loop: foreach($p as $q)
can be just foreach($p as$q)
.
Like the priority adding. @mathiasverraes, can we wangle event data passing into yours? We might also now need an event-object-in-a-tweet, but that should be significantly simpler...
@xsist10 Event data is back! See the comment above.
There you go, 18 characters shorter than @matthiasnoback's latest version, so it clocks in at 120 characters, which leaves enough room for a hashtag. It also has event data passing, so it's fully featured. The unit test now also tests the data passing.
I've had to change the api a bit, but it's for the better: using e() will make each call significantly shorter than the verbose E class.
<?php
function e($n,$p,$c=0){static $a;@krsort($a[$n]);if($c)$a[$n][$p][]=$c;else foreach($a[$n] as$q)foreach($q as$r)$r($p);}
function it($m,$p){echo ($p?'✔︎':'✘')." It $m\n"; if(!$p){$GLOBALS['f']=1;}}function done(){if(@$GLOBALS['f'])die(1);}
ob_start();
e(
'event',
0,
function ($data) {
echo "event, $data, priority 0;";
}
);
e(
'event',
10,
function ($data) {
echo "event, $data, priority 10;";
}
);
e(
'other_event',
-5,
function ($data) {
echo "other_event, $data, priority -5;";
}
);
e(
'other_event',
5,
function ($data) {
echo "other_event, $data priority 5;";
}
);
e('event', 'dataX');
e('other_event', 'dataY');
$output = ob_get_contents();
ob_end_clean();
it(
'calls event listeners in the right order',
$output === 'event, dataX, priority 10;event, dataX, priority 0;other_event, dataY priority 5;other_event, dataY, priority -5;'
);
✔︎ It is perfectly possible to inject the event dispatcher as a dependency into classes.
<?php
// (assume e() is included)
class Foo {
private $eventDispatcher;
function __construct($eventDispatcher)
{
$this->eventDispatcher = $eventDispatcher;
}
function doStuff()
{
// ...
call_user_func($this->eventDispatcher, "my_event", "my data");
}
}
ob_start();
$foo = new Foo(@e);
e("my_event", 5, function($data) { echo "My event was called with '$data'";});
$foo->doStuff();
$output = ob_get_contents();ob_end_clean();
it(
'is perfectly possible to inject the event dispatcher as a dependency into classes.',
$output === "My event was called with 'my data'"
);
Trying a new version:
<?php
class E{function r($n,$c,$p){$this->{$n}[$p][]=$c;krsort($this->$n);}function d($n,$d){@array_walk_recursive($this->$n,call_user_func,$d);}}
This one combines the work of @mathiasverraes and reintroduces event data. However, the event listeners should ignore the first argument passed to them, since that will be the key of the corresponding array value ;) see http://nl1.php.net/manual/en/function.array-walk-recursive.php
Oooh that looks pritty nice, @mathiasverraes!
By the way, I really like this as an exercise since it exposes all kinds of hidden assumptions, like a preference for classes, and an aversion of using different function parameters to trigger different actions :)
Nicked your update @mathiasverraes and used all that saved space you made to add event propagation control.
✔︎ It calls event listeners in the right order with event propagation
<?php
function e($n,$p,$c=0){static $a;@krsort($a[$n]);if($c)$a[$n][$p][]=$c;else foreach($a[$n] as$q)foreach($q as$r)if(!$r($p))return;}
function it($m,$p){echo ($p?'✔︎':'✘')." It $m\n"; if(!$p){$GLOBALS['f']=1;}}function done(){if(@$GLOBALS['f'])die(1);}
ob_start();
e(
'event',
0,
function ($data) {
echo "event, $data, priority 0;";
return true;
}
);
e(
'event',
10,
function ($data) {
echo "event, $data, priority 10;";
return true;
}
);
e(
'other_event',
-5,
// Should not reach this event due to propagation termination
function ($data) {
echo "other_event, $data, priority -5;";
return true;
}
);
e(
'other_event',
5,
function ($data) {
echo "other_event, $data priority 5;";
return false; // Will stop event propagation after this event
}
);
e('event', 'dataX');
e('other_event', 'dataY');
$output = ob_get_contents();
ob_end_clean();
it(
'calls event listeners in the right order with event propagation',
$output === 'event, dataX, priority 10;event, dataX, priority 0;other_event, dataY priority 5;'
);
maybe you are interested on a something like a framework ... https://github.com/liuggio/sized140
Dependency injection container in a tweet ... https://gist.github.com/jm42/3c32dd50bb9d09f57c4a
Two characters shorter, tests still pass. Functional programming bitches! I'll just blame php for the verbosity of the two function names at the end.