Menu
Coddy logo textTech

Try, Catch, Finally

CoddyのPHPジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 68/91。

例外を作成してスローする方法を理解したところで、それらをキャッチする方法を学ぶ必要があります。try-catch-finally 構造を使用すると、アプリケーションをクラッシュさせることなく、例外を適切に処理できます。

例外をスローする可能性のあるコードを try ブロックで囲み、次にその例外を catch ブロックで処理します:

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

出力:

Error: Cannot divide by zero

複数のcatchブロックを使用して、異なる例外タイプをキャッチできます。PHPはこれらを順番にチェックするため、より具体的な例外を最初に配置してください。

<?php
try {
    // リスクのあるコード
} catch (InvalidArgumentException $e) {
    echo "Bad input: " . $e->getMessage();
} catch (Exception $e) {
    echo "Something went wrong: " . $e->getMessage();
}

finally ブロックは、例外がスローされたかキャッチされたかに関わらず実行されます。接続のクローズなどのクリーンアップタスクに最適です:

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

出力:

Attempting operation
Caught: Failed
Cleanup complete

finally ブロックは、try または catch ブロック内から return した場合でも実行されるため、不可欠なクリーンアップ操作において信頼性が高くなります。

challenge icon

チャレンジ

簡単

エラーを適切に処理しながら、常にクリーンアップが行われるようにする try-catch-finally の仕組みを実証するファイル処理システムを構築しましょう。

コードは3つのファイルに分けて構成します:

  • FileException.phpException を継承したカスタム FileException クラスを作成します。これは、システム内のファイル関連のエラーを表します。
  • FileProcessor.php — ファイル操作をシミュレートする FileProcessor クラスを作成します。FileException ファイルをインクルードしてください。クラスには以下を含める必要があります:
    • false で初期化された private な boolean プロパティ $isOpen
    • $isOpentrue に設定し、"Opening: [filename]" と出力するメソッド open(string $filename): void。もし filename が "invalid.txt" の場合は、メッセージ "Cannot open file" を持つ FileException をスローします。
    • "Processing file..." と出力するメソッド process(): void。もし $isOpenfalse の場合は、メッセージ "File not open" を持つ RuntimeException をスローします。
    • $isOpenfalse に設定し、"File closed" と出力するメソッド close(): void
    • 現在の状態を返すメソッド isOpen(): bool
  • main.php — FileProcessor ファイルをインクルードします。1つの入力(ファイル名)を受け取ります。

    FileProcessor を作成し、try-catch-finally 構造を使用して以下を行います:

    • try ブロック内:ファイル名で open() を呼び出し、次に process() を呼び出します。
    • 最初に FileException をキャッチし、"File error: [message]" と出力します。
    • RuntimeException をキャッチし、"Runtime error: [message]" と出力します。
    • finally ブロック内:isOpen() を使用してファイルが開いているか確認し、開いている場合は close() を呼び出します。その後、"Cleanup complete" と出力します。

finally ブロックは、操作が成功したか失敗したかにかかわらず、クリーンアップが確実に行われるようにします。このパターンは、処理中に何が起こってもクリーンアップが必要なファイル、データベース接続、ネットワークソケットなどのリソースを管理するために不可欠です。

チートシート

例外を適切に処理し、クリーンアップコードが常に実行されるようにするには、try-catch-finally を使用します:

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

複数の例外タイプを個別の catch ブロックでキャッチします。より具体的な例外を先に記述してください:

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

finally ブロックは、例外がスローされたかキャッチされたかに関わらず実行されるため、クリーンアップ操作に最適です:

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

自分で試してみよう

<?php
require_once 'FileProcessor.php';

// 入力を読み込む
$filename = trim(fgets(STDIN));

// TODO: FileProcessor インスタンスを作成する

// TODO: try-catch-finally 構造を使用する:
// - try ブロック内: filename を指定して open() を呼び出し、次に process() を呼び出す
// - 最初に FileException をキャッチし、"File error: [message]" と出力する
// - 次に RuntimeException をキャッチし、"Runtime error: [message]" と出力する
// - finally ブロック内: isOpen() を使用してファイルが開いているか確認し、開いている場合は close() を呼び出す
//   その後、"Cleanup complete" と出力する

?>
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン