[Perl] Objekte dynamisch benennen

biont

biont

Grünschnabel
Guten Morgen zusammen,

ich hole mir aus einem XML file zu beliebig vielen "Signalen" meine Eigenschaften und möchte sie in der selben Anzahl von Objekten einer Klasse speichern, die alle Eigenschaften aufnimmt und Zugriffsmethoden dazu bereitstellt (inklusive Wertebereichsüberprüfung uns Plausibilitätsprüfung).

Ausschnitt aus XML:
Code:
...
<SIGNAL>
  <EIGENSCHAFT1>xyz</EIGENSCHAFT1>
  <EIGENSCHAFT2>klm</EIGENSCHAFT2>
  <EIGENSCHAFT3>abc</EIGENSCHAFT3>
</SIGNAL>
<SIGNAL>
...

Das Muster sollte damit klar sein.

Aber jetzt zu meinem Problem: ich kann problemlos eine Instanz/Objekt aus meiner Klasse erstellen und befüllen. Aber wie kann ich den Namen des Objektes dynamisch aus einem String erstellen und dann auch mit Hilfe des Strings darauf zugreifen?

Beispiel (Constructor ist new(); eigenschaft1() ist die Zugriffsmethode auf die gleichnamige, klasseneigene Variable und liefert den Wert der Variablen zurück):
Code:
# funktioniert
my $name = "blabla"; # Daten aus xml
my $obj1 = ClassName->new();
$obj1->eigenschaft1(name);
print $obj1->eigenschaft1."\n";

# funktioniert nicht
my $test = "tralala";
my ${$test} = ClassName->new();
${$test}->eigenschaft1(name); # soll die gleiche Wirkung haben, wie nächste Zeile
$tralala->eigenschaft1(name);

Klar funktioniert der letzte Teil so nicht, aber ich habe einfach keine Idee (mehr), wie ich eine unbekannte Anzahl an Objekten durch-benamen kann und dann auch gezielt Aufrufe zu gestalten.

Einen Tipp, wie mein Ansatz doch funktionieren könnte, oder wie "man" das in Perl eben "richtig" macht, wüsste ich sehr zu schätzen.

Danke schonmal vorab...
 
Hi,

mit anderen Worten, du versuchst metaprogramming in Perl. Ich kenne Perl auch nicht gut genug um zu wissen wie das funktionieren koennte, aber eventuell findest etwas, wenn du mal nach metaprogramming in Verband mit Perl suchst.

Edit:
Och, google sagt dass Perl aehnlich wie die Bash eval kennt:
Code:
#!/usr/bin/perl

my $foo = "bar";
my $bar = 0;
eval "\${$foo} = 20";
print "$bar \n";
So einfach kann das sein. ;)

Edit2:
Mhh, ja, oder auch nicht. ;)
Das funktioniert irgendwie nicht, wenn $bar erst in eval definiert wird. Naja, vielleicht wissen da die Perl Juenger hier mehr drueber.

Edit3:
So, ich glaub ich habs jetzt.
Code:
#!/usr/bin/perl

use strict;

package hallo;
$hallo::foo = "bar";

eval {$hallo::{$hallo::foo} = 40;}; warn $@ if $@;
eval {print "$hallo::{$hallo::foo} \n";}; warn $@ if $@;
Perl ist schon ne komische Sprache.

mfg,
bytepool
 
Zuletzt bearbeitet:
Hallo,

mit anderen Worten, du versuchst metaprogramming in Perl

danke für den Tipp! Unter http://de.wikipedia.org/wiki/Reflection_%28Programmierung%29#Beispiel_in_Perl lernt man, dass diese Programmiermethode "reflection" genannt wird.

Und in dem Beispiel machen die auch fast genau das, wonach ich suche. Nur leider scheint es lediglich für Zugriffe ohne Variablentypkennzeichnung ($,%,@) zu funktionieren. Sprich, für alle Methodenaufrufe und Direktzugriffe von Klassen.

Code:
# funktioniert
$class = "ClassName";
$method = "eigenschaft1";
my $obj3 = $class->new(); # same as: my $obj3 = ClassName->new();
$obj3->$method; # same as: $obj3->eigenschaft1;

Ich glaube für den fehlenden Teil (Ersetzen des Objektnamens in der Deklaration und im Aufruf/Zugriff) brauchen wir (oder nur ich) einen der Perlgötter...

*weitergrübel*


Edit:
Danke Bytepool, während ich meinen Teil schrieb kam schon Dein Edit3... ;-)

Edit2: Und so geht das mit den Objekten (getestet, funktioniert)
Code:
my $test = "tralala";
eval {$main::{$test} = ClassName->new();};
    # Objekt "$tralala" erstellen
eval {$main::{$test}->name(objekt1);};
    # Methode setzt "name" von $tralala ...
eval {print "\$$test->name ";};
    # (Nur Ausgabe)
my $rets = eval {return $main::{$test}->extSPN;};
    # ...oder gibt "name" aus, wenn leer aufgerufen
print "$rets \n";
    # Ausgabe ist dann: > $tralala->name objekt1


$test = "trululu";
    # ändert namensgebenden string
eval {$main::{$test} = ClassName->new();};
    # erstellt neues Objekt "$trululu"
eval {$main::{$test}->name(objekt2);};
    # setzt namen von $trululu auf "objekt2"
eval {print "\$$test->name ";};
    # lediglich Ausgabe
$rets = eval {return $main::{$test}->name;};
    # Ausgabe $trululu->name
print "$rets \n";
    # Ausgabe ist dann: > $trululu->name objekt2


$test = "tralala";
    # zurücksetzen, damit wir schauen können, ob
    # das Objekt2 namens $tralala auch wirklich
    # noch existiert!
eval {print "\$$test->name ";};
    # Ausgabe...
$rets = eval {return $main::{$test}->name;};
    # ... des Namens
print "$rets \n";
    # Ausgabe ist dann : > $tralala->name objekt1

Jetzt müsste ich nur noch herausbekommen, wie man den Weg über den Packagenamen vermeidet...
 
Zuletzt bearbeitet:
Jetzt müsste ich nur noch herausbekommen, wie man den Weg über den Packagenamen vermeidet...

Der von mir derzeit eleganteste Weg mit einer dynamischen Anzahl von Objekten umzugehen, sieht nun so aus:

Code:
use ClassName

my @objekte;
my $cnt = 0;
my $ziel = 3;

while ($objectsAvailable) {
   $objekte[$cnt] = ClassName->new();
   $cnt++;
   }

$objekte[$ziel]->name("lalala");
print "Name of Obj \$ziel ($ziel): ".$objekte[$ziel]->name."\n";

Damit kann ich zwar nicht, wie ursprünglich gewünscht, die Objekte mit einem beliebigen Namen ansprechen, aber doch wenigstens *gezielt* und in Schleifen über die Gesamtzahl.
 
Damit kann ich zwar nicht, wie ursprünglich gewünscht, die Objekte mit einem beliebigen Namen ansprechen, aber doch wenigstens *gezielt* und in Schleifen über die Gesamtzahl.

Der Hash wäre dann wohl die bessere Datenstruktur:

Code:
use ClassName

my %objekte;
my $cnt = 0;

while ($objectsAvailable) {
   $objekte{ "Objekt" . $cnt } = ClassName->new();
   $cnt++;
}

$objekte{Objekt3}->name("lalala");
print "Name of Objekt3: " . $objekte{Objekt3}->name . "\n";
 

Ähnliche Themen

[Perl] Perl OO Methodenaufruf in anderem Objekt

Squid nur zum maskieren der eigenen IP, nicht für Webserver auf port 80

Zurück
Oben