Signal handling on Windows

Update March 2020: As of PHP 7.4, there is sapi_windows_set_ctrl_handler() and sapi_windows_generate_ctrl_event. This lets your script handle Ctrl+C and Ctrl+Break keypresses as well as generate them for other processes in the same process group. proc_open() has also added the create_process_group option to allow the child process to handle CTRL events. This is the best you can do on Windows as far as signal handling goes. Note that these functions are only available to the PHP CLI SAPI (i.e. php.exe) and they only function when the process is attached to a console, which somewhat limits their usefulness.

Original answer:

While the only other answer here is succinct and accurate, it lacks detail on why there isn't signal support on Windows.

First off, signals are a rather limited and outdated way of communicating with a process. There are many more richer ways to inform a process that it needs to drop what it is doing and do something else. Even on POSIX platforms, signal handlers are intended to be VERY lightweight - code in signal handlers has to be ready/capable of handling multiple signals arriving at the same time.

PHP allows for signal handlers via pcntl_signal() with a significant number of caveats. Before they can be used, the code has to adjust the number of "ticks" that pass before PHP will pass a signal that arrived onto a handler. A tick is the number of instructions that Zend (the core of PHP) will execute before checking the signal handler status and running the necessary callbacks. It's basically a busy loop within the main execution loop. As such, adjusting ticks will dramatically slow down the process if the per-tick recommendation of 1 is followed. The comments on the function suggest a tick value of 100 is sufficient on most systems. The easiest way to understand how the handler works is that there is an actual signal handler behind the scenes that collects signal information, which PHP occasionally queries to see if the handler was called, which signal was sent, etc. - if so, then the information is passed along to a callback in userland (i.e your code). It's not real signal handling and never will be due to the dangers and difficulties that real signal handling presents.

The second problem is that, even with the pseudo-signal handler support that pcntl_signal() provides, PHP can lose information about signals that occurred. If the multiple signal scenario happens, the script will not be notified that some signal happened multiple times. The larger the tick value, the more likely this can happen, especially on a busy system.

Windows, for the most part, doesn't really use signals. There is the SetConsoleCtrlHandler() function which exists to capture Ctrl+C and Ctrl+Break and is roughly equivalent to SIGINT. The downsides are that there has to be a console attached to the process for it to work and can't be sent by other processes. The TerminateProcess() function is equivalent to SIGKILL, which can't be blocked/handled under other OSes and the SIGKILL signal doesn't actually arrive at the target process. Other than those two functions/signals, there's very little in common. Ultimately, Windows is a very different beast under the hood.

The only reason to look at signals is for some sort of long-running PHP process - a task that everyone seems to say that the language isn't suitable for (I completely disagree, but that's a different discussion). As I learned about the limitations of signal support in PHP even under POSIX OSes, I decided that they weren't really the answer to my situation. The correct solution is to ignore signals altogether. For SIGINT, command-line scripts should be written to handle the scenario of premature termination - that is, they should be idempotent. In the world of PHP, signals are largely irrelevant as there are other, more flexible, and richer solutions including named mutexes/events, sockets, files, named pipes, shared memory, Service Manager, etc.


PHP doesn't support signal handling on Windows. Sorry.