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 completefinally ブロックは、try または catch ブロック内から return した場合でも実行されるため、不可欠なクリーンアップ操作において信頼性が高くなります。
チャレンジ
簡単エラーを適切に処理しながら、常にクリーンアップが行われるようにする try-catch-finally の仕組みを実証するファイル処理システムを構築しましょう。
コードは3つのファイルに分けて構成します:
FileException.php—Exceptionを継承したカスタムFileExceptionクラスを作成します。これは、システム内のファイル関連のエラーを表します。FileProcessor.php— ファイル操作をシミュレートするFileProcessorクラスを作成します。FileException ファイルをインクルードしてください。クラスには以下を含める必要があります:falseで初期化された private な boolean プロパティ$isOpen$isOpenをtrueに設定し、"Opening: [filename]"と出力するメソッドopen(string $filename): void。もし filename が"invalid.txt"の場合は、メッセージ"Cannot open file"を持つFileExceptionをスローします。"Processing file..."と出力するメソッドprocess(): void。もし$isOpenがfalseの場合は、メッセージ"File not open"を持つRuntimeExceptionをスローします。$isOpenをfalseに設定し、"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" と出力する
?>このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。