Do You PHP?    
Search Engine Optimization  php5 powerd  Valid XHTML 1.0!  Valid CSS!  このサイトのはてなブックマーク数 



last updated
2005/05/23

counter hits
since 1999/11/06


PHP5を試してみる - 例外処理

memoサンプルは、EXPERIENCEで実際に確認できるようにしてますので、気になる方は見てみてください。

スクリプト言語でここまでやるか?という感もありますが、やっぱり一番気になるのがこれでしょう(^-^; サンプルではちょっと分かりづらいですが、実際の使い方としては、「ある処理を行った結果エラーかどうかを判定し、エラーの場合は例外をthrowする」という感じではないかと思います。

なお、ChangeLogにもあるとおり、β4から組み込みクラスである「exception」クラスを継承する必要があります

●13.exception_handling.php5

<?php
    /**
     * β4からexceptionクラスを継承する必要あり
     */
    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
/**
 * Oracle例外クラス
 * β4からexceptionクラスを継承する必要あり
 */
class OracleException extends exception
{
    /**
     * デバッグ情報のトレース
     * 参考文献:WEB+DB PRESS Vol.12(技術評論社,ISBN4-7741-1623-8),p.205
     */
    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
{
}

/**
 * Oracleクラス
 * とりあえず、接続・切断のみ
 */
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()
{
    /**
     * catchされない例外がthrowされると、
     *「Fatal error: Uncaught exception!」となる
     */
    try {
        $ora = new Oracle();

        /**
         * 存在しないOracleユーザー・インスタンス
         */
        $ora->connect('foo', 'bar', 'hoge');
        echo 'OK<br>';
        $ora->close();
    }
    catch (ConnectionFailedException $e) {
        echo 'ConnectionFailedException: ' . $e->getMessage() . '<br>';
        $e->printStackTrace();

        // Exceptionクラスの実装から
        echo'<hr>';
        echo '<pre>' . $e->__toString() . '</pre>';
    }
    catch (OracleException $e) {
        echo 'OracleException: ' . $e->getMessage() . '<br>';
        $e->printStackTrace();

        // Exceptionクラスの実装から
        echo'<hr>';
        echo '<pre>' . $e->getTraceAsString() . '</pre>';

    }
    echo '<hr>';

    // Javaならスコープ外
    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。。。(^-^;



About This Site |  Privacy Policy |  Contact
Copyright © 1999 - 2005 by Hideyuki SHIMOOKA all rights reserved.