How to Build a Pure PHP Timer with PCNTL and Signals
This article explains how to implement a pure‑PHP timer using CLI mode, the PCNTL extension, and SIGALRM signals, covering basic concepts, task storage structures, the Timer class implementation, example usage, and practical considerations for long‑running services.
Introduction
Timer tasks are common in web applications. Traditional solutions use crontab with shell scripts or rely on ignore_user_abort() and set_time_limit(), which have limitations. This guide shows how to create a pure PHP timer that runs independently of the browser.
Basic Knowledge
CLI: PHP command‑line mode, distinct from the typical FPM web mode.
Process: The basic execution unit with its own memory space and control block.
Inter‑process Communication (IPC): Mechanisms such as pipes, shared memory, signals, message queues, and sockets enable data exchange between processes.
PCNTL extension: Provides process control functions like pcntl_alarm().
Implementation Principle
Tasks are stored in a three‑dimensional array indexed by timestamps. Each entry contains the execution interval, callback function, arguments, and a persistence flag.
array(
'1438156396' => array(
array(1, array('Class','Func'), array(), true),
)
);
// 1438156396 is the timestamp; the inner array represents interval, callback, arguments, persistence.The timer uses a signal (SIGALRM) sent every second. The signal handler iterates over the task array, executes due tasks via callbacks, removes one‑time jobs, and re‑schedules persistent jobs.
Timer Class Code
<?php
/**
* Timer
*/
class Timer {
// Store all scheduled tasks
public static $task = array();
// Interval in seconds
public static $time = 1;
/**
* Start the service
* @param int $time
*/
public static function run($time = null) {
if ($time) {
self::$time = $time;
}
self::installHandler();
pcntl_alarm(1);
}
/** Register signal handler */
public static function installHandler() {
pcntl_signal(SIGALRM, array('Timer','signalHandler'));
}
/** Signal handler */
public static function signalHandler() {
self::task();
// Schedule next alarm
pcntl_alarm(self::$time);
}
/** Execute callbacks */
public static function task() {
if (empty(self::$task)) { return; }
foreach (self::$task as $time => $arr) {
$current = time();
foreach ($arr as $k => $job) {
$func = $job['func']; // callback
$argv = $job['argv']; // arguments
$interval = $job['interval'];
$persist = $job['persist'];
if ($current == $time) {
call_user_fun_array($func, $argv);
unset(self::$task[$time][$k]);
}
if ($persist) {
self::$task[$current+$interval][] = $job;
}
}
if (empty(self::$task[$time])) {
unset(self::$task[$time]);
}
}
}
/** Add a task */
public static function add($interval, $func, $argv = array(), $persist = false) {
if (is_null($interval)) { return; }
$time = time() + $interval;
self::$task[$time][] = array('func'=>$func, 'argv'=>$argv, 'interval'=>$interval, 'persist'=>$persist);
}
/** Delete all tasks */
public function dellAll() {
self::$task = array();
}
}
?>Callback Example
<?php
class DoJob {
public function job($param = array()) {
$time = time();
echo "Time: {$time}, Func: ".get_class()."::".__FUNCTION__ ."(".json_encode($param).")
";
}
}
?>Usage Scenario
<?php
require_once(__DIR__.'/Timer.php');
require_once(__DIR__.'/DoJob.php');
Timer::dellAll();
Timer::add(1, array('DoJob','job'), array(), true); // persistent job
Timer::add(3, array('DoJob','job'), array('a'=>1), false); // one‑time job
echo "Time start: ".time()."
";
Timer::run();
while (1) {
sleep(1);
pcntl_signal_dispatch();
}
?>The script registers two jobs, starts the timer, and enters an infinite loop that dispatches signals. The persistent job runs repeatedly, while the non‑persistent job runs only once.
Conclusion
Before receiving a signal, the process must stay alive; a continuously true loop is used here. In production, such a loop would be part of a long‑running service (e.g., handling I/O or socket connections). PHP timers operate with a granularity of one second, which is sufficient for most scheduling needs.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
21CTO
21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
