Речь пойдет не о выполнении кода в потоке одного скрипта с таймаутами, а о задаче очередности некоего стека php кода в рамках некоего проекта с исполнением по таймаутам. Предположим есть некая строка в бд, которой необходимо проставить некий статус на заданное количество секунд и затем вернуть статусы на место. Напишем класс с функциями установки кода в стек, удаления кода из стека и выполнения кода по истечению таймаута. Код будем записывать в json файл, ключами массива сделаем microtime меточку и будем выполнять через eval вышедший по таймауту код:
<?php
class Phpstack
{
public static $filename = 'phpstack.json';
public static function set($code, $time)
{
$file = new SplFileObject(self::$filename, 'a+b');
$file->flock(LOCK_EX);
$file->rewind();
$data = $file->fread($file->getSize());
$data = $data ?: '[]';
$arr = json_decode($data, true);
$key = microtime(true) + $time;
while (isset($arr[$key])) {
$key = $key + 0.0001;
}
$key = (string)$key;
$arr[$key] = $code;
$file->ftruncate(0);
$file->fwrite(json_encode($arr));
$file->flock(LOCK_UN);
return $key;
}
public static function remove($key)
{
$file = new SplFileObject(self::$filename, 'a+b');
$file->flock(LOCK_EX);
$file->rewind();
$data = $file->fread($file->getSize());
$data = $data ?: '[]';
$arr = json_decode($data, true);
if (isset($arr[$key])) {
unset($arr[$key]);
}
$file->ftruncate(0);
$file->fwrite(json_encode($arr));
$file->flock(LOCK_UN);
}
public static function execute()
{
global $mysqli;
$file = new SplFileObject(self::$filename, 'a+b');
$file->flock(LOCK_EX);
$file->rewind();
$data = $file->fread($file->getSize());
$data = $data ?: '[]';
$arr = json_decode($data, true);
$exec = false;
foreach ($arr as $key => $value) {
if ($key <= microtime(true)) {
eval($value);
unset($arr[$key]);
$exec = true;
}
}
if ($exec) {
$file->ftruncate(0);
$file->fwrite(json_encode($arr));
}
$file->flock(LOCK_UN);
}
}
Функция set принимает в аргументах строку кода и таймаут в секундах, через который он должен быть исполнен. Возвращает установленный ключ — для того чтобы код можно было в случае чего удалить без исполнения по данному ключу функцией remove. Функция execute исполняет вышедший из заданного таймаута стек кодов. Блокировкой файла мы исключаем возможность повторного исполнения одного и того же кода.
Использование, добавляем код в стек на 122 секунды:
$mysqli->query("UPDATE `questions` SET `section` = 12, `app_status` = 14 WHERE `id` = $id");
Phpstack::set('$mysqli->query("UPDATE `questions` SET `section` = 7, `app_status` = 2 WHERE `id` = ' . $id . '");', 122);
А в индексном файле проекта пропишем исполнение:
Phpstack::execute();
глобальную $mysqli добавил потому что она требуется в текущем проекте для запроса в бд, у вас же её может не быть.
UPD: обновил код и добавил функцию executeKey($key)
Функция нужна для того, чтобы вызвать по ключу(ключ возвращается функцией set) код прямо здесь и сейчас(без учета таймаута). Т.е. функция remove просто удаляет заданный код по ключу, без выполнения, а функция executeKey выполняет и удаляет код.
<?php
class Phpstack
{
public static $filename = 'phpstack.json';
public static function set($code, $time)
{
$file = new SplFileObject(self::$filename, 'a+b');
$file->flock(LOCK_EX);
$file->rewind();
$data = $file->fread($file->getSize());
$data = $data ?: '[]';
$arr = json_decode($data, true);
$key = microtime(true) + $time;
while (isset($arr[$key])) {
$key = $key + 0.0001;
}
$key = (string)$key;
$arr[$key] = $code;
$file->ftruncate(0);
$file->fwrite(json_encode($arr));
$file->flock(LOCK_UN);
return $key;
}
public static function remove($key)
{
$file = new SplFileObject(self::$filename, 'a+b');
$file->flock(LOCK_EX);
$file->rewind();
$data = $file->fread($file->getSize());
$data = $data ?: '[]';
$arr = json_decode($data, true);
if (isset($arr[$key])) {
unset($arr[$key]);
}
$file->ftruncate(0);
$file->fwrite(json_encode($arr));
$file->flock(LOCK_UN);
}
public static function execute()
{
global $mysqli;
$file = new SplFileObject(self::$filename, 'a+b');
$file->flock(LOCK_EX);
$file->rewind();
$data = $file->fread($file->getSize());
$data = $data ?: '[]';
$arr = json_decode($data, true);
$exec = false;
foreach ($arr as $key => $value) {
if ($key <= microtime(true)) {
eval($value);
unset($arr[$key]);
$exec = true;
}
}
if ($exec) {
$file->ftruncate(0);
$file->fwrite(json_encode($arr));
}
$file->flock(LOCK_UN);
}
public static function executeKey($key) {
global $mysqli;
$file = new SplFileObject(self::$filename, 'a+b');
$file->flock(LOCK_EX);
$file->rewind();
$data = $file->fread($file->getSize());
$data = $data ?: '[]';
$arr = json_decode($data, true);
if (isset($arr[$key])) {
eval($arr[$key]);
unset($arr[$key]);
}
$file->ftruncate(0);
$file->fwrite(json_encode($arr));
$file->flock(LOCK_UN);
}
}