PHP’s register_shutdown_function

Personally, I’m not a fan of PHP. With 5830 functions defined in the global namespace as of right now, how could one ever make the argument that PHP is a well thought-out language? However, what the language is good at is giving you a bunch of tools that you never even thought you wanted. Case in point: register_shutdown_function.

This obscure, but fantastically useful, function allows you to execute a block of code whenever your script ends — for any reason. Whether your page exit()s or die()s or just finishes, a developer has a hook to run whatever code he/she deems necessary. And not just one function either… you can use this call to register as many shutdown functions as you want, and they will get executed in the order that they get applied. But of course, you must be careful: PHP will happily give you more rope than you will ever need to hang yourself. A lot of people may consider the use of this function to be magic, and you’ll want to be very clear that what you’re doing is documented.

Use of this function is very straight-forward.

void register_shutdown_function ( callback $function [, mixed $parameter [, mixed $... ]] )

Now, something undocumented (but incredibly useful) is that you can pass a lambda function in for callback. The examples on php.net show that you should pass in a string (or array) representing a function to call. So, if the function that you wanted to call was named “bye”, you would call register_shutdown_function(“bye”). But say that you wanted to call a method called “bye” on a “Utilities” class. Well, then you must call register_shutdown_function(array(“Utilities”,”bye”)). Honestly, I find that incredibly unintuitive and hard to follow. I would much rather see this:

register_shutdown_function(function() { /* do something */ });

But then again, I love javascript, and oh do I miss functional programming….

Now, you might be asking yourself: why would I ever need to use that function?

register_shutdown_function(function() {
	Timer::writeAll();
});

class Timer {
	private static $events = array();
	public static function set($title) {
		self::$events[] = array("name" => $title, "time" => microtime(true));
	}
	public static function writeAll() {
		array_walk(self::$events, function($item) {
			echo $item["name"] . ": " . $item["time"] . "\n";
		});
	}
}

Timer::set("Test before 1000");
for($i=0; $i<1000; $i++);
Timer::set("Test after 1000");
for($i=0; $i<10000; $i++);
Timer::set("Test after 10,000");
for($i=0; $i<1000000; $i++);
Timer::set("Test after 1,000,000");

This highly simplified example shows a Timer class with two methods: “set” and “writeAll”. Perhaps you were doing some performance testing and you decided to litter your code with Timer::set() calls. At the end of the script, you can print out all of your debugging information to show where any bottlenecks may be.

The output would look something like this:

Test before 1000: 1298609284.6236
Test after 1000: 1298609284.6237
Test after 10,000: 1298609284.6245
Test after 1,000,000: 1298609284.699
Leave a comment

0 Comments.

Leave a Reply


[ Ctrl + Enter ]