Make great applications with PHP

simply put: Events - Talks about handling events in your application, as well as hooks.

About Events

One of the most notable things about PHP ON PIE is that it makes heavy use of a common event system. In many places, rather than calling a function, PIE or your app would fire an event. This has many benefits, including:

  • The ability to override an event's handler by just dropping a file in the right place
  • Potential for attaching various hooks before or after an event
  • Loading code dynamically on demand, only when it is needed

In PIE, lots of things are implemented using events, including the entire controller logic of your app (this is the C in MVC).

Events are fired by calling:

Pie::event("foo/bar/baz", array('param1' => $value1))
By the way, you can often pass paarameters more elegantly, using PHP's compact function:
Pie::event("foo/bar/baz", compact('param1', 'param2'))


When an event named foo/bar/baz is fired, PIE attempts to find the corresponding event handler, by looking for a file called handlers/foo/bar/baz.php and expecting it to look something like this:


function foo_bar_baz($params) {
	// $params is the array of parameters passed to the event
The search proceeds along all the paths in get_include_path(). Your app's folder (APP_DIR) is checked first, followed by any plugins that were installed (more on that later in the guide), finally followed by the PIE framework's folder (PIE_DIR). This means that plugins can override PIE's default handlers (if any), and your app can override anything.

Normally, if the file of the handler is not found, or the function of the handler is not defined, PIE throws an exception. This happens unless a "pure event" is fired, which is explained next.


The event system in PIE allows hooks to be attached before or after any event. This is done by explicitly merging this information into the config fields pie/handlersBeforeEvent and pie/handlersAfterEvent. For example, the users plugin does this in its config/plugin.json file, something like the following:

	"pie": {
		"handlersBeforeEvent": {
			"pie/init": ["users/before/pie/init"],
			"pie/objects": ["users/before/pie/objects"],
			"pie/redirect": ["users/before/pie/redirect"]
		"handlersAfterEvent": {
			"pie/reroute": ["users/after/pie/reroute"]
After the above configuration file is merged into the config, the "users/before/pie/init" handler, for example, will now execute every time before the "pie/init" handler (which is intended to handle the "pie/init" event). Remember that a handler is just a function defined inside a file.

Pure events

Often, you will want to fire an event for which there is no default handler. This is done just so people can hook into your code, without having to hack it. By firing events when appropriate (whether pure or not), your code becomes more re-usable.

To execute any hooks registered to run before an event, you would write:

Pie::event("$app/myCoolEvent", $params, 'before');
To execute any hooks registered to run after an event, it would be:
Pie::event("$app/myCoolEvent", $params, 'after');
Note that pure events can — but do not have to — have corresponding handlers.

Here is an example of how pure events can be used to outsource caching:

class Users 
  static function fql($query)
    // run any hooks before sending our expensive request
    $ret = Pie::event('users/fql', compact('query'), 'before');

    if (isset($ret)) { // return what is likely a cached result
      return $ret;

    // otherwise, send the expensive request
    $app = Pie_Config::expect('pie', 'app');
    $result = Users::$facebooks[$app]->api_client->fql_query($query);
    // run any hooks after the result has been obtained
    // giving them a chance e.g. to cache the result for next time
    Pie::event('users/fql', compact('query', 'result'), 'after');
    return $result;

In fact, the users plugin has a method very similar to this.

Notice that PIE determines which hooks to run simply by checking the config at run-time. There is no "magic" going on — hooks are explicitly specified in a config file (e.g. by a plugin or by your app). As a result, firing pure events hardly incurs any overhead at all when there are no hooks attached — especially when all the config files are aggregated in production. So feel free to fire as many pure events as you need in your own code.

Return values

When an event is fired, the return value of the handler is ultimately what Pie::event(...) returns. However, hooks can be used to modify the value an event would return. To do this, the hook accepts a second parameter:


function myApp_before_pie_init($params, &$return)
	// $params are the parameters passed during Pie::event(...)
	// Meanwhile, &$return is what will be returned to the caller.
	// Modifying $return will modify this return value.
	// In "before" hooks, it starts out as null.
	// In "after" hooks, it starts out as the return value of the
	// event's handler, if any.


Notice that unlike an event's handler, a hook's return value does not become the return value of Pie::event(...). Instead, a hook can return false to skip all subsequent hooks. If this is done in a "before" hook, then the event's handler (if any) is skipped, too.

Complete reference to PHP ON PIE

TODO: include an iframe with PHPDoc-generated reference