API Reference: Timer

Полный справочник по классу Timer для работы с таймерами и отложенным выполнением.

Класс Timer

namespace localzet;

class Timer

Класс для управления таймерами и отложенным выполнением задач.

Статические методы

add()

Добавление таймера.

public static function add(
    float $timeInterval,
    callable $func,
    ?array $args = [],
    bool $persistent = true
): int

Параметры:

  • $timeInterval - Интервал выполнения в секундах (float, >= 0)
  • $func - Callback функция для выполнения
  • $args - Массив аргументов для передачи в callback
  • $persistent - Повторяющийся таймер (true) или одноразовый (false)

Возвращает:

ID таймера (int) для последующего удаления.

Примеры:

// Повторяющийся таймер (каждую секунду)
$timerId = Timer::add(1.0, function() {
    echo "Tick\n";
});

// Одноразовый таймер (через 5 секунд)
$timerId = Timer::add(5.0, function($message) {
    echo $message . "\n";
}, ['Delayed message'], false);

// Таймер с несколькими аргументами
$timerId = Timer::add(2.0, function($name, $age) {
    echo "$name is $age years old\n";
}, ['John', 30], false);

del()

Удаление таймера.

public static function del(int $timerId): bool

Параметры:

  • $timerId - ID таймера для удаления

Возвращает:

true если таймер найден и удален, иначе false.

Пример:

$timerId = Timer::add(10.0, function() {
    echo "Это не выполнится\n";
});

// Удаление таймера до его выполнения
Timer::del($timerId);

delAll()

Удаление всех таймеров.

public static function delAll(): void

Описание:

Удаляет все активные таймеры. Полезно при остановке сервера.

Пример:

// Очистка всех таймеров
Timer::delAll();

repeat()

Создание повторяющегося таймера.

public static function repeat(
    float $timeInterval,
    callable $func,
    array $args = []
): int

Параметры:

  • $timeInterval - Интервал повторения в секундах
  • $func - Callback функция
  • $args - Аргументы для callback

Возвращает:

ID таймера.

Пример:

// Heartbeat каждые 30 секунд
$heartbeatId = Timer::repeat(30.0, function() use ($connection) {
    $connection->sendPing();
});

// Остановка heartbeat
Timer::del($heartbeatId);

delay()

Создание одноразового таймера (задержка).

public static function delay(
    float $timeInterval,
    callable $func,
    array $args = []
): int

Параметры:

  • $timeInterval - Задержка в секундах
  • $func - Callback функция
  • $args - Аргументы для callback

Возвращает:

ID таймера.

Пример:

// Выполнение через 3 секунды
Timer::delay(3.0, function($message) {
    echo $message . "\n";
}, ['Delayed execution']);

sleep()

Приостановка выполнения на указанное время (для корутин).

public static function sleep(float $delay): void

Параметры:

  • $delay - Время приостановки в секундах (>= 0)

Описание:

Асинхронная приостановка выполнения. Не блокирует обработку других запросов.

Примеры:

// В Fiber или корутине
use localzet\Timer;

// Правильно - асинхронная задержка
Timer::sleep(1.0); // Не блокирует процесс

// НЕПРАВИЛЬНО - блокирует весь процесс
sleep(1);

Пример использования:

$server->onMessage = function(TcpConnection $connection, $data) {
    // Асинхронная задержка перед ответом
    Timer::sleep(0.5);
    $connection->send('Delayed response');
};

init()

Инициализация таймера.

public static function init(?EventInterface $event = null): void

Параметры:

  • $event - EventInterface, цикл событий (опционально)

Описание:

Инициализирует систему таймеров. Вызывается автоматически при запуске сервера.

Пример:

// Ручная инициализация (обычно не требуется)
Timer::init(Server::getEventLoop());

Примеры использования

Пример 1: Таймаут для операции

$server->onMessage = function(TcpConnection $connection, $data) {
    // Установка таймаута
    $timeoutId = Timer::delay(10.0, function() use ($connection) {
        $connection->close('Operation timeout');
    });
    
    // Асинхронная операция
    performAsyncOperation(function($result) use ($connection, $timeoutId) {
        // Отмена таймаута при успешном завершении
        Timer::del($timeoutId);
        
        $connection->send($result);
    });
};

Пример 2: Heartbeat для соединений

$server->onConnect = function(TcpConnection $connection) {
    // Создание heartbeat таймера
    $connection->context->heartbeatTimer = Timer::repeat(30.0, function() use ($connection) {
        if (!$connection->sendPing()) {
            // Не удалось отправить - закрываем соединение
            Timer::del($connection->context->heartbeatTimer);
            $connection->close();
        }
    });
};

$server->onClose = function(TcpConnection $connection) {
    // Удаление heartbeat при закрытии
    if (isset($connection->context->heartbeatTimer)) {
        Timer::del($connection->context->heartbeatTimer);
    }
};

Пример 3: Периодическая очистка

// Очистка временных данных каждые 5 минут
Timer::repeat(300.0, function() {
    $now = time();
    
    // Удаление старых записей
    foreach ($temporaryData as $key => $data) {
        if ($data['expires'] < $now) {
            unset($temporaryData[$key]);
        }
    }
});

Пример 4: Отложенная отправка

$server->onMessage = function(TcpConnection $connection, $data) {
    // Отправка ответа с задержкой
    Timer::delay(1.0, function() use ($connection, $data) {
        $connection->send('Delayed: ' . $data);
    });
};

Пример 5: Ограничение частоты запросов

$requestCounts = [];

$server->onMessage = function(TcpConnection $connection, $data) {
    $ip = $connection->getRemoteIp();
    $now = time();
    
    // Инициализация счетчика
    if (!isset($requestCounts[$ip])) {
        $requestCounts[$ip] = ['count' => 0, 'resetTime' => $now + 1];
    }
    
    // Сброс счетчика каждую секунду
    if ($requestCounts[$ip]['resetTime'] <= $now) {
        $requestCounts[$ip] = ['count' => 0, 'resetTime' => $now + 1];
    }
    
    // Проверка лимита
    if (++$requestCounts[$ip]['count'] > 100) {
        $connection->close('Rate limit exceeded');
        return;
    }
    
    // Обработка запроса
    $connection->send('OK');
};

Пример 6: Автоматическое переподключение

function connectWithRetry($address, $maxRetries = 3) {
    $retryCount = 0;
    
    $tryConnect = function() use ($address, &$retryCount, $maxRetries, &$tryConnect) {
        $connection = new AsyncTcpConnection($address);
        
        $connection->onConnect = function() {
            echo "Connected successfully\n";
            $retryCount = 0; // Сброс счетчика
        };
        
        $connection->onClose = function() use (&$retryCount, $maxRetries, &$tryConnect) {
            if (++$retryCount <= $maxRetries) {
                echo "Reconnecting in 5 seconds... ($retryCount/$maxRetries)\n";
                Timer::delay(5.0, $tryConnect);
            } else {
                echo "Max retries reached\n";
            }
        };
        
        $connection->connect();
    };
    
    $tryConnect();
}

Лучшие практики

1. Всегда удаляйте таймеры при необходимости

// Плохо - утечка таймера
$server->onConnect = function($conn) {
    Timer::repeat(1.0, function() use ($conn) {
        // Таймер продолжит работать даже после закрытия соединения
    });
};

// Хорошо - удаление таймера
$server->onConnect = function($conn) {
    $conn->context->timerId = Timer::repeat(1.0, function() use ($conn) {
        // Логика
    });
};

$server->onClose = function($conn) {
    if (isset($conn->context->timerId)) {
        Timer::del($conn->context->timerId);
    }
};

2. Используйте Timer::sleep() вместо sleep()

// Плохо - блокирует весь процесс
sleep(1);

// Хорошо - асинхронная задержка
Timer::sleep(1.0);

3. Валидация параметров

// Всегда проверяйте параметры перед использованием
if ($delay < 0) {
    throw new InvalidArgumentException('Delay must be >= 0');
}

Timer::delay($delay, $callback);

Ограничения

  • Таймеры работают только в контексте Localzet Server
  • Минимальный интервал зависит от точности системного таймера (обычно ~1ms)
  • Максимальный интервал ограничен типом float в PHP