web-dev-qa-db-ja.com

PHP try / catchおよび致命的なエラー

PHPを使用してデータベースを使用するには、次のスクリプトを使用しています。

_try{
    $db = new PDO('mysql:Host='.$Host.';port='.$port.';dbname='.$db, $user, $pass, $options);
}
catch(Exception $e){
    $GLOBALS['errors'][] = $e;
}
_

ここで、このデータベースハンドルを使用して、このコードを使用してリクエストを実行します。

_try{
    $query = $db->prepare("INSERT INTO users (...) VALUES (...);");
    $query->execute(array(
        '...' => $...,
        '...' => $...
    ));
}
catch(Exception $e){
    $GLOBALS['errors'][] = $e;
}
_

ここに問題があります:

  • DBへの接続に問題がなければ、すべてが機能し、
  • 接続に失敗してもDBを使用しない場合、_$GLOBALS['errors'][]_配列があり、その後もスクリプトは実行されていますが、
  • DBへの接続に失敗すると、次の致命的なエラーが発生します。

通知:未定義の変数:32行目のC:\ xampp\htdocs [...]\test.phpのdb

致命的なエラー:C:\ xampp\htdocs [...]\test.phpの32行目の非オブジェクトでのメンバー関数prepare()の呼び出し

注:32行目は$query = $db->prepare(...)命令です。

つまり、スクリプトがクラッシュし、try/catchは役に立たないようです。この2回目のtry/catchが機能しない理由とその解決方法を知っていますか?

助けてくれてありがとう!

編集:本当に良い返信がいくつかあります。私が検証したいのは、私がやりたかったこととは厳密には一致しませんが、おそらくこれが最善のアプローチです。

20
Ploppe

try/catchブロックは、スローされた例外に対してのみ機能します(_throw Exception_またはExceptionのサブクラスを呼び出す必要があります)。 try/catchを使用して致命的なエラーをキャッチすることはできません。

DB接続を確立できない場合、おそらくページで意味のあることをDBが行う必要があるので、致命的だと考えます。

PDOは、接続を確立できない場合に例外をスローします。あなたの特定の問題は、それを使ってメソッドを呼び出そうとしたときに_$db_が定義されていないため、致命的なnullポインタ(一種)を取得することです。他の人が示唆しているようにif ($db == null)フープをジャンプするのではなく、コードを修正して、_$db_が必要なときに常に定義されるか、またはDB接続は、それを使用するコードで使用できます。

致命的なエラーを「キャッチ」したい場合は、_set_error_handler_を使用しますが、これでも致命的なエラーでスクリプトの実行が停止します。

27
Explosion Pills

PHP7では、 致命的なエラーの試行を使用できるようになりました 簡単な作業で

try {
   do some thing evil
} catch (Error $e) {
   echo 'Now you can catch me!';
}

しかし、通常、catch Errorの使用は避ける必要があります。これは、プログラマーの責任に属するコードを見逃すことになるためです:-)

11
Hiro

なぜtry ... catchこれを宣言するためのステートメント。これを交換してください:

try{
    $db = new PDO('mysql:Host='.$Host.';port='.$port.';dbname='.$db, $user, $pass, $options);
}

と:

$db = new PDO('mysql:Host='.$Host.';port='.$port.';dbname='.$db, $user, $pass, $options) or die("Cannot Create PDO!");

またはあなたのやり方で:

$db = new PDO('mysql:Host='.$Host.';port='.$port.';dbname='.$db, $user, $pass, $options) or ($GLOBALS['errors'][] = "Cannot Create PDO!");

次のifステートメントを追加してみてください。

if ($db) {
    $query = $db->prepare("INSERT INTO users (...) VALUES (...);");
    $query->execute(....);
}
else die('Connection lost');
0
Ertunç

データベース接続が失敗した場合、最初の_$db_ブロックの_try .. catch_はnullになります。そのため、後で$db->prepare(...)のように、非オブジェクトのメンバーを使用できなくなります。これを使用する前に

_if ($db) {
    // other try catch statement
}
_

これにより、dbインスタンスを操作できるようになります。

0
Kosta

$dbが空の場合、テストについてすでに何が書かれているかは報告しません。 「クリーン」な解決策は、データベースへの接続が失敗した場合に人為的に例外を作成することであると追加するだけです。

if ($db == NULL) throw new Exception('Connection failed.');

次のようにtry - catchに前の行を挿入します。

try{

    // This line create an exception if $db is empty
    if ($db == NULL) throw new Exception('Connection failed.');


    $query = $db->prepare("INSERT INTO users (...) VALUES (...);");
    $query->execute(array(
        '...' => $...,
        '...' => $...
    ));
}
catch(Exception $e){
    $GLOBALS['errors'][] = $e;
}

これが他の人の役に立つことを願っています!

0
Fifi
try{
if(!is_null($db))
{
    $query = $db->prepare("INSERT INTO users (...) VALUES (...);");
    $query->execute(array(
        '...' => $...,
        '...' => $...
    ));
}
}
catch(Exception $e){
    $GLOBALS['errors'][] = $e;
}
0
Arun Killu