Archiv verlassen und diese Seite im Standarddesign anzeigen : [Perl] defined undefined
Hallo *,
Kann ich folgenden Perl-Code noch verkürzen?
1 if ( defined ${$self->{"db"}->readDB(DBrec, lastEMail)} ) # ist definiert?
2 {
3 ${$self->{"db"}->readDB(DBrec, lastEMail)} =~ /(\d+)/; # Zahl extrahieren
4 $eMailTime = $1;
5 } Das Problem dabei ist, dass ich zweimal über eine andere Klasse auf eine Datenbank zugreifen muss. Wenn ich allerdings die Zeile 3 in die if-Abfrage packe, dann bekomme ich einen Fehler, sobald die betroffene Stelle in der Datenbank nicht steht. Dies ist besonders deshalb unschön, da das ganze mit crontab läuft und deshalb eine Mail für die Fehlermeldung kommt.
michael.sprick
14-03-2006, 22:37
Hi,
gibt Deine readDB() Methode wirklich eine Referenz zurück? Du dereferenzierst ja zu einem Skalar.
Wenn ich jetzt Deinen Code richtig begreife, hast Du zwei Klassen. Klasse A hat ein Objekt der Klasse B als Attribut, richtig?
Dann sollte eigentlich sowas funktionieren:
#!/usr/bin/perl
use strict;
use warnings;
#########################
package DB;
sub new()
{
my $Invokation = shift(@_);
my $Class = ref($Invokation) || $Invokation;
my $this = {
someproperty => 'somevalue'
};
bless($this, $Class);
return($this);
}
sub readDB()
{
my $this = shift(@_);
return($this->{someproperty});
}
########################
package SomeClass;
sub new()
{
my $Invokation = shift(@_);
my $Class = ref($Invokation) || $Invokation;
my $this = {
db => DB->new()
};
bless($this, $Class);
return($this);
}
sub test()
{
my $this = shift(@_);
if($this->{'db'}->readDB() =~ m/(some.*)/i )
{
print $1;
}
}
######################
package main;
my $SomeObject = SomeClass->new();
$SomeObject->test();
Dein Codeschnipsel findest Du der SomeClass->test() wieder.
hth, michael
Richtig erkannt, es handelt sich um die controller-Klasse (main), die auf die Datenbank-Klasse zugreift (hier die Zeit, zu der zuletzt eine E-Mail versandt wurde).
Der Wert, der abgefragt wird, ist eine Referenz auf ein Skalar (Dies kommt daher, dass die selbe Funktion auch ein Hash zurückgeben kann und dies als Referenz geschieht).
Das Problem ist leider nicht gelöst.
Denn, wenn ich die Abfrage nach dem Wert ohne define mache, schreibt crontab folgende Mail, wenn dieser nicht definiert ist:
Use of uninitialized value in pattern match (m//) at /home/dommel/temperatur/temperature.pl line 418. Dies soll verhindert werden.
Hier mal mein Kunstruktor und die angesprochene Funktion:
sub new # Konstruktor
{
my $this = shift;
my $class = ref($this) || $this;
my $path = shift;
my @names;
push @names, @_;
die "Keine Datenbank angegeben!" unless defined $names[0];
my $self = {
dbNames => \@names, # alle Datenbanken in Array
};
bless $self, $class; # Objekt erzeugen
foreach my $file (@{$self->{dbNames}}) #("temperature","sensorError","record")
{
tie(%{$self->{$file}}, 'SDBM_File', "$path$file", O_RDWR|O_CREAT, 0666);
}
return $self;
}
sub readDB
{
my $self = shift;
my $db = shift; # Datenoberbegriff
my $key = shift; # Datenschluessel
my $ret;
return $self->{$db} unless (defined $key);# gesamtes Hash wird zurueckgegeben
if (defined $self->{$db}->{$key})
{
$ret = $self->{$db}->{$key};
}
return \$ret; # ein Wert wird zurueckgegeben (ref)
}
und nochmal der geänderte Aufruf:
my $eMailTime = 0;
if ( ${$self->{"db"}->readDB(DBrec, lastEMail)} =~ m/(\d+)/ )
{
;
$eMailTime = $1;
}
Leider nicht in Farbe. Hat gerade irgendwie nicht funktioniert.
michael.sprick
15-03-2006, 09:59
hmm,
also wenn der Kommentar hinter dem folgenden Code bedeutet, was ich vermute:
foreach my $file (@{$self->{dbNames}}) #("temperature","sensorError","record")
{
tie(%{$self->{$file}}, 'SDBM_File', "$path$file", O_RDWR|O_CREAT, 0666);
}
Dann sieht das Objekt der klasse, in der die ReadDB Methode steht nach der foreach Schleife irgendwie so aus:
OBJECT-
|---'dbNames' = ArrayRef('Name1','Name2');
|---'temperature' = HashRef()
|---'senseError' = HashRef()
|---'record' = HashRef()
Im Aufruf benutzt Du dann aber
$self->{"db"}
Ist "db" hier nur ein Platzhalter für eine der drei Datenbanken? Wenn nein - das könnte ein Fehler sein.
Dann:
my $ret;
# $ret ist undef
return $self->{$db} unless (defined $key);
# nur wenn kein $key übergeben wurde
# $ret ist immernoch undef
# Nur wenn es die kombination $db->{$key} wirklich gibt!!!
if (defined $self->{$db}->{$key})
{
$ret = $self->{$db}->{$key};
}
# sonst ist $ret weiterhin undef
return \$ret;
Solltest Du also z.B. "db" tatsächlich benutzt haben, würde das genau die Warnung verursachen, die Du beschrieben hast. Das Gleiche gilt, wenn es $key nicht gibt.
Wenn Du nur die Warnung umgehen willst, und es für Dich OK bzw. gewollt ist, dass die Funktion ein undef zurückgibt, dann schreib einfach vor das Patternmatching
no warnings;
zwei andere Möglichkeiten sind
entweder:
my $ret = '';
# $ret erst sauber definieren
oder Du baust den Aufruf so um:
if($_ = ${$self->{"db"}->readDB(DBrec, lastEMail)} and m/(\d+)/i)
{
print $1;
}
hth, michael
Danke, der letzte Code-Schnipsel war der, den ich suchte. Jetzt funktioniert es so wie ich will - ohne Mail mit Fehlermeldung.
Zur weiteren Erklärung:
$self{"db"} ist die Referenz auf das Objekt der Datenbank-Klasse.
Dieses enthält dann die drei Datenbanken "temperature", "sensorError" und "record". Wobei es hier um "record" geht. Dieser String steht in der Konstante DBrec. Auch die Konstante lastEMail beinhaltet einen String. Mit readDB(DBrec, lastEMail) wird also in der Datenbank "record" nach dem Eintrag der Konstante lastEMail gesucht und der Wert zurueck gegeben.
Zweck des ganzen ist es heraus zu finden, wann die letzte E-Mail versandt wurde und ob es an der Zeit ist eine weitere zu verschicken. Dies geschieht dann, wenn die Temperatur im Serverraum eine bestimmte Schwelle (über längere Zeit) überschreitet.
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.