Can't call method on unblessed reference - but why?

Dieser Post wurde aus meiner alten WordPress-Installation importiert. Sollte es Darstellungsprobleme, falsche Links oder fehlende Bilder geben, bitte einfach hier einen Kommentar hinterlassen. Danke.

OOP in Perl is pretty simple: Every reference may become an object. But trying to use a reference instead of an object for an OOP call results in Can't call method on unblessed reference.

Here is a short code snippet (after I removed some uninteresting parts):

eval { $dbhs->{master} = DBI->connect($dsn_master); };die ('Connect master: ' . $@) if $@ and !$dbhs->{master};

my $hostinfo = $dsn_master;$hostinfo =~ s/password=([^;]*)(;|$)//;$dbhs->{master}->{private_hostinfo} = $hostinfo;

if (!defined $dbhs->{master}) { return; }

return $dbhs->{master}->prepare($sql);

Pretty simple, isn't it?
  • Connect to the database server. In case of hard error, die using an extended error string.
  • Strip the password out of the dsn string and save it into a DBI private variable.
  • Handle soft errors by returning implicit undef.
  • Return a statement handle if everything was ok.
But the last line issued a Can't call method prepare on unblessed reference error.

I got the error report yesterday but didn't see the problem. Connection errors are handled by eval/die or the defined-check, how could a non-object appear at the prepare line? Another completely unrelated report came in today and made me looking at this source lines again for some reason. I discovered the solution not thinking about yesterdays problem at all, it simply jumped into my eyes:

The reason is Perl's implicit reference creation. Every hard error is covered by eval { }, but a soft error not issuing a die() within DBI->connect returns an undef value into $dbhs->{master} without setting $@ - the die after eval will never happen in this situation. When the hostinfo is assigned, {master} still has no value which makes Perl create a hash refrence in $dbhs->{master} before filling in the key "private_hostinfo".

The !defined check will never ever capture anything because $dbhs->{master} either contains a valid DBI connection handle (in case of a DBI->connect success earlier) or the auto-created hash reference - and both of them are "true".

I simply moved the hostinfo creation block below the soft error check - and everything is fine now.


1 Kommentar. Schreib was dazu

  1. anonymouse

    i prefer try:tiny like next code. you can sure use eval the same way

    if($dbhs->{master} = try { DBI->connect($dsn_master) }) ....

    or use return unless. whatever. the point - you wont pass with broken data.
    also you can handle known exceptions with catch

Schreib was dazu

Die folgenden HTML-Tags sind erlaubt:<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>