Remember that signal handlers are called immediately, so every time when your process receives registered signal blocking functions like sleep() and usleep() are interrupted (or more like ended) like it was their time to finish.
This is expected behaviour, but not mentioned in this documentation. Sleep interruption can be very unfortunate when for example you run a daemon that is supposed to execute some important task exactly every X seconds/minutes - this task could be called too early or too often and it would be hard to debug why it's happening exactly.
Simply remember that signal handlers might interfere with other parts of your code.
Here is example workaround ensuring that function gets executed every minute no matter how many times our loop gets interrupted by incoming signal (SIGUSR1 in this case).
<?php
pcntl_async_signals(TRUE);
pcntl_signal(SIGUSR1, function($signal) {
});
function everyMinute() {
}
$wait = 60;
$next = 0;
while (TRUE) {
$stamp = time();
do {
if ($stamp >= $next) { break; }
$diff = $next - $stamp;
sleep($diff);
$stamp = time();
} while ($stamp < $next);
everyMinute();
$next = $stamp + $wait;
sleep($wait);
}
?>
So in this infinite loop do {} while() calculates and adds missing sleep() to ensure that our everyMinute() function is not called too early. Both sleep() functions here are covered so everyMinute() will never be executed before it's time even if process receives multiple SIGUSR1 signals during it's runtime.