# Lithium 0.9: The Lambdas-are-awesome! Edition
I'm very excited to announce the immediate release of Lithium 0.9 ([download now!](http://rad-dev.org/lithium/versions)). Three weeks and [wiki:releases/0_9 80 changes] after 0.8, this release moves us much closer to 1.0. A few of the new features include:
**ErrorHandler**: The `ErrorHandler` class provides a highly configurable solution for capturing and handling PHP errors and exceptions across your entire application. Its innovative design allows you to capture errors / exceptions on a variety of parameters, including type (error or exception), error code, exception class name (with inheritance), the class where the error originated, or any class / method that appears in the stack trace.
If you update your applications to 0.9, you can try the following example right now:
Create a new file in your application's config, let's say `config/bootstrap/error.php`, include it in your boostrap, and add the following:
{{{
/**
* First, import the relevant Lithium core classes.
*/
use \lithium\core\ErrorHandler;
use \lithium\analysis\Logger;
use \lithium\template\View;
/**
* Then, set up a basic logging configuration that will write to a file.
*/
Logger::config(array('error' => array('adapter' => 'File')));
/**
* Configure an error page renderer function that we can use to render 404 and 500 error pages (for
* this part to work, you need to create errors/404.html.php and errors/500.html.php in your views/
* directory).
*/
$render = function($template, $content) {
$view = new View(array(
'paths' => array(
'template' => '{:library}/views/{:controller}/{:template}.{:type}.php',
'layout' => '{:library}/views/layouts/{:layout}.{:type}.php',
)
));
echo $view->render('all', compact('content'), compact('template') + array(
'controller' => 'errors',
'layout' => 'default',
'type' => 'html'
));
};
/**
* Finally, wire up the error configuration. The first rule captures any exceptions where the
* message matches one of the given regular expressions: eitheer a template or controller wasn't
* found. In either case, render a 404.
*
* For all other exceptions, log them to the error log, and show the user a 500 error.
*/
ErrorHandler::config(array(
array(
'type' => 'Exception',
'message' => '/(^Template not found|^Controller \w+ not found)/',
'handler' => function($info) use ($render) {
$render('404', $info);
}
),
array(
'type' => 'Exception',
'handler' => function($info) use ($render) {
Logger::write('error', "{$info['file']} : {$info['line']} : {$info['message']}");
$render('500', $info);
}
)
));
/**
* Last but not least, tell the ErrorHandler to start capturing errors.
*/
ErrorHandler::run();
}}}
And you instantly have a fully-customizable error management solution. The handlers allow you to respond to errors in whatever way you see fit, but usually this means logging them and/or rendering an error page (in the case of uncaught exceptions).
**Persistent parameters**: Among the many enhancements to routing are the addition of persistent parameters. When connecting a new route, this feature allows you to specify a list of parameters which, if the route is matched, will be persist through the request, and will be used to generate subsequent links. Consider these two routes:
{{{
Router::connect('/admin/{:controller}/{:action}', array('admin' => true), array('persist' => array(
'admin', 'controller'
)));
Router::connect('/{:controller}/{:action}');
}}}
Now, when browsing the admin section of the site, any links generated will automatically inherit the persisted property:
{{{<?=$this->html->link('Add post', array('controller' => 'posts', 'action' => 'add')); // links to /admin/posts/add ?>}}}
To disable the parameter(s), simply pass the corresponding key with a `null` value:
{{{<?=$this->html->link(
'Add post', array('controller' => 'posts', 'action' => 'add', 'admin' => null
)); // links to /posts/add ?>}}}
**Route Handlers**: One of the most important new features, route handlers allow you to apply controller logic directly to application routes. This allows for some very cool features, like the ability to develop small, fast micro-applications. Previously the domain of plugins outside the framework, this functionality has been moved into core and can be mixed directly in with your application's main routing. Consider this simple example:
{{{
use lithium\action\Response;
use \lithium\net\http\Router;
Router::connect('/hello/{:name}', array('name' => null), function($request) {
$name = $request->name ?: 'World';
return new Response(array('body' => "Hello {$name}!"));
});
Router::connect('/redirect', array('name' => null), function($request) {
return new Response(array('location' => '/'));
});
}}}
The first thing of note about this is that route handlers are able to directly return a `Response` object, which immediately bypasses everything else in the framework, and renders the response. Alternatively, handlers can return the `$request` parameter (optionally modifying it), and processing will continue as normal. In the first example, a greeting is written to the screen, either to no one in particular ("Hello World!" when accessing `/hello`), or to the `{:name}` parameter specified in the URL ("Hello Nate!" when accessing `/hello/Nate`).
In the second example, requests to `/redirect` are captured, and the handler returns a `Response` object that redirects the browser to another page. With the `Response` object (which is also available as a property in controller objects), you have direct control over how the response is returned to the browser.
**Template extraction**: Because some developers in the community prefer more explicitness when authoring templates, we've implemented an alternative syntax for accessing template variables. In addition to, for example, `$title`, template variables are now accessible as `$this['title']`.
Also available is the option to completely disable the extraction of variables into templates. By adding the `'extract'` parameter to the correct configuration, we can easily disable regular template variables:
{{{
Media::type('html', 'text/html', array(
'view' => '\lithium\template\View',
'extract' => false,
'paths' => array(
'template' => '{:library}/views/{:controller}/{:template}.{:type}.php',
'layout' => '{:library}/views/layouts/{:layout}.{:type}.php',
)
));
}}}
After applying this configuration, `$this['title']` will continue to work, but `$title` will not.
Finally, [ Joël](http://twitter.com/jperras) and I will be speaking at the upcoming [ TEK·X](http://tek.phparch.com/) conference a month from tomorrow. We'll be presenting a joint session on Lithium, as well as individual sessions on code quality and (social) graph theory. [Sign up now](http://tek.phparch.com/signup/), then come by and say hi. Hope to see you in Chicago.
~ nate ~
<a href="http://tek.phparch.com"><img src="http://
tekx.s3.amazonaws.com/TEKX_SpeakerBadge_135x135.png" height="135" width="135" /></a>