Search by

lumetas / luper

lumetas

Package info

github.com/Lumetas/Luper

pkg:composer/lumetas/luper

Statistics

Installs: 28

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

1.3.4.5 2026-08-31 11:31 UTC

This package is not auto-updated.

Last update: 2026-09-14 11:39:39 UTC


README

Введение

О библиотеке

Luper - это легковесная библиотека для асинхронного программирования в PHP, предоставляющая механизмы для работы с параллельными задачами, таймерами и файберами.

Ключевые возможности

Асинхронное выполнение PHP-функций через отдельные процессы

Управление задачами с помощью Fibers (доступно с PHP 8.1)

Таймеры и периодические задачи

Неблокирующее ожидание результатов

Простой и интуитивно понятный API

Установка

Требования

PHP >= 8.1

Composer

composer require lumetas/luper

Async - Асинхронное выполнение

Класс для запуска PHP-функций в отдельных процессах.

Создание асинхронной задачи

<?php
use Luper\Async;

// Создание асинхронной функции из файла
$asyncFunction = Async::create(__DIR__.'/my_function.php');

Запуск и ожидание результата

<?php
// Запуск с аргументами
$promise = $asyncFunction("arg1", "arg2");

// Проверка завершения
if ($promise->isCompleted()) {
	$result = $promise->getResult();
}

// Получение ошибки (если есть)
$error = $promise->getError();

AsyncPromise - обмен данными с дочерним процессом

Промис, возвращаемый асинхронной функцией, поддерживает двусторонний обмен данными между родительским и дочерним процессами на всём протяжении выполнения.

Родитель -> Дочерний процесс

<?php
$promise = $asyncFunction(...);

// Неблокирующая отправка данных в дочерний процесс
$promise->sendData('hello');
$promise->sendData(['key' => 'value']);

Внутри дочерней функции данные принимаются через luper_get_data().

Дочерний процесс -> Родитель

<?php
return function() {
    // Отправка данных родителю
    luper_send_data('progress: 50%');
    luper_send_data(['status' => 'working']);

    return 'final result';
};

Родитель получает их через $promise->getData().

Методы

  • $promise->sendData($data) - неблокирующая отправка данных в дочерний процесс. Выполнение не останавливается даже при переполнении канала (данные буферизуются).
  • $promise->getData(bool $nonBlocking = false) - получить данные от дочернего процесса. По умолчанию ожидает появления данных (внутри файбера приостанавливает его). Если передать true - вернёт null сразу, когда готовых данных нет.
  • luper_get_data(bool $nonBlocking = false) - получить данные, отправленные через $promise->sendData(). Семантика та же, что у getData.
  • luper_send_data($data) - отправить данные родителю; они попадают в очередь $promise->getData().

Пример обмена

<?php
// worker.php - дочерняя функция
return function(int $count) {
    for ($i = 0; $i < $count; $i++) {
        luper_send_data("progress: $i/$count");
        usleep(100000);
    }
    $command = luper_get_data(); // ждём команду от родителя
    return $command;
};
<?php
$promise = Async::create(__DIR__ . '/worker.php')(3);

// Читаем промежуточные данные (блокирует, пока данных нет)
var_dump($promise->getData()); // "progress: 0/3"
var_dump($promise->getData()); // "progress: 1/3"

// Неблокирующая проверка: данных ещё нет -> null
var_dump($promise->getData(true));

$promise->sendData('СТАРТ');

var_dump($promise->await()); // "СТАРТ"

Loop - Цикл событий

Центральный класс для управления асинхронными задачами.

Создание экземпляра

<?php
use Luper\Loop;

// Создание нового цикла
$loop = new Loop();

// Или использование синглтона
$loop = Loop::make();

Добавление задач

<?php
$loop->addTask(function () {
// Ваш код здесь
	echo "Выполнено в файбере!";
});

Таймеры

<?php
// Одноразовый таймер
$timerId = $loop->addTimer(2.5, function () {
	echo "Выполнится через 2.5 секунды";
});

// Периодический таймер
$repeatingTimerId = $loop->addTimer(1.0, function () {
	echo "Выполняется каждую секунду";
}, true);

// Отмена таймера
$loop->clearTimer($timerId);

Управление выполнением

<?php
// Запуск цикла
$loop->run();

// Остановка цикла
$loop->stop();

// Приостановка выполнения в файбере
Loop::suspend();

// Задержка выполнения
$loop->sleep(0.5); // sleep на 0.5 секунды

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

Базовый пример

<?php
require_once "vendor/autoload.php";
use Luper\Async;
use Luper\Loop;

$startTime = time();

function createRequests($count) {
	$loop = new Loop();
	$results = [];

	for($i = 0; $i < $count; $i++) {
		$loop->addTask(function () use (&$loop, &$results) {
			$asyncFunc = Async::create(__DIR__.'/requestFunc.php');
			$promise = $asyncFunc("https://google.com");

			while ($promise->getResult() === null) {
				$loop->suspend();
		 	}

			$results[] = strlen($promise->getResult()['result']);
		});
	}

	$loop->run();
	return $results;
}

var_dump(createRequests(10));
echo "\nИтоговое время: " . (time() - $startTime);

Пример файла requestFunc.php

<?php
// Файл должен возвращать callable функцию
return function($url) {
// Имитация HTTP-запроса
sleep(1); // Длительная операция
return [
	'status' => 200,
	'content' => file_get_contents($url),
	'headers' => []
];
};

Практические примеры

Параллельные HTTP-запросы

<?php
use Luper\Async;
use Luper\Loop;

function fetchMultipleUrls(array $urls) {
	$loop = new Loop();
	$responses = [];

	foreach ($urls as $index => $url) {
		$loop->addTask(function () use ($url, $index, &$responses, $loop) {
			$fetch = Async::create(__DIR__.'/fetch_url.php');
			$promise = $fetch($url);

			while (!$promise->isCompleted()) {
				Loop::suspend();
			}

			$responses[$index] = $promise->getResult();
		});
	}

	$loop->run();
	return $responses;
}

Периодические задачи

<?php
use Luper\Loop;

$loop = new Loop();

// Обновление кэша каждые 30 секунд
$loop->addTimer(30, function () {
	updateCache();
}, true);

// Одноразовая задача через 5 секунд
$loop->addTimer(5, function () {
	sendNotification();
});

$loop->run();

closure

<?php
require __DIR__ . '/vendor/autoload.php';
use function Luper\async;
$var = 123;
$asyncFunction = async(function($a, $b) use ($var) { 
	sleep(1);
	return $a + $b + $var; 
});	

$promise = $asyncFunction(1, 2);
$result = $promise->await();
echo $result;

Pull и PullMax

Это два класса представляющие собой обёртку над функционалом. Чтобы было проще обрабатывать данные Пример:

<?php
use Luper\Pull;

$items = [];
for($i = 0; count($items) < 50; $i ++) {$items[] = $i;}

$pullSize = 10;
// Создаем пул с максимум 3 параллельными процессами
$pull = new Pull($pullSize, __DIR__.'/proc.php');

// Добавляем задачи
foreach ($items as $item) {
    $pull->add($item, 'дополнительный_аргумент');
}

// Запускаем обработку
$results = $pull->run();

И аналогичный пример для PullMax:

<?php
use Luper\PullMax;

$items = [];
for($i = 0; count($items) < 50; $i ++) {$items[] = $i;}

$pullSize = 10;

$pull = new PullMax(__DIR__.'/proc.php');

// Добавляем задачи
foreach ($items as $item) {
    $pull->add($item, 'дополнительный_аргумент');
}

// Запускаем обработку 
$results = $pull->run();

Класс Pull Позволяет легко обрабатывать данные, указав максимальное количество одновременно запущенных процессов. PullMax Будет пытаться запустить столько паралельных процессов сколько сможет

await

Асинхронная функция при выполнении возвращает промис, у которого есть метод await, он возвращает результат работы функции, если функция ещё не выполнена метод останавливает поток выполнения дожидаясь завершения, в случае если метод был вызван внутри файбера, то файбер будет приостанавливаться до завершения выполнения функции. Поэтому метод крайне полезно использовать внутри EventLoop, пример:

<?php
use Luper\{Loop, Async};
$func = Async::create(__DIR__.'/proc.php');
$loop = new Loop;
$results = [];
foreach ($elems as $elem) {
	$loop->addTask(function () use ($func, $loop, &$results) {
		$results[] = $func(1, 2)->await();
	});
}
$loop->run();
var_dump($results);

Best Practices

Структура асинхронных функций

  • Каждая асинхронная функция должна быть в отдельном файле
  • Файл должен возвращать callable
  • Используйте обработку ошибок внутри функций

Управление памятью

  • Используйте ссылки для больших данных чтобы избежать копирования

Производительность

  • Не создавайте чрезмерное количество параллельных процессов

Ограничения

  • Ограничения процессов PHP (память, время выполнения)
  • Требует аккуратного управления ресурсами

Заключение

Luper предоставляет простой и эффективный способ асинхронного программирования в PHP, особенно полезный для I/O-операций и параллельной обработки задач.