PHP code example of rcalicdan / defer

1. Go to this page and download the library: Download rcalicdan/defer library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

rcalicdan / defer example snippets


use Rcalicdan\Defer\Defer;

function processFile($filename) {
    $file = fopen($filename, 'r');
    
    // Defer cleanup - executes when function ends
    $defer = Defer::scope();
    $defer->task(fn() => fclose($file));
    
    // Your file processing logic here
    $data = fread($file, 1024);
    
    // File automatically closed when function returns
    return $data;
}

use Rcalicdan\Defer\Defer;

function databaseTransaction() {
    $pdo = new PDO($dsn, $user, $pass);
    $pdo->beginTransaction();
    
    $defer = Defer::scope();
    $defer->task(fn() => $pdo->rollback()); // Safety rollback
    
    // Perform operations
    $stmt = $pdo->prepare("INSERT INTO users (name) VALUES (?)");
    $stmt->execute(['John']);
    
    $pdo->commit();
    // Defer cleanup executes here (though rollback is harmless after commit)
}

$defer = Defer::scope()
    ->task(fn() => fclose($file))
    ->task(fn() => unlink($tempFile))
    ->task(fn() => echo "Cleanup completed\n");

// Execution order: echo message, unlink file, close file (LIFO)

function processMultipleFiles(array $filenames) {
    $defer = Defer::scope();
    $handles = [];
    
    foreach ($filenames as $filename) {
        $handle = fopen($filename, 'r');
        $handles[] = $handle;
        
        // Each file gets its own cleanup defer
        $defer->task(fn() => fclose($handle));
    }
    
    // Process all files
    foreach ($handles as $handle) {
        // ... process file
    }
    
    // All files automatically closed when function ends (LIFO order)
}

use Rcalicdan\Defer\Defer;

Defer::global(function() {
    echo "First registered\n";
});

Defer::global(function() {
    echo "Second registered\n";  
});

Defer::global(function() {
    echo "Third registered\n";
});

// Output on shutdown (LIFO order):
// Third registered
// Second registered  
// First registered

Defer::global(fn() => echo "1. Final cleanup completed\n");
Defer::global(fn() => close_database_connections());
Defer::global(fn() => cleanup_temp_files());
Defer::global(fn() => echo "4. Starting cleanup sequence...\n");

$app = new Application();

Defer::global(fn() => $app->saveState());

// Opt in once, early in your entry point
Defer::enableSignals();

Defer::global(function() {
    file_put_contents('/tmp/shutdown.log', 'Clean shutdown: ' . date('Y-m-d H:i:s'));
});

// Your long-running process
while (true) {
    // ... do work
    sleep(1);
}

// Without enableSignals(): cleanup runs on normal exit only
// With enableSignals(): cleanup also runs on Ctrl+C, SIGTERM, SIGHUP, etc.

use Rcalicdan\Defer\Defer;

function handleRequest($request) {
    $response = processRequest($request);
    
    // Background tasks execute in FIFO order after response is sent
    Defer::terminate(function() use ($request) {
        logAnalytics($request->getUri(), $request->getUserAgent());
    });
    
    Defer::terminate(function() use ($request) {
        sendWelcomeEmail($request->get('email'));
    });
    
    return $response;
}

// Only runs on successful responses (2xx, 3xx)
Defer::terminate(fn() => incrementSuccessCounter());

// Always runs, regardless of status code
Defer::terminate(function() {
    logRequestCompletion();
}, always: true);

// Function-scoped - manual execution in LIFO order
$defer = Defer::scope();
$defer->task(fn() => echo "Second\n");
$defer->task(fn() => echo "First\n");
$defer->executeAll();

// Global - manual execution in LIFO order
Defer::global(fn() => echo "Global cleanup\n");
Defer::getHandler()->executeAll();

// Terminate - manual execution in FIFO order
Defer::terminate(fn() => echo "First task\n");
Defer::terminate(fn() => echo "Second task\n");
Defer::getHandler()->executeTerminate();

// Check pending defer count
$defer = Defer::scope();
$defer->task(fn() => cleanup1());
$defer->task(fn() => cleanup2());
echo $defer->count(); // 2

// Check whether signal handling is active
var_dump(Defer::signalsEnabled()); // bool(false) by default

// Inspect signal handling capabilities
$info = Defer::getHandler()->getSignalHandlingInfo();
print_r($info);

// Run the built-in capability test (outputs platform/method details)
Defer::getHandler()->testSignalHandling();

$info = Defer::getHandler()->getHandler()->getEnvironmentInfo();

if ($info['fastcgi'] && $info['fastcgi_finish_request']) {
    echo "✅ Optimal terminate defer support available\n";
} else {
    echo "⚠️ Using fallback terminate handling\n";
}

$defer = Defer::scope()
    ->task(function() {
        throw new Exception("This won't stop other defers");
    })
    ->task(function() {
        echo "This will still execute\n";
    });

// Exception is logged via error_log(), execution continues in LIFO order

function transferFunds($fromAccount, $toAccount, $amount) {
    $pdo = new PDO($dsn, $user, $pass);
    $pdo->beginTransaction();
    
    $defer = Defer::scope()
        ->task(fn() => auditLog("Transaction attempt completed")) // Runs first (LIFO)
        ->task(fn() => $pdo->rollback());                        // Runs second - safety net
    
    $stmt = $pdo->prepare("UPDATE accounts SET balance = balance - ? WHERE id = ?");
    $stmt->execute([$amount, $fromAccount]);
    
    $stmt = $pdo->prepare("UPDATE accounts SET balance = balance + ? WHERE id = ?");
    $stmt->execute([$amount, $toAccount]);
    
    $pdo->commit();
    // LIFO: audit log, then rollback (harmless after commit)
}

function processUploadedImage($uploadedFile) {
    $tempPath = '/tmp/' . uniqid() . '.tmp';
    move_uploaded_file($uploadedFile['tmp_name'], $tempPath);
    
    $defer = Defer::scope()
        ->task(fn() => echo "Processing completed\n") // Runs first (LIFO)
        ->task(fn() => unlink($tempPath));             // Runs second - cleanup
    
    $image = imagecreatefromjpeg($tempPath);
    $resized = imagescale($image, 800, 600);
    
    $finalPath = '/uploads/' . $uploadedFile['name'];
    imagejpeg($resized, $finalPath);
    
    imagedestroy($image);
    imagedestroy($resized);
    
    return $finalPath;
}

function processOrder($orderData) {
    $order = createOrder($orderData);
    
    // Background tasks execute in FIFO order after response is sent
    Defer::terminate(function() use ($order) {
        updateInventory($order);        // Runs first
    });
    
    Defer::terminate(function() use ($order) {
        sendConfirmationEmail($order);  // Runs second
    });
    
    Defer::terminate(function() use ($order) {
        logOrderCompletion($order);     // Runs third
    });
    
    return ['success' => true, 'order_id' => $order->id];
}

// Opt in to signal handling for graceful interruption
Defer::enableSignals();

// Register cleanup in LIFO order
Defer::global(fn() => echo "Shutdown complete\n");
Defer::global(function() {
    file_put_contents('/var/log/worker.log', "Worker stopped: " . date('c') . "\n", FILE_APPEND);
});
Defer::global(fn() => echo "Starting shutdown sequence...\n");

while (true) {
    $job = getNextJob();
    if (!$job) {
        sleep(1);
        continue;
    }
    
    processJob($job);
}

// LIFO cleanup runs on normal exit AND on Ctrl+C / SIGTERM (because enableSignals() was called)