関数内でのPDO try-catchの使用法

pdo php
関数内でのPDO try-catchの使用法

将来のWebアプリケーションのすべてでPDOを使用することを考えています。 現在(これまでにSOから学んだことを使用して)、データベース接続を処理するために私のサイトにあるものは、次のようなSingletonクラスです。

class DB {

    private static $instance = NULL;
    private static $dsn      = "mysql:host=localhost;dbname=mydatabase;";
    private static $db_user  = 'root';
    private static $db_pass  = '0O0ooIl1';

    private function __construct()
    {

    }
    private function __clone()
    {

    }
    public static function getInstance() {

        if (!self::$instance)
        {
            self::$instance = new PDO(self::$dsn, self::$db_user, self::$db_pass);
            self::$instance-> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        }
        return self::$instance;
    }
}

もう1つのファイル(functions.php)には、次のようなコンテンツ固有の関数があります。

function get_recent_activities ()
{
    try
    {
        $db = DB::getInstance();
        // --prepare and execute query here, fetch the result--
        return $my_list_of_recent_activities;
    }
    catch (PDOException $e)
    {
        return "some fail-messages";
    }
}
...

私は `トライを繰り返さなければならないことを意味します.. すべての関数の中で `の一部をとらえてください。

私の質問は:

  1. それをどのようにもっと効率的にするべきですか? (eg. 繰り返す必要はありません
    すべての関数で `try..catch`を実行しますが、それでもそれぞれに異なる「失敗メッセージ」を返すことができます)

  2. これはもう良いやり方ですか? 私はまだPDOとOOPにまだ慣れていません(まだ
    学ぶべきことはもっとたくさんあります)、そのため(現時点では)、そこに改善できる欠点や問題は実際にはありません。

それがはっきりしないか長すぎるように思えば申し訳ありません。 前もって感謝します。

  30  28


ベストアンサー

あなたの実装は丁度良いです、そしてそれはほとんどの目的のために完璧にうまくいくでしょう。

すべてのクエリをtry / catchブロック内に配置する必要はありません。実際、ほとんどの場合、実際にはそうしたくありません。 その理由は、クエリが例外を生成した場合、それは構文エラーやデータベースの問題などの致命的な問題の結果であり、それらがすべてのクエリで考慮されるべき問題ではないためです。

例えば:

{$ rs = $ db-> prepare( 'SELECT * FROM foo');を試してください。 $ rs-> execute(); $ foo = $ rs-> fetchAll(); catch(Exception $ e){die( "ああ、いや! クエリにエラーがあります。 ");}

ここでのクエリは正しく機能するか、まったく機能しません。 それがまったく機能しないという状況は、本番システムでは規則性があっても発生することはありません。そのため、ここで確認する必要はありません。 変更しないとエラーが発生し、問題を警告するような例外メッセージが表示されないため、そうすることは実際には逆効果です。

代わりに、単にこれを書いてください:

$ rs = $ db  - > prepare( 'SELECT * FROM foo'); $ rs-> execute(); $ foo = $ rs-> fetchAll();

一般に、クエリの例外をキャッチして処理する唯一の時間は、クエリが失敗した場合に何か他のことをしたい場合です。 例えば:

// We're handling a file upload here.
{$ rs = $ db-> prepare( 'INSERT INTOファイル(fileID、filename)値(?、?)');を試してください。 $ rs  - > execute(array(1234、 '/var/tmp/file1234.txt')); catch(例外$ e){unlink( '/ var / tmp / file1234.txt');} $ eを投げます。 }

実稼働環境で発生したデータベースエラーをログに記録または通知し、例外トレースの代わりにわかりやすいエラーメッセージをユーザーに表示する単純な例外ハンドラーを作成することをお勧めします。 その方法についてはhttp://www.php.net/set-exception-handlerを参照してください。

40


ここでいくつか注意点があります:

  • このコードは、データベースロギングやデータベース構成管理など、いくつかの従来の問題を考慮して書かれています。

  • 自分で構築する前に、既存の解決策を検討することを強くお勧めします。 既存のフレームワークやライブラリーを使用したくないと考えるようになったとき、多くの人が自分たち自身で考えています。私は自分のカスタムフレームワークとラッパークラスをフレームワークに移行することを諦めていると強調することはできません。 Zendへの移行を検討していますが、優れた選択肢がいくつかあります。

ああ、私はこの点があなたの問い合わせのための例外処理の全てを扱うために一つの機能をどのように包むことができるかを例証することを指摘しなければなりません。 クエリからのスタックトレースから、問題をデバッグして修正するために必要なすべての情報が得られるため、try catchブロックは他の場所には書きません。

これが私の現在のPDOラッパークラスの実装です。

class DBはPDOを拡張します{//シングルトンパターンの実装を許可します -  ndg 5/24/2008 private static $ instance;

//特定のデータベース用にDBクラスを設定するためのpublic static変数 -  ndg 6/16/2008 public static $ error_table; public static $ host_name; public static $ db_name; public static $ username;公開静的$パスワード。 public static $ driver_options; public static $ db_config_path;


function __construct($ dsn = ""、$ username = ""、$ password = ""、$ driver_options = array()){if(isset(self :: $ db_config_path)){try {if(!require_once self ::) $ db_config_path){新しいエラーをスローします( 'ファイルを要求できませんでした:'。 self :: $ db_config_path); catch(エラー$ e){$ e-> emailAdmin();}} elseif(isset($ _ ENV ['DB'])){self :: $ db_config_path = 'config.db.php';}

{if(!require_once self :: $ db_config_path){{新しいエラーをスローしてください(ファイルの要求に失敗しました: ')。 self :: $ db_config_path); catch(エラー$ e){$ e-> emailAdmin();}} }}

parent :: __ construct( "mysql:host ="。 self :: $ host_name "; dbname =" .self :: $ db_name、self :: $ username、self :: $ password、self :: $ driver_options); $ this-> setAttribute(PDO :: ATTR_ERRMODE、PDO :: ERRMODE_EXCEPTION); $ this-> setAttribute(PDO :: ATTR_STATEMENT_CLASS、array( 'QueryStatement'、array($ this)));

if(!isset(self :: $ error_table)){self :: $ error_table = 'errorlog_rtab'; }}

/ **
     *  DB接続オブジェクトを返す*
     *  @return DB * / public static function connect(){

//新規開発および保守開発で使用する新規PDO接続{{(!isset(self :: $ instance)){{(!self :: $ instance = new DB()){throw new error( 'PDO DB接続がエラーで失敗しました: '。 self :: errorInfo()); }}

self :: $ instanceを返します。 catch(error $ e){$ e-> printErrMsg();} }}

/ **
     *  動的クエリを構築するために使用できるQueryBuilderオブジェクトを返します*
     *  QueryBuilder @return
     *  * / public関数createQuery(){新しいQueryBuilder()を返す。 }

パブリック関数executeStatement($ステートメント、$ params = null、$ FETCH_MODE = null){if($ FETCH_MODE == 'スカラー'){return $ this-> executeScalar($ステートメント、$ params); }

try {try {if(!empty($ params))} {$ stmt = $ this-> prepare($ statement); $ stmt-> execute($ params); } else {$ stmt = $ this-> query($ statement);} catch(PDOException $ pdo_error){新しいエラーをスローします( "クエリの実行に失敗しました:\ n"。 $ステートメント msgstr "\ nパラメータを使用しています:\ n"#:。 print_r($ params、true) "\ nエラーあり:\ n" $ pdo_error-> getMessage()); catch(エラー$ e){$ this-> logDBError($ e);} $ e-> emailAdmin(); falseを返します。 }

{if($ FETCH_MODE == 'all'){$ tmp = $ stmt-> fetchAll();}を試してください。 } elseif($ FETCH_MODE == 'column'){$ arr = $ stmt-> fetchAll();}

foreach($ arrは$ key => $ val){foreach($ valは$ var => $ value){$ tmp [] = $ value; elseif($ FETCH_MODE == 'row'){$ tmp = $ stmt-> fetch();}}} } elseif(empty($ FETCH_MODE)){trueを返す。 catch(PDOException $ pdoError){trueを返します。 }

$ stmt-> closeCursor();

$ tmpを返します。

}

パブリック関数executeScalar($ステートメント、$ params = null){$ stmt = $ this-> prepare($ステートメント);

if(!empty($ this-> bound_params)

try {try {if(!empty($ params))} {$ stmt-> execute($ params); } else {$ stmt = $ this-> query($ statement);} catch(PDOException $ pdo_error){新しいエラーをスローします( "クエリの実行に失敗しました:\ n"。 $ステートメント msgstr "\ nパラメータを使用しています:\ n"#:。 print_r($ params、true) "\ nエラーあり:\ n" $ pdo_error-> getMessage()); catch(エラー$ e){$ this-> logDBError($ e);} $ e-> emailAdmin(); }

$ count = $ stmt-> fetchColumn();

$ stmt-> closeCursor();

// echo $ count; $ countを返します。 }

保護された関数logDBError($ e){$ error = $ e-> getErrorReport();

$ sql = "INSERT INTO" self :: $ error_table "(message、time_date)VALUES(:エラー、NOW())";

$ this-> executeStatement($ sql、array( ':error' => $ error)); }}

QueryStatementクラスはPDOStatement {public $ conn;}を拡張します。

保護された関数__construct(){$ this-> conn = DB :: connect();} $ this-> setFetchMode(PDO :: FETCH_ASSOC); }

パブリック関数execute($ bound_params = null){return parent :: execute($ bound_params);} }}

3


タイトルとURLをコピーしました