CLI: Catching Ctrl+C, kill commands and fatal errors
Sometimes, when you write a Command Line (CLI) script, you want to catch Ctrl+C. Simple Example: Your script does some stuff on the database and you don't want to leave it in the state it had in the moment the script was killed, Ctrl+C'd or quit by a fatal error.
First off, we have to tell PHP to use ticks, in order for the catches to work (for more information on ticks check the pcntl_signal() documentation):
declare(ticks = 1);
Then, we add shutdown functions to the classes that have to rollback the state:
/**
* Cleanup if process has been killed unexpectedly
*
*/
private function shutdown()
{
$this->getTargetDb()->rollBack();
print('Script quit unexpectedly. Doing rollback' . PHP_EOL);
exit();
}
/**
* Method that is executed, when a Fatal Error occurs
*
*/
public function fatalErrorShutdown()
{
$lastError = error_get_last();
if (!is_null($lastError) && $lastError['type'] === E_ERROR) {
$this->shutdown();
}
}
/**
* Method, that is executed, if script has been killed by
* SIGINT: Ctrl+C
* SIGTERM: kill
*
* @param int $signal
*
*/
public function sigintShutdown($signal)
{
if ($signal === SIGINT || $signal === SIGTERM) {
$this->shutdown();
}
}
You shouldn't forget to include an exit() at some point in the shutdown methods or your script won't quit at all. In the example the shutdown() method (which is called by both shutdown methods, that will be registered afterwards) quits the script as soon as it's done.
As a last step, you only have to register your shutdown methods and you're done:
$sync = new Process_Sync();
// Catch Fatal Error (Rollback)
register_shutdown_function(array($sync, 'fatalErrorShutdown'));
// Catch Ctrl+C, kill and SIGTERM (Rollback)
pcntl_signal(SIGTERM, array($sync, 'sigintShutdown'));
pcntl_signal(SIGINT, array($sync, 'sigintShutdown'));
5 comments
14.01.2011, 23:30 o'clock
Works great, thanks!
Geoffrey McRae
27.02.2011, 10:51 o'clock
Umm, why the class… you can just do this..
function catchSigInt() {
}
function catchSigTerm() {
}
pcntl_signal(SIGINT , 'catchSigInt' );
pcntl_signal(SIGTERM, 'catchSigTerm');
You should also be aware that "register_shutdown_function" doesn't just occur on a fatal shutdown, it occurs EVERY time your script exits.
IT support UK
23.10.2011, 11:21 o'clock
C has a numerical value of three. It was chosen to cause an interrupt as it is otherwise unlikely to be part of the program's interactive interface.
31. Mai 2009
comments feed
recent posts
Robert de Wilde
07.02.2010, 09:53 o'clock
This was great help, thanks! Only thing is that my exit() didn't seem to be right, lol. Can't kill the proces :)