このコーナーについて
私は根っからの文系なのでプログラミングや情報技術についてはITパスポート程度の知識しかなく、現在は全くの独学でコードや言語等のスキルの勉強はチュートリアル等でコードを書いて成果物を作りながら学んでいけるが、それらの過程で出てくる用語や技術についてはイマイチ学びきれない。
なので、折に触れて書籍及びQlita記事等のネットサーフィンで学んだ座学的知識をアウトプットすることがこのコーナーの目的である。
今回
パーフェクトPHPで学ぶ例外処理まで
例外処理
例外処理とはエラー(例外)が発生しても正常にスクリプトが動作するように行う処理。
プログラムの実行時のエラーを適切に処理するためのものと言ってもいい。
基本
<?php
throw new $classname(引数);
?>
<?php
try {
// 例外が起きる恐れがあるコード
} catch ($classname $e ) {
// 例外発生時の処理
}
?>
基本的な構文は以上の2つ。これを合わせて以下のようにするのが基本的な使い方。
<?php
try {
throw new $classname(引数);
} catch($classname $e ) {
}
?>
$classname
の部分には例外クラスの名称、$e
の部分には例外を受け取るための任意の変数を指定しておく。
では実際に使ってみる。
<?php
function warizan($val1,$val2) {
return $val1 / $val2;
}
var_dump(warizan(2,0));
?>
<br />
<b>Warning</b>: Division by zero in <b>[...][...]</b> on line <b>3</b><br />
float(INF)
当然上記のようにエラーメッセージが出るのでこれを例外処理で投げて任意の処理に置き換えたいとすると
<?php
function warizan($val1,$val2) {
try {
if($val2 === 0) { // 1
throw new Exception("0では割れません");
}
return $val1 / $val2;
} catch (Exception $e) { // 2
return $e->getMessage(); // 3
}
}
?>
こういうことになる。例外処理を書く上でのポイントは3つ。
1 例外を投げる
まずは例外処理を行う関数において起こるであろうエラーを自分で想定することが肝要である。
今回は簡単な割り算の関数なのですぐにエラーが想定できるが、実際のコードではそうはいかないのでエラーメッセージやアルゴリズムを参考に例外処理を考えていく。
閑話休題。
今回は割る数に0を入れてしまうとエラーになるのだから、if
文で条件付して例外を投げてしまえばいい。
例外クラスのException
については後述する。
2 例外を受け取る(キャッチする)
ここでは例外クラスのException
のインスタンスを$e
に代入している。
インスタンスがいつ作られたのかというと、コードをみれば分かる通り前述の1のときである。
つまり、大雑把に考えると以下のようなものと思っている。
throw new Exception("0では割れません"); + catch (Exception $e)
= $e = new Exception("0では割れません");
3 例外クラスのインスタンスにあるgetMessageメソッドへアクセスする
ここではcatch
ブロック内に例外が発生したときの処理を書く。
つまり、必要であるなら1と同じようにthrow
構文で例外を投げ、さらにcatch
ブロックを増やすということになる。
今回は、それはせずに受け取った例外に対してどのような反応を返すかということを定義するだけに留まっている。
$e->getMessage()
とあるということは、インスタンスの中にあるgetMessage
メソッドにアクセスしているということになる。
このメソッドは引数に設定された文字を例外メッセージとして取得するメソッドになるので、0では割れませんという文字列が値としてreturn
で返されることになる。
また、蛇足ではあるが例外が投げられたということはエラーが起きているということになるので、例外が投げられた時点で本来想定していた処理(今回なら割り算の実行結果を返す)は行われず、以上の処理の流れで例外処理が行われる。
以上の流れが例外処理の基本なので覚えておきたい。
補足 Exceptionって?
Exception
とはPHPに備え付けられている例外処理をまとめたクラスのことで、PHPにおいて例外をスローする場合は必ずException
あるいは大本であるException
を継承しているサブクラス(~Exception
の形で表現されているクラス)にスローしなければならない。
Exceptionを継承しているサブクラスというのは例えば定義済みの例外の中では
LogicException extends Exception { // Exceptionを継承しているのがわかる。
/* 継承したプロパティ */
protected string $message ;
protected int $code ;
protected string $file ;
protected int $line ;
/* 継承したメソッド */
final public Exception::getMessage ( void ) : string
final public Exception::getPrevious ( void ) : Exception
final public Exception::getCode ( void ) : mixed
final public Exception::getFile ( void ) : string
final public Exception::getLine ( void ) : int
final public Exception::getTrace ( void ) : array
final public Exception::getTraceAsString ( void ) : string
public Exception::__toString ( void ) : string
final private Exception::__clone ( void ) : void
}
というものがある。
役割はプログラムのロジック内でのエラーを表す。
つまり、この例外に投げられた場合は書いたコードのロジックがおかしいということ。
さらにこれを継承した
BadFunctionCallException extends LogicException { // LogicExceptionを継承していることがわかる。
/* 継承したプロパティ */
protected string $message ;
protected int $code ;
protected string $file ;
protected int $line ;
/* 継承したメソッド */
final public Exception::getMessage ( void ) : string
final public Exception::getPrevious ( void ) : Exception
final public Exception::getCode ( void ) : mixed
final public Exception::getFile ( void ) : string
final public Exception::getLine ( void ) : int
final public Exception::getTrace ( void ) : array
final public Exception::getTraceAsString ( void ) : string
public Exception::__toString ( void ) : string
final private Exception::__clone ( void ) : void
}
というものもある。
ちなみに未定義の関数をコールバックが参照したり、引数を指定しなかったりした場合にこの例外に投げられる。
つまり、どこまでいってもExceptionが大本にあり、これらのクラスはそこから継承したプロパティやメソッドを使って各々の例外処理を行っているということがわかるので、最初にいったスローの際の決まり事にも納得が行くと思う。
PHPにおいての例外は参考の項目にマニュアルのURLを載せておくので各自参照してほしい。
参考
パーフェクトPHP
[PHP超入門】クラス~例外処理~PDOの基礎
例外
定義済みの例外