| perlobj Dokumentation | Download als POD | Wie kann ich hier etwas ändern? |
Ein Objekt ist einfach eine Referenz, nur dass es weiß, welcher Klasse es angehört.
Eine Klasse ist einfach ein Paket, nur dass sie Methoden bietet, um mit Objektreferenzen umzugehen.
Eine Methode ist einfach eine Subroutine, die eine Objektreferenz (oder einen Paketnamen im Falle einer Klassenmethode) als erstes Argument erwartet.
package Kriechtier;
sub new { bless {} }
Das Wort new wird nicht besonders behandelt. Sie könnten ebenso schreiben:
package Kriechtier;
sub neu { bless {} }
Man könnte dies sogar als vorteilhafter betrachten, da C++-Programmierer nicht in die Versuchung kommen, zu denken, dass new in Perl dasselbe tut wie in C++. Denn so ist es nicht. Wir empfehlen, dass Sie Ihren Konstruktoren Namen geben, die im Zusammenhang mit ihrer Aufgabe Sinn machen; so wie die Konstruktoren der Perl-Tk-Erweiterung z.B. nach den Widgets heißen, die sie erzeugen.
Ein Unterschied zwischen Konstruktoren in C++ und Perl ist, dass sie in Perl selbst Speicher allozieren müssen. (Ein weiterer Punkt ist, dass sie nicht automatisch überschriebene Basisklassen-Konstruktoren aufrufen.) Das {} alloziert einen anonymen Hash, der noch keine Key/Value-Paare enthält. Diese Hash-Referenz wird als erstes Argument an bless() übergeben, wodurch dem referenzierten Objekt gesagt wird, dass es nun ein Kriechtier ist. Dann wird die Referenz von bless() zurückgegeben, was nur eine Erleichterung für den Programmierer darstellt; denn das referenzierte Objekt weiß, dass es gesegnet wurde, und man könnte die Referenz direkt zurückgeben:
sub new {
my $self = {};
bless $self;
return $self;
}
Man sieht so etwas oft in komplizierten Konstruktoren, die im Zuge der Konstruktion Methoden der Klasse aufrufen:
sub new {
my $self = {};
bless $self;
$self->initialisieren();
return $self;
}
Falls Sie Vererbung berücksichtigen möchten (und das sollten Sie, siehe L<perlmodlib/"Modules: Creation, Use and Abuse">), so benutzen Sie bitte bless() mit zwei Argumenten, damit Ihre Konstruktoren geerbt werden können:
sub new {
my $klasse = shift;
my $self = {};
bless $self, $klasse;
$self->initialisieren();
return $self;
}
Oder falls Sie befürchten, dass Nutzer Ihres Moduls nicht nur KLASSE->new() sondern auch $obj->new() aufrufen könnten, so benutzen Sie bitte das folgende Beispiel. Die initialisieren()-Methode wird in der $klasse aufgerufen, in die wir das Objekt eingesegnet haben:
sub new {
my $this = shift;
my $klasse = ref($this) || $this;
my $self = {};
bless $self, $klasse;
$self->initialisieren();
return $self;
}
Innerhalb des Klassenpaketes behandeln die Methoden die Referenz wie eine normale Referenz behandeln. Außerhalb des Klassenpaketes wird die Referenz normalerweise wie ein undurchsichtiges Objekt, auf das nur über die Methoden der Klasse zugegriffen werden kann, behandelt.
Obwohl ein Konstruktor theoretisch ein referenziertes Objekt, das schon einer anderen Klasse angehört, erneut segnen könnte, wird dies mit an Sicherheit grenzender Wahrscheinlichkeit Ärger bringen. Die neue Klasse ist für alle späteren Aufräumarbeiten verantwortlich. An die vorherige Segnung wird dabei nicht mehr gedacht, da ein Objekt nur einer Klasse gleichzeitig angehören kann. (Trotzdem ist es natürlich möglich, Methoden mehrerer anderer Klassen zu erben.) Falls Sie sich zum Umsegnen eines Objektes gezwungen fühlen, liegt das sicherlich an einer schlechten Implementation der vorherigen Klasse des Objektes.
Um Missverständnissen vorzubeugen: Objekte werden gesegnet; Referenzen nicht. Objekte wissen, zu welchem Paket sie gehören; Referenzen nicht. Die bless()-Funktion benutzt nur eine Referenz, um das Objekt zu finden. Betrachten sie dieses Beispiel:
$a = {};
$b = $a;
bless $a, BLAH;
print "\$b est ein ", ref($b), "\n";
Die Ausgabe wird berichten, dass $b ein BLAH ist. Also hat bless() offensichtlich auf das Objekt gewirkt, nicht auf die Referenz.
UNIVERSAL als der letzten Basisklasse. Einige oft benötigten Methoden werden automatisch von UNIVERSAL bereitgestellt, siehe dazu Standardmethoden von UNIVERSAL.
Wenn eine fehlende Methode in einer Basisklasse gefunden wird, so wird sie aus Effizienzgründen in der aktuellen Klasse gecacht. Der Cache wird jedoch entkräftigt, wenn @ISA verändert wird oder wenn neue Subroutinen definiert werden, sodass die Methodensuche ggf. erneut durchgeführt wird.
Wenn eine Methode weder in der aktuellen Klasse, ihren expliziten Basisklassen noch in UNIVERSAL gefunden wird, werden diese drei Orte noch einmal durchsucht, wobei dieses Mal nach einer Methode mit Namen AUTOLOAD() gesucht wird. Wenn eine solche gefunden wird, wird sie statt der fehlenden Methode aufgerufen, wobei die globale Paketvariable $AUTOLOAD auf den vollständig qualifizierten Namen der Methode gesetzt wird, die ursprünglich aufgerufen werden sollte.
Wenn das alles nicht funktioniert, gibt Perl auf und beschwert sich.
Wenn Sie den AUTOLOAD-Mechanismus außer Kraft setzen möchten, sagen Sie am Besten
sub AUTOLOAD;
sodass der Aufruf unter dem Namen der gewünschten Methode wie mit "die" abbrechen wird.
Perl-Klassen erben allein Methoden. Für Datenvererbung muss von der Klasse selbst gesorgt werden. In Perl ist das für gewöhnlich kein Problem, weil die meisten Klassen die Attribute ihrer Objekte mit Hilfe eines anonymen Hashes implementieren. Dieser Hash ist wie ein kleiner Namensraum für sich und wird von all den Klassen zusammengebastelt, die etwas mit dem Objekt anstellen wollen. Das einzige Problem dabei ist, dass man nicht sicher sein kann, dass man einen Hashkey benutzt, der nicht schon für etwas benutzt wird. Ein guter Ausweg ist es, den Namen des aktuellen Paketes vorne an den Feldnamen anzufügen:
sub erhoehen {
my $self = shift;
$self->{ __PACKAGE__ . ".zaehler"}++;
}
sub find {
my ($klasse, $name) = @_;
$objekttabelle{$name};
}
Eine Instanzmethode bekommt als erstes Argument eine Objektreferenz. Typischerweise shiftet sie ihr erstes Argument in eine "self"- oder "this"-Variable (engl. "this" = "dies", "self" = "selbst". Die Wörter werden nicht besonders behandelt, man könnte ebenso $selbst verwenden, aber das tut keiner), welche sie dann wie eine gewöhnliche Referenz benutzt.
sub anzeigen {
my $self = shift;
my @keys = @_ ? @_ : sort keys %$self;
foreach $key (@keys) {
print "\t$key => $self->{$key}\n";
}
}
my $fred = Kriechtier->find("Fred");
$fred->anzeigen("Groesse", "Gewicht");
Sie sollten mit dem Gebrauch von dem -> -Operator für Referenzen bereits vertraut sein. Da $fred im obigen Beispiel eine Referenz auf ein Objekt ist, können Sie sich tatsächlich einen Methodenaufruf als eine weitere Form des Dereferenzierens vorstellen.
Das, was auf der linken Seite des Pfeiles steht, wird der Methoden-Soubroutine als erstes Argument gegeben, ob es nun ein Klassenname oder eine Referenz ist. Der obige Code ist also fast das Gleiche wie:
my $fred = Kriechtier::find("Kriechtier", "Fred");
Critter::anzeigen($fred, "Groesse", "Gewicht");
Woher weiß Perl, in welchem Paket die Subroutine ist? Indem es auf die linke Seite von dem Pfeil schaut, die entweder ein Paketname sein muss oder eine Referenz auf ein Objekt, also etwas, das in ein Paket eingesegnet wurde. In beiden Fällen ist dies nur der Anfang von Perls Suche nach der Subroutine. Wenn sie dort nicht gefunden wird, sucht Perl in den Basisklassen weiter, etc.
Wenn Sie müssen, können Sie Perl sagen, dass es in einem anderen Paket mit der Suche beginnen soll:
my $barney = MeinKriechtier->Kriechtier::find("Barney");
$barney->Kriechtier::anzeigen("Groesse", "Gewicht");
Dabei ist MeinKriechtier vermutlich eine Unterklasse von Kriechtier , die ihre eigenen Versionen von find() und anzeigen() hat. Wir haben nicht angegeben, was diese Methoden tun. Aber das macht nichts, da wir Perl gezwungen haben, in Kriechtier anzufangen, sie zu suchen.
Sie können auch die Pseudoklasse SUPER angeben, damit Perl die Methodensuche in den Paketen aus dem Array @ISA der aktuellen Klasse beginnt.
package MeinKriechtier;
use base 'Kriechtier'; # setzt @MyKriechtier::ISA = ('Kriechtier');
sub anzeigen {
my ($self, @args) = @_;
$self->SUPER::anzeigen("Name", @args);
}
Statt einem Klassennamen oder einer Objektreferenz können Sie auf der linken Seite des Pfeils auch einen Ausdruck schreiben, der eines der beiden zurückgibt. Ein Kriechtier-Beispiel dafür ist:
Kriechtier->find("Fred")->anzeigen("Groesse", "Gewicht");
oder:
my $fred = (reverse "reithceirK")->find(reverse "derF");
print STDERR "Hilfe!!!\n";Dieselbe Syntax kann auch benutzt werden, um Klassen- oder Instanzmethoden aufzurufen:
my $fred = find Kriechtier "Fred"; anzeigen $fred "Groesse", "Gewicht";Beachten Sie, dass kein Komma zwischen dem Objekt oder Klassennamen und den Parametern steht. Wäre es anders, könnte Perl nicht zwischen einem indirekten Methodenaufruf und einem gewöhnlichen Subroutinenaufruf unterscheiden. Was ist aber, wenn es keine weiteren Argumente gibt? In dem Fall muss Perl raten, was Sie wollen. Es muss es sogar schon beim Kompilieren erraten. Meist liegt Perl dann mit der Antwort richtig, aber es treten auch Fälle auf, wo Perl sich irrt und Ihr Funktionsaufruf als Methode kompiliert wird oder umgekehrt. Dies kann hinterhältige Bugs zur Folge haben, die schwer zu finden sind. Zub Beispiel könnte ein Methodenaufruf von
new in der indirekten Notation -- wie C++-Programmierer es gerne machen -- fälschlicherweise als ein Subroutinenaufruf kompiliert werden, sofern der Ausdruck im Geltungsbereich einer Subroutinendefinition mit Namen new steht. Das Resultat wäre, dass statt dem new der gewünschten Klasse die Subroutine im aktuellen Paket aufgerufen wird. Der Compiler versucht zwar zu schummeln, indem er sich require s mit Barewords merkt; aber der Kummer, wenn es schief geht, ist wirklich nicht das jahrelange Fehlersuchen nach solchen hinterhältigen Bugs wert.
Es gibt noch ein weiteres Problem mit dieser Syntax: Das indirekte Objekt darf nur ein Name, eine skalare Variable oder ein Block sein. XXX TODO: because it would have to do too much lookahead otherwise, just like any other postfix dereference in the language. (Dieselben eigenwilligen Regeln gelten für die Daheihandle-Übergabe an Funktionen wie print und printf .) Das kann zu fürchterlich verwirrenden Problemen bezüglich der Operatoren-Rangfolge kommen, wie diese Zeilen illustrieren:
move $obj->{FELD}; # wahrscheinlich falsch!
move $ary[$i]; # wahrscheinlich falsch!
Überraschenderweise werden sie nämlich wie folgt ausgewertet:
$obj->move->{FELD}; # Schau mal einer an
$ary->move([$i]); # Das haben Sie nicht erwartet, oder?
Wahrscheinlich hätten Sie dies erwartet:
$obj->{FELD}->move(); # So ein Glück sollten Sie haben.
$ary[$i]->move; # Ja, wirklich.
Um mit Indirect Object Syntax das richtige Verhalten zu erreichen, müssten Sie das indirekte Objekt in einen Block tun:
move {$obj->{FELD}};
move {$ary[$i]};
Even then, you still have the same potential problem if there happens to be a function named move in the current package. The =- = notation suffers from neither of these disturbing ambiguities, so we recommend you use it exclusively.> However, you may still end up having to read code using the indirect object notation, so it's important to be familiar with it.
UNIVERSAL package automatically contains the following methods that are inherited by all other classes:
isa returns true if its object is blessed into a subclass of CLASS
You can also call UNIVERSAL::isa as a subroutine with two arguments. The first does not need to be an object or even a reference. This allows you to check what a reference points to, or whether something is a reference of a given type. Example
if(UNIVERSAL::isa($ref, 'ARRAY')) {
#...
}
To determine if a reference is a blessed object, you can write
print "It's an object\n" if UNIVERSAL::isa($val, 'UNIVERSAL');
can checks to see if its object has a method called METHOD , if it does then a reference to the sub is returned, if it does not then undef is returned.
UNIVERSAL::can can also be called as a subroutine with two arguments. It'll always return undef if its first argument isn't an object or a class name. So here's another way to check if a reference is a blessed object
print "It's still an object\n" if UNIVERSAL::can($val, 'can');
You can also use the blessed function of Scalar::Util:
use Scalar::Util 'blessed';
my $blessing = blessed $suspected_object;
blessed returns the name of the package the argument has been blessed into, or undef .
VERSION returns the version number of the class (package). If the NEED argument is given then it will check that the current version (as defined by the $VERSION variable in the given package) not less than NEED; it will die if this is not the case. This method is normally called as a class method. This method is called automatically by the VERSION form of use .
use A 1.2 qw(some imported subs);
# implies:
A->VERSION(1.2);
can directly uses Perl's internal code for method lookup, and isa uses a very similar method and cache-ing strategy. This may cause strange effects if the Perl code dynamically changes @ISA in any package.
You may add other methods to the UNIVERSAL class via Perl or XS code. You do not need to use UNIVERSAL to make these methods available to your program (and you should not do so).
$_[0] within the destructor. The object itself (i.e. the thingy the reference points to, namely ${$_[0]} , @{$_[0]} , %{$_[0]} etc.) is not similarly constrained.
If you arrange to re-bless the reference before the destructor returns, perl will again call the DESTROY method for the re-blessed object after the current one returns. This can be used for clean delegation of object destruction, or for ensuring that destructors in the base classes of your choosing get called. Explicitly calling DESTROY is also possible, but is usually never needed.
Do not confuse the previous discussion with how objects CONTAINED in the current one are destroyed. Such objects will be freed and destroyed automatically when the current object is freed, provided no other references to them exist elsewhere.
-O flag, performance will suffer. If you have built Perl with cc -O , then this probably won't matter.
A more serious concern is that unreachable memory with a non-zero reference count will not normally get freed. Therefore, this is a bad idea:
{
my $a;
$a = \$a;
}
Even thought $a should go away, it can't. When building recursive data structures, you'll have to break the self-reference yourself explicitly if you don't care to leak. For example, here's a self-referential node such as one might use in a sophisticated tree structure:
sub new_node {
my $self = shift;
my $class = ref($self) || $self;
my $node = {};
$node->{LEFT} = $node->{RIGHT} = $node;
$node->{DATA} = [ @_ ];
return bless $node => $class;
}
If you create nodes like that, they (currently) won't go away unless you break their self reference yourself. (In other words, this is not to be construed as a feature, and you shouldn't depend on it.)
Almost.
When an interpreter thread finally shuts down (usually when your program exits), then a rather costly but complete mark-and-sweep style of garbage collection is performed, and everything allocated by that thread gets destroyed. This is essential to support Perl as an embedded or a multithreadable language. For example, this program demonstrates Perl's two-phased garbage collection:
#!/usr/bin/perl
package Subtle;
sub new {
my $test;
$test = \$test;
warn "CREATING " . \$test;
return bless \$test;
}
sub DESTROY {
my $self = shift;
warn "DESTROYING $self";
}
package main;
warn "starting program";
{
my $a = Subtle->new;
my $b = Subtle->new;
$$a = 0; # break selfref
warn "leaving block";
}
warn "just exited block";
warn "time to die...";
exit;
When run as /tmp/test , the following output is produced:
starting program at /tmp/test line 18.
CREATING SCALAR(0x8e5b8) at /tmp/test line 7.
CREATING SCALAR(0x8e57c) at /tmp/test line 7.
leaving block at /tmp/test line 23.
DESTROYING Subtle=SCALAR(0x8e5b8) at /tmp/test line 13.
just exited block at /tmp/test line 26.
time to die... at /tmp/test line 27.
DESTROYING Subtle=SCALAR(0x8e57c) during global destruction.
Notice that "global destruction" bit there? That's the thread garbage collector reaching the unreachable.
Objects are always destructed, even when regular refs aren't. Objects are destructed in a separate pass before ordinary refs just to prevent object destructors from using refs that have been themselves destructed. Plain refs are only garbage-collected if the destruct level is greater than 0. You can test the higher levels of global destruction by setting the PERL_DESTRUCT_LEVEL environment variable, presuming -DDEBUGGING was enabled during perl build time. See perlhack, PERL_DESTRUCT_LEVEL for more information.
A more complete garbage collection strategy will be implemented at a future date.
In the meantime, the best solution is to create a non-recursive container class that holds a pointer to the self-referential data structure. Define a DESTROY method for the containing object's class that manually breaks the circularities in the self-referential structure.
| I | Attachment | Action | Size | Date | Who | Comment |
|---|---|---|---|---|---|---|
| |
perlobj.pod | manage | 22.4 K | 2005-04-09 - 12:45 | ChristophBussenius | Das ist die pod-Datei von perlobj |