protect

(PHP 8.6+, True Async 1.0)

protect() — Ejecuta un closure en modo no cancelable. La cancelación de la corrutina se difiere hasta que el closure se complete.

Descripción

protect(\Closure $closure): mixed

Mientras $closure se está ejecutando, la corrutina se marca como protegida. Si llega una solicitud de cancelación durante este tiempo, AsyncCancellation se lanzará solo después de que el closure termine.

Parámetros

closure Un closure a ejecutar sin interrupción por cancelación.

Valores de retorno

Devuelve el valor retornado por el closure.

Ejemplos

Ejemplo #1 Proteger una transacción

<?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;
});

// Si la corrutina fue cancelada durante protect(),
// AsyncCancellation se lanzará aquí — después de commit()
?>

Ejemplo #2 Proteger escritura de archivos

<?php
use function Async\protect;

protect(function() {
    $fp = fopen('data.json', 'w');
    fwrite($fp, json_encode($data));
    fclose($fp);
});
?>

Ejemplo #3 Obtener un resultado

<?php
use function Async\protect;

$cached = protect(function() use ($cache, $key) {
    $value = computeExpensiveResult();
    $cache->set($key, $value);
    return $value;
});
?>

Ejemplo #4 Cancelación diferida y diagnóstico

Durante protect(), la cancelación se guarda pero no se aplica. Esto se puede verificar mediante métodos de la corrutina:

<?php
use function Async\spawn;
use function Async\protect;
use function Async\current_coroutine;

$coroutine = spawn(function() {
    protect(function() {
        $me = current_coroutine();

        // Dentro de protect() después de cancel():
        echo $me->isCancellationRequested() ? "true" : "false"; // true
        echo "\n";
        echo $me->isCancelled() ? "true" : "false";             // false
        echo "\n";

        suspend();
        echo "Operación protegida completada\n";
    });

    // AsyncCancellation se lanza aquí — después de protect()
    echo "Este código no se ejecutará\n";
});

suspend(); // Dejar que la corrutina entre en protect()
$coroutine->cancel();
suspend(); // Dejar que protect() termine

echo $coroutine->isCancelled() ? "true" : "false"; // true
?>

Notas

Nota: Si la cancelación ocurrió durante protect(), AsyncCancellation se lanzará inmediatamente después de que el closure retorne — el valor de retorno de protect() se perderá en este caso.

Nota: protect() no hace el closure atómico — otras corrutinas pueden ejecutarse durante las operaciones de E/S dentro de él. protect() solo garantiza que la cancelación no interrumpirá la ejecución.

Ver también