Menu
Coddy logo textTech

Try, Catch, Finally

Part of the Object Oriented Programming section of Coddy's PHP journey — lesson 68 of 91.

Now that you know how to create and throw exceptions, you need to learn how to catch them. The try-catch-finally structure lets you handle exceptions gracefully instead of letting them crash your application.

Wrap code that might throw an exception in a try block, then handle the exception in a catch block:

<?php
class Calculator {
    public function divide(int $a, int $b): float {
        if ($b === 0) {
            throw new InvalidArgumentException("Cannot divide by zero");
        }
        return $a / $b;
    }
}

$calc = new Calculator();

try {
    echo $calc->divide(10, 0);
} catch (InvalidArgumentException $e) {
    echo "Error: " . $e->getMessage();
}

Output:

Error: Cannot divide by zero

You can catch different exception types with multiple catch blocks. PHP checks them in order, so place more specific exceptions first:

<?php
try {
    // risky code
} catch (InvalidArgumentException $e) {
    echo "Bad input: " . $e->getMessage();
} catch (Exception $e) {
    echo "Something went wrong: " . $e->getMessage();
}

The finally block runs regardless of whether an exception was thrown or caught. It's perfect for cleanup tasks like closing connections:

<?php
try {
    echo "Attempting operation\n";
    throw new Exception("Failed");
} catch (Exception $e) {
    echo "Caught: " . $e->getMessage() . "\n";
} finally {
    echo "Cleanup complete";
}

Output:

Attempting operation
Caught: Failed
Cleanup complete

The finally block executes even if you return from within the try or catch blocks, making it reliable for essential cleanup operations.

challenge icon

Challenge

Easy

Let's build a file processing system that demonstrates how try-catch-finally works together to handle errors gracefully while ensuring cleanup always happens.

You'll organize your code across three files:

  • FileException.php — Create a custom FileException class that extends Exception. This will represent file-related errors in your system.
  • FileProcessor.php — Create a FileProcessor class that simulates file operations. Include the FileException file. Your class should have:
    • A private boolean property $isOpen initialized to false
    • A method open(string $filename): void that sets $isOpen to true and prints "Opening: [filename]". If the filename is "invalid.txt", throw a FileException with the message "Cannot open file"
    • A method process(): void that prints "Processing file...". If $isOpen is false, throw a RuntimeException with the message "File not open"
    • A method close(): void that sets $isOpen to false and prints "File closed"
    • A method isOpen(): bool that returns the current state
  • main.php — Include the FileProcessor file. You'll receive one input: a filename.

    Create a FileProcessor and use a try-catch-finally structure to:

    • In the try block: call open() with the filename, then call process()
    • Catch FileException first and print "File error: [message]"
    • Catch RuntimeException and print "Runtime error: [message]"
    • In the finally block: check if the file is open using isOpen(), and if so, call close(). Then print "Cleanup complete"

The finally block ensures that cleanup happens whether the operations succeed or fail. This pattern is essential for managing resources like files, database connections, or network sockets where cleanup must occur regardless of what happens during processing.

Cheat sheet

Use try-catch-finally to handle exceptions gracefully and ensure cleanup code always runs:

<?php
try {
    // code that might throw an exception
} catch (ExceptionType $e) {
    // handle the exception
    echo $e->getMessage();
}

Catch multiple exception types with separate catch blocks. Place more specific exceptions first:

<?php
try {
    // risky code
} catch (InvalidArgumentException $e) {
    echo "Bad input: " . $e->getMessage();
} catch (Exception $e) {
    echo "Something went wrong: " . $e->getMessage();
}

The finally block executes regardless of whether an exception was thrown or caught, making it ideal for cleanup operations:

<?php
try {
    // attempt operation
} catch (Exception $e) {
    // handle error
} finally {
    // cleanup code runs always
}

Try it yourself

<?php
require_once 'FileProcessor.php';

// Read input
$filename = trim(fgets(STDIN));

// TODO: Create a FileProcessor instance

// TODO: Use try-catch-finally structure:
// - In try block: call open() with the filename, then call process()
// - Catch FileException first and print "File error: [message]"
// - Catch RuntimeException and print "Runtime error: [message]"
// - In finally block: check if file is open using isOpen(), if so call close()
//   Then print "Cleanup complete"

?>
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming