سؤال

يشير هذا السؤال إلى هذا التعليق من Ikegami:

[...] But if you're going to put an eval around every statement, just use RaiseError => 0. [...]

في هذا خيط.

ماذا سأكسب إذا قمت بتعيين RaiseError ل 0 في مثل هذه الحالات؟

#!/usr/bin/env perl
use warnings;
use 5.10.1;
use DBI;

my $db = 'my_test_sqlite_db.sqlite';
open my $fh, '>', $db or die $!;
close $fh or die $!;

my ( $dbh, $sth );
eval {
    $dbh = DBI->connect( "DBI:SQLite:dbname=$db", "", "", {} );
};
if ( $@ ) { print $@ };

my $table = 'my_sqlite_table';

say   "RaiseError = 1";
say   "PrintError = 0";
$dbh->{RaiseError} = 1;
$dbh->{PrintError} = 0;
eval {
    $sth = $dbh->prepare( "SELECT * FROM $table" );
    $sth->execute();
};
if ( $@ ) { print "ERROR: $@" };

say "\nRaiseError = 0";
say   "PrintError = 1";
$dbh->{RaiseError} = 0;
$dbh->{PrintError} = 1;
eval {
    $sth = $dbh->prepare( "SELECT * FROM $table" );
    $sth->execute();
};
if ( $@ ) { print "ERROR: $@" };

say "\nRaiseError = 0";
say   "PrintError = 0";
$dbh->{RaiseError} = 0;
$dbh->{PrintError} = 0;
eval {
    $sth = $dbh->prepare( "SELECT * FROM $table" );
    $sth->execute();
};
if ( $@ ) { print "ERROR: $@" };

انتاج:

RaiseError = 1
PrintError = 0
ERROR: DBD::SQLite::db prepare failed: no such table: my_sqlite_table at ./perl2.pl line 23.

RaiseError = 0
PrintError = 1
DBD::SQLite::db prepare failed: no such table: my_sqlite_table at ./perl2.pl line 33.
ERROR: Can't call method "execute" on an undefined value at ./perl2.pl line 34.

RaiseError = 0
PrintError = 0
ERROR: Can't call method "execute" on an undefined value at ./perl2.pl line 44.
هل كانت مفيدة؟

المحلول

إذا فشلت لبعض الأسباب، فإن معظم الطرق $dbh ستقوم إما بما يلي:

  • (لو RaiseError تم ضبط الخيار على 0) العودة undef
  • (لو RaiseError تم ضبط الخيار على 1) الخروج فورًا من البرنامج النصي ("الموت") مع تقديم سبب الخطأ كرسالة خروج.

النقطة الأساسية هنا هي أن الأمر متروك لك في كيفية معالجة الأخطاء.إذا كنت ترغب في ذلك، يمكنك فقط تجاهلها، على سبيل المثال (من الواضح أن ما يلي سيعمل مع RaiseError ضبط ل 0 فقط):

for my $db ( ... ) {
    my $dbh = get_database_handle( $db )
       or next;
    ...
}

في هذا المقتطف (المنسوخ من إجابة @ikegami التي ذكرتها في سؤالك) يمكنك استعراض بعض قائمة الإعدادات الخاصة باتصال قاعدة البيانات؛إذا كان بعض الاتصال يمنحك undef, ، ما عليك سوى اختيار واحد آخر، ولا تفعل شيئًا مع الخطأ.

ومع ذلك، يتعين عليك عادةً القيام بما هو أكثر من مجرد "المتابعة" عند حدوث خطأ - ولكن مرة أخرى، لديك خياران:إما الاختيار كل $dbh-بيان ذو صلة بشيء مثل هذا:

$sth = $dbh->prepare('some_params') 
  or process_db_error('In prepare');
...
$res = $sth->execute('another_set_of_params') 
  or process_db_error('In execute');
...
$res->doAnythingElse('something completely different') 
  or process_db_error('In something completely different');

(مثل or لن يتم تنفيذ الأجزاء إلا إذا تم تقييم "الأجزاء اليسرى" المقابلة لها false في سياق منطقي).

...أو قم فقط بلف كل هذا في كتلة "محاولة الالتقاط" لـ Perlish:

if (!eval {    
   $sth = $dbh->prepare('some_params');
   ...
   $res = $sth->execute('another_set_of_params');
   ...
   $res->doSomethingElse('something completely different') 
   ...
   1  # No exception
}) {
   process_db_error($@);
}

ماذا تختار، الأمر متروك لك:إنه قرار شائع بين "أخطاء في عبارات الإرجاع" (باستثناء أنه لجلب خطأ فعلي عليك أن تطلب كائن $dbh) والاستثناءات.

لكن خلاصة القول هي أنه لا يمكنك كتابة هذا فقط:

$sth = $dbh->do_something('that_can_result_in_error');
$sth->do_something('else');

...إذا قمت بتعيين RaiseError ل 0.في هذه الحالة لن يموت النص، $sth سيتم تعيين undef, ، وستحصل على خطأ "مشتق" (حيث لا يمكنك استدعاء طريقة ما undef).

وهذا بالضبط ما حدث في الجزء الأخير من الكود في سؤالك الأصلي.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top