stas 2004/05/07 18:26:40 Modified: src/docs/2.0/api/APR Error.pod Log: explain the new exceptions mechanism Revision Changes Path 1.2 +111 -8 modperl-docs/src/docs/2.0/api/APR/Error.pod Index: Error.pod =================================================================== RCS file: /home/cvs/modperl-docs/src/docs/2.0/api/APR/Error.pod,v retrieving revision 1.1 retrieving revision 1.2 diff -u -u -r1.1 -r1.2 --- Error.pod 7 May 2004 21:38:48 -0000 1.1 +++ Error.pod 8 May 2004 01:26:40 -0000 1.2 @@ -1,26 +1,129 @@ =head1 NAME -APR::Error - Perl API for APR/mod_perl exceptions +APR::Error - Perl API for APR/Apache/mod_perl exceptions =head1 Synopsis - use APR::Error (); - - - - + eval { $obj->mp_method() }; + if ($@ && $ref $@ eq 'APR::Error' && $@ == $some_code) { + # handle the exception + } + else { + die $@; # rethrow it + } =head1 Description -C<APR::Error> provides ... - +Apache and APR API return status code for almost all methods, so if +you didn't check the return code and handled any possible problems, +you may have silent failures which may cause all kind of obscure +problems. On the other hand checking the status code after each call +is just too much of a kludge and makes quick prototyping/development +almost impossible, not talking about the code readability. Having +methods return status codes, also complicates the API if you need to +return other values. + +Therefore to keep things nice and make the API readable we decided to +not return status codes, but instead throw exceptions with +C<APR::Error> objects for each method that fails. If you don't catch +those exceptions, everything works transparently - perl will intercept +the exception object and C<die()> with a proper error message. So you +get all the errors logged without doing any work. + +Now, in certain cases you don't want to just die, but instead the +error needs to be trapped and handled. For example if some IO +operation times out, may be it is OK to trap that and try again. If we +were to die with an error message, you would have had to match the +error message, which is ugly, inefficient and may not work at all if +locale error strings are involved. Therefore you need to be able to +get the original status code that Apache or APR has generated. And the +exception objects give you that if you want to. Moreover the objects +contain additional information, such as the function name (in case you +were eval'ing several commands in one block), file and line number +where that function was invoked from. More attributes could be added +in the future. + +C<APR::Error> uses method overloading, such that in boolean and +numerical contexts, the object returns the status code; in the string +context the full error message is returned. + +When intercepting exceptions you need to check whether C<$@> is an +object (reference). If your application uses other exception objects +you additionally need to check whether this is a an C<APR::Error> +object. Therefore most of the time this is enough: + + eval { $obj->mp_method() }; + if ($@ && $ref $@ && $@ == $some_code) + warn "handled exception: $@"; + } + +But with other, non-mod_perl, exception objects you need to do: + + eval { $obj->mp_method() }; + if ($@ && $ref $@ eq 'APR::Error' && $@ == $some_code) + warn "handled exception: $@"; + } + +In theory you could even do: + + eval { $obj->mp_method() }; + if ($@ && $@ == $some_code) + warn "handled exception: $@"; + } + +but it's possible that the method will die with a plain string and not +an object, in which case C<$@ == $some_code> won't quite +work. Remember that mod_perl throws exception objects only when Apache +and APR fail, and in a few other special cases of its own (like +C<L<exit|docs::2.0::api::ModPerl::Util/C_exit_>>). + + warn "handled exception: $@" if $@ && $ref $@; + +For example you wrote a code that performs L<a socket +read|docs::2.0::api::APR::Socket/C_recv_>: + + my $buff = $sock->recv(1024); + my $rlen = length $buff; + warn "read $rlen bytes\n"; + +and in certain cases it times out. The code will die and log the +reason for the failure, which is fine, but later on you decide that +you want to give the read another chance before dying. In which case +you rewrite the code to handle the exception like so: + + use APR::Const -compile => qw(TIMEUP); + my $buff = eval { $sock->recv(1024) }; + if ($@) { + die $@ unless ref $@ && $@ == APR::TIMEUP; + goto retry; + } + my $rlen = length $buff; + warn "read $rlen bytes\n"; + +Notice that we handle non-object and non-C<APR::Error> exceptions as +well, by simply rethrowing them. + + +Finally, the class is called C<APR::Error> because it needs to be used +outside mod_perl as well, when called from +C<L<APR|docs::2.0::api::APR>> applications written in perl. + + +=head1 API + +=head2 C<cluck> +C<cluck> is an equivalent of C<Carp::cluck> that works with +C<APR::Error> exception objects. +=head2 C<confess> +C<confess> is an equivalent of C<Carp::confess> that works with +C<APR::Error> exception objects. =head1 See Also
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]