问题
I am planning on working on a game that has a PHP back-end to communicate with the data repository. I was thinking about it and concluded that the best design paradigm to follow for our game would be event driven. I am looking to have an achievement system (similar to the badges system of this website) and basically I would like to be able to hook these "achievement checks" into a number of different events that occur in the game. ie:
When a user does action X hook Y is fired and all attached functions are called to check against an achievement requirement.
In structuring the architecture like this I will allow for new achievements to be added easily as all I will have to do is add the checking function to the proper hook and everything else will fall into place.
I'm not sure if this is a great explanation of what I intend to do, but in any case I am looking for the following:
- Good reference material on how to code an event-driven application
- Code snippet(s) showing how to put a "hook" in a function in PHP
- Code snippet(s) showing how to attach a function to the "hook" mentioned in point 2
I have a few ideas as to how to accomplish 2) and 3) but I was hoping that somebody well-versed in the matter could shed some light on best practices.
Thank you in advance!
回答1:
Good reference material on how to code an event-driven application
You can either do this with "dumb" callbacks (Demo):
class Hooks
{
private $hooks;
public function __construct()
{
$this->hooks = array();
}
public function add($name, $callback) {
// callback parameters must be at least syntactically
// correct when added.
if (!is_callable($callback, true))
{
throw new InvalidArgumentException(sprintf('Invalid callback: %s.', print_r($callback, true)));
}
$this->hooks[$name][] = $callback;
}
public function getCallbacks($name)
{
return isset($this->hooks[$name]) ? $this->hooks[$name] : array();
}
public function fire($name)
{
foreach($this->getCallbacks($name) as $callback)
{
// prevent fatal errors, do your own warning or
// exception here as you need it.
if (!is_callable($callback))
continue;
call_user_func($callback);
}
}
}
$hooks = new Hooks;
$hooks->add('event', function() {echo 'morally disputed.';});
$hooks->add('event', function() {echo 'explicitly called.';});
$hooks->fire('event');
Or implementing a pattern often used in event-driven applications: Observer Pattern.
Code snippet(s) showing how to put a "hook" in a function in PHP
The manual link above (callbacks can be stored into a variable) and some PHP code examples for the Observer Pattern.
回答2:
For PHP I've regulary integrated the Symfony Event Component: http://components.symfony-project.org/event-dispatcher/.
Here's a short example below, which you can find expanded in Symfony's Recipe section.
<?php
class Foo
{
protected $dispatcher = null;
// Inject the dispatcher via the constructor
public function __construct(sfEventDispatcher $dispatcher)
{
$this->dispatcher = $dispatcher;
}
public function sendEvent($foo, $bar)
{
// Send an event
$event = new sfEvent($this, 'foo.eventName', array('foo' => $foo, 'bar' => $bar));
$this->dispatcher->notify($event);
}
}
class Bar
{
public function addBarMethodToFoo(sfEvent $event)
{
// respond to event here.
}
}
// Somewhere, wire up the Foo event to the Bar listener
$dispatcher->connect('foo.eventName', array($bar, 'addBarMethodToFoo'));
?>
This is the system we integrated into a shopping cart to create a game-like shopping experience, hooking user actions into game-events. When the user performed specific actions, php fired events causing rewards to be triggered.
Example 1: if the user clicked a specific button 10 times, they received a star.
Example 2: when the user refers a friend and that friend signs up an event is fired rewarding the original referrer with points.
回答3:
Check out CodeIgniter as it has hooks built right in.
Simply enable hooks:
$config['enable_hooks'] = TRUE;
And then define your hook:
$hook['post_controller_constructor'] = array(
'class' => 'Hooks',
'function' => 'session_check',
'filename' => 'hooks.php',
'filepath' => 'hooks',
'params' => array()
);
Then use it in your class:
<?php
class Hooks {
var $CI;
function Hooks() {
$this->CI =& get_instance();
}
function session_check() {
if(!$this->CI->session->userdata("logged_in") && $this->CI->uri->uri_string != "/user/login")
redirect('user/login', 'location');
}
}
?>
来源:https://stackoverflow.com/questions/6846118/event-driven-architecture-and-hooks-in-php