protect
(PHP 8.6+, True Async 1.0)
protect() — Выполняет замыкание в некансельируемом режиме. Отмена корутины откладывается до завершения замыкания.
Описание
protect(\Closure $closure): mixed
На время выполнения $closure корутина помечается как защищённая. Если в этот момент поступает запрос на отмену, CancellationError будет выброшен только после завершения замыкания.
Параметры
closure
Замыкание, которое нужно выполнить без прерывания отменой.
Возвращаемое значение
Возвращает значение, возвращённое замыканием.
Примеры
Пример #1 Защита транзакции
<?php
use function Async\protect;
$db->beginTransaction();
$result = protect(function() use ($db) {
$db->exec("UPDATE accounts SET balance = balance - 100 WHERE id = 1");
$db->exec("UPDATE accounts SET balance = balance + 100 WHERE id = 2");
$db->commit();
return true;
});
// Если корутина была отменена во время protect(),
// CancellationError будет выброшен здесь — после commit()
?>
Пример #2 Защита записи в файл
<?php
use function Async\protect;
protect(function() {
$fp = fopen('data.json', 'w');
fwrite($fp, json_encode($data));
fclose($fp);
});
?>
Пример #3 Получение результата
<?php
use function Async\protect;
$cached = protect(function() use ($cache, $key) {
$value = computeExpensiveResult();
$cache->set($key, $value);
return $value;
});
?>
Пример #4 Отложенная отмена и диагностика
Во время protect() отмена сохраняется, но не применяется. Это можно проверить через методы корутины:
<?php
use function Async\spawn;
use function Async\protect;
use function Async\current_coroutine;
$coroutine = spawn(function() {
protect(function() {
$me = current_coroutine();
// Внутри protect() после cancel():
echo $me->isCancellationRequested() ? "true" : "false"; // true
echo "\n";
echo $me->isCancelled() ? "true" : "false"; // false
echo "\n";
suspend();
echo "Защищённая операция завершена\n";
});
// CancellationError выбрасывается здесь — после protect()
echo "Этот код не выполнится\n";
});
suspend(); // Даём корутине войти в protect()
$coroutine->cancel();
suspend(); // Даём завершить protect()
echo $coroutine->isCancelled() ? "true" : "false"; // true
?>
isCancellationRequested()—trueсразу послеcancel(), даже внутриprotect()isCancelled()—falseпокаprotect()не завершится, затемtrue
Примечания
Примечание: Если отмена произошла во время
protect(),CancellationErrorбудет выброшен сразу после возврата из замыкания — результатprotect()в этом случае потеряется.
Примечание:
protect()не делает замыкание атомарным — другие корутины могут выполняться во время I/O-операций внутри него.protect()гарантирует только то, что отмена не прервёт выполнение.