PHP5を試してみる - 例外処理
サンプルは、EXPERIENCEで実際に確認できるようにしてますので、気になる方は見てみてください。
スクリプト言語でここまでやるか?という感もありますが、やっぱり一番気になるのがこれでしょう(^-^; サンプルではちょっと分かりづらいですが、実際の使い方としては、「ある処理を行った結果エラーかどうかを判定し、エラーの場合は例外をthrowする」という感じではないかと思います。
なお、ChangeLogにもあるとおり、β4から組み込みクラスである「exception」クラスを継承する必要があります。
●13.exception_handling.php5
<?php
class MyException extends exception {
function MyException($_error) {
$this->error = $_error;
}
function getException()
{
return $this->error;
}
}
function ThrowException()
{
throw new MyException("'This is an exception!'");
}
try {
} catch (MyException $exception) {
print "There was an exception: " . $exception->getException();
print "\n";
}
try {
ThrowException();
} catch (MyException $exception) {
print "There was an exception: " . $exception->getException();
print "\n";
}
?>
次に実践的(?)なサンプルで、かなりJava風にしています。中身は以下のような感じです。
- 例外クラス「OracleException」「ConnectionFailedException」を用意する
- Oracleクラスのconnectメソッドは、接続に失敗した場合に「ConnectionFailedException」をthrowする
- Oracleアクセスクラスを使用する関数「main」を用意し、try~catchブロック内でOracleクラスのconnectメソッドを「エラーが発生するように」呼び出す。また、catchする例外は、「OracleException」「ConnectionFailedException」の2つ
- 参考程度に、Javaの「Throwable.printStackTrace()」を真似たメソッドも用意してみる
- 組み込みクラスの1つであるexceptionクラスのgetTraceAsStringメソッドの出力もしてみる
●exception/exception_test01.php5
<?php
class OracleException extends exception
{
function getStackTrace()
{
$bt = debug_backtrace();
$ret = get_class($this) . ':' . $this->getMessage();
foreach ($bt as $stack) {
$pathinfo = pathinfo($stack['file']);
$ret .= sprintf(
" at %s%s(%s:%s)\n",
isset($stack['class']) ? $stack['class'] . '.' : '',
$stack['function'],
$pathinfo['basename'],
$stack['line']);
}
return $ret;
}
function printStackTrace()
{
echo '<pre>' . $this->getStackTrace() . '</pre>';
}
}
class ConnectionFailedException extends OracleException
{
}
class Oracle
{
private $conn_;
function connect($user, $pass, $netstr)
{
$this->conn_ = @OCILogon($user, $pass, $netstr);
if (!$this->conn_) {
$err = OCIError();
throw new ConnectionFailedException($err['message'], $err['code']);
}
}
function close()
{
if (!$this->conn_) {
OCILogoff($this->conn_);
}
}
}
?>
<?php
function main()
{
try {
$ora = new Oracle();
$ora->connect('foo', 'bar', 'hoge');
echo 'OK<br>';
$ora->close();
}
catch (ConnectionFailedException $e) {
echo 'ConnectionFailedException: ' . $e->getMessage() . '<br>';
$e->printStackTrace();
echo'<hr>';
echo '<pre>' . $e->__toString() . '</pre>';
}
catch (OracleException $e) {
echo 'OracleException: ' . $e->getMessage() . '<br>';
$e->printStackTrace();
echo'<hr>';
echo '<pre>' . $e->getTraceAsString() . '</pre>';
}
echo '<hr>';
if (isset($e)) {
echo '■Javaならスコープ外<br>';
echo 'get_class_name($e)=' . get_class($e) . '<br>';
echo 'getTrace=<pre>' . $e->getTraceAsString() . '</pre><br>';
}
echo '<hr>';
echo 'finished<br>';
}
main();
?>
<hr>
<?php
show_source($_SERVER['SCRIPT_FILENAME']);
?>
●出力結果ConnectionFailedException: ORA-12154: TNS:could not resolve service name
ConnectionFailedException:ORA-12154: TNS:could not resolve service name
at ConnectionFailedException.getStackTrace(exception_test01.php5:29)
at ConnectionFailedException.printStackTrace(exception_test01.php5:82)
at main(exception_test01.php5:109)
exception 'ConnectionFailedException' with message 'ORA-12154: TNS:could not resolve service name
' in /path/to/php5/exception/exception_test01.php5:52
Stack trace:
#0 /path/to/php5/exception/exception_test01.php5(76): Oracle->connect('foo', 'bar', 'hoge')
#1 /path/to/php5/exception/exception_test01.php5(109): main()
#2 {main}
■Javaならスコープ外
get_class_name($e)=ConnectionFailedException
getTrace=
#0 /path/to/php5/exception/exception_test01.php5(76): Oracle->connect('foo', 'bar', 'hoge')
#1 /path/to/php5/exception/exception_test01.php5(109): main()
#2 {main}
finished
試して分かったことですが、
- try~catchブロックでcatchされない例外がthrowされると、「Fatal error: Uncaught exception 'Exception' in ...」となる。この際、Exception#getTraceAsStringの結果も出力される
- catchする例外は、サブクラスから順に記述する必要がある
- 例外をcatchした場合、try~catchブロック以降で例外が使えてしまう(仕方がないのか。。。)
な感じです。
1番目は、JavaのRuntimeExceptionっぽい感じで結構はまりそうな予感です。最終的に組み込みクラスであるExceptionクラスのインスタンスをcatchするような仕組み(何らかのフレームワーク)を使った方が良さそうな感じです。
2番目もJavaと同じですね。こちらも気を付ける必要がありそうです。
しかし、スタックトレースが妙にJava。。。(^-^;
|