You are here: Perldoc Web>PerlDokumentListe>Perlobj (2005-04-28)
perlobj Dokumentation | Download als POD | Wie kann ich hier etwas ändern?

NAME

perlobj - Objekte in Perl

BESCHREIBUNG

Zunächst sollten Sie Perls Referenzen verstehen. Siehe dazu perlref. Falls Sie das folgende Referenzwerk immer noch zu kompliziert finden, schauen Sie sich bitte die Tutorials in perltoot und perltooc an.

Falls Sie weiterlesen wollen, fangen wir mit den folgenden drei Definitionen an, die Sie als beruhigend empfinden sollten.

  1. Ein Objekt ist einfach eine Referenz, nur dass es weiß, welcher Klasse es angehört.

  2. Eine Klasse ist einfach ein Paket, nur dass sie Methoden bietet, um mit Objektreferenzen umzugehen.

  3. Eine Methode ist einfach eine Subroutine, die eine Objektreferenz (oder einen Paketnamen im Falle einer Klassenmethode) als erstes Argument erwartet.

Wir werden diese Punkte nun tiefergehend behandeln.

Ein Objekt ist einfach eine Referenz

Im Gegensatz zu z. B. C++ hat Perl keine spezielle Syntax für Konstruktoren. Vielmehr ist ein Konstruktor nur eine Subroutine, die eine Referenz auf eine in eine Klasse eingesegnete Referenz zurückgibt. (Anm. des Übersetzers: "segnen" entspricht engl. "to bless".) Normalerweise handelt es sich um diejenige Klasse, in der die Subroutine definiert ist. Ein Beispiel für einen typischen Konstruktor:

    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.

Eine Klasse ist einfach ein Paket

Im Gegensatz zu z. B. C++ hat Perl keine spezielle Syntax, um Klassen zu definieren. Um ein Paket als Klasse benutzen zu können, müssen Sie dort bloß Methoden definieren.

In einem Paket gibt es ein besonderes Array: @ISA (engl. "is a" = "ist ein"). Es besagt, wo Perl nach Methoden suchen soll, wenn sie in dem Paket selbst nicht gefunden werden. So wird in Perl Vererbung implementiert. Die Elemente von @ISA sind schlicht Namen von anderen Paketen, die ebenfalls Klassen sind. Diese Klassen werden in der Reihenfolge des Arrays nach fehlenden Methoden durchsucht (Tiefensuche). Die Klassen, die über @ISA erreichbar sind, nennen wir auch Basisklassen der aktuellen Klasse.

Alle Klassen erben implizit von der Klasse 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"}++;
    } 

Eine Methode ist einfach eine Subroutine

Im Gegensatz zu z. B. C++ hat Perl keine spezielle Syntax, um Methoden zu definieren. (Es hat allerdings eine kleine Syntaxhilfe zum Methodenaufruf, aber mehr dazu später.) Das erste Argument an eine Methode sollte das Objekt (Referenz) oder Package (String) sein, auf dass die Methode angewandt wird. Das legt nahe, dass es zwei verschiedene Arten gibt, eine Methode aufzurufen. Wir nennen sie Klassenmethoden und Instanzmethoden.

Eine Klassenmethode bekommt als erstes Argument einen Klassennamen. Ihre Funktionalität dient der Klasse als Ganzes. Konstruktoren sind meist Klassenmethoden (siehe jedoch perltoot und perltooc für Alternativen). Viele Klassenmethoden ignorieren ihr erstes Argument einfach, weil sie bereits wissen, in welcher Klasse sie definiert sind; und es ist ihnen egal, über welche Klasse sie aufgerufen wurden. (Das sind nicht notwendigerweise dieselben, weil Klassenmethoden wie auch gewöhnliche Instanzmethoden den Vererbungsbaum beachten.) Eine weitere häufige Anwendung für Klassenmethoden ist es, ein Objekt an Hand eines Namens nachzuschlagen:

    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";
        }
    }

Aufruf von Methoden

Aus verschiedensten historischen und anderen Gründen bietet Perl zwei gleichbedeutende Schreibweisen für einen Methodenaufruf. Die einfachere und verbreitetere ist die Pfeil-Schreibweise:

    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");

Indirect Object Syntax

Die andere Möglichkeit, eine Methode aufzurufen, ist die sogenannte "Indirect Object Syntax". Diese Notation gab es schon in Perl 4 lange bevor Objekte eingeführt wurden. Sie wird auch immer noch für Datei-Handles wie folgt benutzt:

   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.

Standardmethoden von UNIVERSAL

The UNIVERSAL package automatically contains the following methods that are inherited by all other classes:

isa(CLASS)

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(METHOD)

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( [NEED] )

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);

NOTE: 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).

Destructors

When the last reference to an object goes away, the object is automatically destroyed. (This may even be after you exit, if you've stored references in global variables.) If you want to capture control just before the object is freed, you may define a DESTROY method in your class. It will automatically be called at the appropriate moment, and you can do any extra cleanup you need to do. Perl passes a reference to the object under destruction as the first (and only) argument. Beware that the reference is a read-only value, and cannot be modified by manipulating $_[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.

Summary

That's about all there is to it. Now you need just to go off and buy a book about object-oriented design methodology, and bang your forehead with it for the next six months or so.

Two-Phased Garbage Collection

For most purposes, Perl uses a fast and simple, reference-based garbage collection system. That means there's an extra dereference going on at some level, so if you haven't built your Perl executable using your C compiler's -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.

SIEHE AUCH

Eine sanftere und lesefreundlichere Anleitung zum objektorientierten Programmieren in Perl können Sie in perltoot, perlboot und perltooc finden. Sie sollten sich ebenso perlbot für weitere Objekt-Tricks, -Fallen und -Tips ansehen, sowie perlmodlib für ein paar Style-Richtlinien beim Erstellen von Modulen und Klassen.

Zum Zeitpunkt dieser Übersetzung war mir jedoch keine Übersetzung eines dieser Dokumente bekannt.

ÜBERSETZER

Christoph Bußenius, perl-community.de; Herbst 2004


Kommentare:

-- HaraldBongartz - 29 Jun 2003
Topic attachments
I Attachment Action Size Date Who Comment
perlobj.podpod perlobj.pod manage 22.4 K 2005-04-09 - 12:45 ChristophBussenius Das ist die pod-Datei von perlobj
Topic revision: r8 - 2005-04-28 - 17:32:41 - HaraldBongartz
 
Bitte die NutzungsBedingungen beachten.
Bei Vorschlägen, Anfragen oder Problemen mit dem PerlCommunityWiki bitten wir um WebBottomBarExample">Rückmeldung.