1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<title>SELFHTML: Perl / Perl-Sprachelemente / Objektorientiertes Programmieren</title>
<link rel="stylesheet" type="text/css" href="../../src/selfhtml.css">
<meta name="description" content="Was objektorientierte Programmierung auszeichnet, und wie sie in Perl funktioniert.">
<meta name="keywords" content="SELFHTML, Perl, OOP, objektorientierte Programmierung, Objekte, Klassen, Instanzen, Eigenschaften, Methoden, Objekteigenschaften, Objektdaten, Konstruktorfunktion, Destruktorfunktion">
<meta name="author" content="Redaktion SELFHTML, selfhtml81@selfhtml.org">
<meta name="robots" content="noindex, nofollow">
<meta name="DC.Publisher" content="SELFHTML e. V.">
<meta name="DC.Date" content="2005-11-09T00:29:27+01:00">
<meta name="DC.Identifier" content="http://de.selfhtml.org/perl/sprache/objekte.htm">
<meta name="DC.Language" content="de">
<meta name="DC.Rights" content="../../editorial/copyright.htm">
<meta name="DC.Date.created" content="2001-10-27T08:00+01:00">
<meta name="SELF.Pagetype" content="page">
<link rel="alternate" type="application/atom+xml" title="SELFHTML-Weblog (Atom, gesamt)" href="http://aktuell.de.selfhtml.org/weblog/atom-feed">
<link rel="alternate" type="application/rss+xml" title="SELFHTML-Weblog (RSS, Auszge)" href="http://aktuell.de.selfhtml.org/weblog/rss-feed">
<link rel="shortcut icon" type="image/x-icon" href="../../src/favicon.ico">
<link rel="author" title="Impressum" href="../../editorial/impressum.htm">
<link rel="contents" title="Inhaltsverzeichnis" href="../../navigation/inhalt.htm">
<link rel="index" title="Stichwortverzeichnis" href="../../navigation/stichwort.htm">
<link rel="search" title="Suche" href="../../navigation/suche/index.htm">
<link rel="help" title="Hilfe" href="../../editorial/index.htm">
<link rel="copyright" title="Urheberrecht" href="../../editorial/copyright.htm">
<link rel="top" title="SELFHTML" href="../../index.htm">
<link rel="up" title="Perl-Sprachelemente" href="index.htm">
<link rel="next" title="CGI-typische Aufgaben in Perl" href="cgitypisch.htm">
<link rel="prev" title="Tokens" href="tokens.htm">
<link rel="first" title="CGI-notwendige Anweisungen in Perl" href="cginotwendig.htm">
<link rel="last" title="CGI-typische Aufgaben in Perl" href="cgitypisch.htm">
</head>
<body>
<table cellpadding="4" cellspacing="0" border="0" width="100%">
<tr>
<td colspan="2" class="nav"><a class="an" name="top"><img src="../../src/refkap.gif" width="16" height="13" alt="Teil von"></a> <a href="../../index.htm">SELFHTML</a>/<a href="../../navigation/index.htm" target="_parent" class="navh">Navigationshilfen</a> <img src="../../src/refkap.gif" width="16" height="13" alt="Teil von"> <a href="../index.htm">Perl</a> <img src="../../src/refkap.gif" width="16" height="13" alt="Teil von"> <a href="index.htm">Perl-Sprachelemente</a></td>
</tr>
<tr>
<td class="doc" width="110"><a href="../../index.htm"><img src="../../src/logo.gif" width="106" height="109" border="0" alt="SELFHTML"></a></td>
<td class="docbot" width="100%"><h1 class="ph1">Objektorientiertes Programmieren</h1></td>
</tr>
<tr>
<td class="doctop">
<img src="../../src/dokx.gif" width="30" height="20" vspace="6" alt="Informationsseite">
</td>
<td valign="top" nowrap="nowrap">
<p>
<img src="../../src/down.gif" width="14" height="10" alt="nach unten"> <a href="#oop">Objektorientierte Programmierung (OOP)</a><br>
<img src="../../src/down.gif" width="14" height="10" alt="nach unten"> <a href="#oop_perl">Objektorientierte Programmierung in Perl</a><br>
<img src="../../src/down.gif" width="14" height="10" alt="nach unten"> <a href="#htmlprint_beispiel">Einfaches Beispiel: das HTMLprint-Objekt</a><br>
<img src="../../src/down.gif" width="14" height="10" alt="nach unten"> <a href="#vcard_beispiel">Beispiel mit Objektdaten: das VCard-Objekt</a><br>
</p>
</td>
</tr><tr><td colspan="2" class="doc"> <a href="#bottom"><img src="../../src/down.gif" width="14" height="10" border="0" alt="nach unten"></a> </td></tr>
</table>
<h2><a class="an" name="oop">Objektorientierte Programmierung (OOP)</a></h2>
<p>Vor allem bei greren Programmiervorhaben ist es wichtig, nicht einfach draufloszuprogrammieren, sondern sich vorher darber Gedanken zu machen, was die Anwendung knnen, in welcher Form sie Daten speichern soll, welche Benutzerschnittstellen erforderlich sind usw. In dieser Phase ist es gar nicht wichtig und eher hinderlich, dauernd irgendwelche Quellcode-Fetzen im Kopf zu haben. Besser ist es, vom natrlichen Denken ausgehend die Anwendung zu modellieren.</p>
<p>Das natrliche Denken des modernen Menschen ist aber nicht so "prozedural" ausgerichtet wie die klassische Programmierung. Es vollzieht sich nicht in Sprungadressen und Kontrollstrukturen, sondern wird an grere eigenstndige Einheiten (Menschen, Maschinen usw.), die in der Lage sind, Informationen und Fhigkeiten beizusteuern, miteinander zu kommunizieren und dadurch etwas Neues zu schaffen, gebunden.</p>
<p>Auch ein CGI-basiertes Gstebuch lsst sich so denken. Da gibt es beispielsweise einen Formular-Manager, der sich um die Auswertung ausgefllter HTML-Formulare kmmert, einen Daten-Manager, dessen Aufgabe das zuverlssige und einheitliche Speichern und Einlesen von Daten ist, und einen Konfigurations-Manager, der entscheidet, welche Mglichkeiten des Gstebuchs im konkreten Fall genutzt werden und in welcher Form. Dabei muss der Konfigurations-Manager beispielsweise den Daten-Manager um das Einlesen bestimmter Konfigurationsdaten bitten. Selber darf er das nicht, das ist nun mal Aufgabe des Daten-Managers. Genausowenig darf der Daten-Manager sich einfach die HTML-Formulare holen, die vom Anwender abgesendet wurden. Dafr ist der Formular-Manager zustndig, der dann vielleicht wieder beim Konfigurations-Manager nachfragen muss, wie die Daten weiterzugeben sind, und der Antwort entsprechend die Daten an den Daten-Manager zum Abspeichern weitergibt.</p>
<p>Solche teamfhigen Einheiten werden in der objektorientierten Programmierung als Objekte bezeichnet. Ein Objekt hat Eigenschaften und kann etwas tun. Einige der Eigenschaften und Fhigkeiten stammen von anderen Objekten, die das Objekt selbst eingebunden und damit geerbt hat, und andere wiederum sind ganz eigene und besondere Eigenschaften und Fhigkeiten dieses Objekts.</p>
<p>Diese Dokumentation ist allerdings nicht der Rahmen, um die Theorie der objektorientierten Programmierung auszubreiten. Ein paar wichtige Begriffe sollten Sie trotzdem kennen:</p>
<p><strong>Klasse:</strong><br>
Eine Klasse ist die Summe der programmierten Fhigkeiten eines Objekts. Alles, woraus ein Objekt besteht und was es kann, muss irgendwo programmiert sein. Eine Klasse ist aber "abstrakt" programmiert, sie fhrt noch keinen konkreten Code aus. So wie man, wenn man an "Handy" denkt, einen bestimmten Begriff von so einem Gert hat, ist ein konkretes Objekt in der objektorientierten Programmierung nur von seiner Klasse ableitbar. Ein konkretes Objekt hat die Eigenschaften und Fhigkeiten seiner Klasse, so wie man von einem Handy, den man in der Hand hat, sagt, dass es ein Handy ist, weil er die Eigenschaften und Funktionen eines Handys hat, also dem Begriff des Handys entspricht. In einer objektorientierten Anwendung knnen Sie sagen: fr die Aufgabe, die ich lsen mchte, brauche ich erst mal eine bestimmte Klasse, so wie man sagen knnte: fr diese Aufgabe brauche ich einen Handy.</p>
<p><strong>Instanz:</strong><br>
Eine Instanz ist ein konkretes Objekt einer bestimmten Klasse. Mit dem Begriff vom Handy allein knnen Sie noch keine Aufgaben lsen. Sie brauchen ein ganz reales Handy dazu. Genauso brauchen Sie eine ganz reale Instanz einer Klasse, um eine Aufgabe innerhalb Ihrer Anwendung objektorientiert anzupacken. Ihr konkretes Objekt erhlt einen individuellen Namen, unter dem Sie es ansprechen knnen.</p>
<p><strong>Eigenschaften und Methoden:</strong><br>
Von einer Objektinstanz knnen Sie nicht mehr verlangen als das, wozu das Objekt aufgrund seiner Klasse in der Lage ist. Das, wozu ein Objekt in der Lage ist, ist dadurch festgelegt, was in seiner Klasse programmiert ist. Eigenschaften (auch Attribute genannt) sind Variablen, die Ihnen zur Verfgung stehen, wenn Sie eine Instanz eines Objekts erzeugt haben. Methoden sind Funktionen, die Ihnen eine Objektinstanz zur Verfgung stellt. Eine Instanz der Klasse "Formular-Manager" knnte beispielsweise als Eigenschaft eine Datenstruktur anbieten, in der sie eingelesene Formulardaten bequem zur Verfgung stellt. Als Methoden knnte diese Instanz zum Beispiel Filterfunktionen enthalten, um etwa nur die Daten aus versteckten Formularfeldern anzubieten. In Ihrer Anwendung knnen Sie dann Eigenschaften und Methoden verwenden, indem Sie auf deren Namen innerhalb einer konkreten Instanz "zeigen". Das ist so, als ob Sie an dem Laptop, den Sie vor sich haben, die Funktion "suche den nchsten ausreichend starken WLAN-Hotspot" anstoen (eine Methode) und bei gefundenem Hotspot am Display dessen Standort ablesen knnen (eine Eigenschaft).</p>
<p><strong>Konstruktor- und Destruktor-Funktion:</strong><br>
Eine Konstruktorfunktion bernimmt die Handlung, eine Instanz eines Objektes zu erzeugen. Sie macht gewissermaen aus dem Begriff von einem Handy ein reales Handy. Nun sind Sie damit unterwegs, und irgendwann brauchen Sie das Handy nicht mehr. Dann ist es nur unntiges Gepck. Deshalb knnen Sie es dann abschalten. Zumindest im Computer ist das sinnvoll, denn dadurch werden wieder Speicher-Ressourcen frei. Zum Abschalten (Zerstren) von Objektinstanzen gibt es daher eine Destruktor-Funktion.</p>
<p class="doc"><a href="#top"><img src="../../src/up.gif" width="14" height="10" border="0" alt="nach oben"></a><a href="#bottom"><img src="../../src/down.gif" width="14" height="10" border="0" alt="nach unten"></a></p>
<h2><a class="an" name="oop_perl">Objektorientierte Programmierung in Perl</a></h2>
<p>Der Perl-Interpreter untersttzt objektorientiertes Programmieren seit der Version 5.0. Um eine Klasse zu programmieren, also das, wovon sich eine Objektinstanz ableiten lsst, brauchen Sie in Perl ein eigenes <strong>Package</strong>, also einen eigenen Namensraum. <img src="../../src/dok.gif" width="15" height="10" alt="Seite"> <a href="subroutinen.htm">Subroutinen</a>, die innerhalb des Packages notiert sind, sind die Methoden von Objekten dieser Klasse. Auch Objekteigenschaften knnen Sie innerhalb solcher Methoden auf bestimmte Weise definieren. Packages lassen sich zwar auch innerhalb eines Perl-Scripts definieren (siehe Beispiel zur Perl-Funktion <img src="../../src/dok.gif" width="15" height="10" alt="Seite"> <a href="../funktionen/module.htm#package">package</a>), aber im Normalfall ist ein Package eine separate Perl-Datei, die keine andere Aufgabe hat als die, in Perl-Scripts "eingebunden" zu werden. Kurzum: ein Package ist in Perl meist ein <img src="../../src/kap.gif" width="15" height="13" alt="Kapitel"> <a href="../module/index.htm">Modul</a> mit der entsprechenden Dateiendung <code>.pm</code>. Von daher haben in Perl modul-orientiertes Programmieren und objektorientiertes Programmieren viel miteinander zu tun.</p>
<p>Ein Package ist allerdings noch nicht automatisch eine Klasse fr Objekte. Packages sind lediglich Namensrume und damit das "Klima, in dem Objektklassen gedeihen knnen". Damit Perl eine Klasse fr Objekte als solche erkennt, muss sie als solche definiert und erstellt werden.</p>
<p>Ebenso ist es mit den Objektinstanzen. Zunchst mssen Sie Perl mitteilen, dass Sie eine Instanz eines Objekts erzeugen mchten. Ist das gelungen, knnen Sie anschlieend Eigenschaften und Methoden dieses Objekts ber eine bestimmte Syntax ansprechen.</p>
<h3 class="inf">Beachten Sie:</h3>
<p>Perl bietet auch weitere Features der objektorientierten Programmierung an, etwa Vererbung und Methodenbindung an Variablen. In diesem einfhrenden Abschnitt werden solche weiteren Features jedoch nicht behandelt.</p>
<p class="doc"><a href="#top"><img src="../../src/up.gif" width="14" height="10" border="0" alt="nach oben"></a><a href="#bottom"><img src="../../src/down.gif" width="14" height="10" border="0" alt="nach unten"></a></p>
<h2><a class="an" name="htmlprint_beispiel">Einfaches Beispiel: das HTMLprint-Objekt</a></h2>
<p>In diesem Beispiel wird gezeigt, wie Sie ein Modul als Objektklasse erstellen, in einem Perl-Script eine Instanz dieses Objekts erzeugen und mit Methoden des Objekts arbeiten. Das Beispiel realisiert ein einfaches Objekt fr HTML-Ausgaben.</p>
<h3 class="xmp">Beispiel der Moduldatei <var>HTMLprint.pm</var>:</h3>
<pre>
package HTMLprint;
sub new {
my $Objekt = shift;
my $Referenz = {};
bless($Referenz,$Objekt);
return($Referenz);
}
sub Anfang {
my $Objekt = shift;
my $Titel = shift;
print "Content-type: text/html\n\n";
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
print "<html><head><title>$Titel</title></head><body>\n";
}
sub Titel {
my $Objekt = shift;
my $Ausgabetext = shift;
print "<h1>$Ausgabetext</h1>\n";
}
sub Text {
my $Objekt = shift;
my $Ausgabetext = shift;
print "<p>$Ausgabetext</p>\n";
}
sub Ende {
my $Objekt = shift;
print "</body></html>\n";
}
1;
</pre>
<h3 class="xmp"><a class="an" name="beispiel">Beispiel eines vollstndigen CGI-Scripts in Perl:</a></h3>
<p><img src="../../src/dokf.gif" width="15" height="10" alt="Beispiel-Seite"> <a href="http://de.selfhtml.org/cgi-bin/812/objekte.pl">Anzeigebeispiel: So sieht's aus</a> (Zum Aufruf des Scripts ist eine Internet-Verbindung erforderlich)</p>
<pre>
#!/usr/bin/perl -w
use strict;
use CGI::Carp qw(fatalsToBrowser);
use HTMLprint;
my $html = HTMLprint -> new();
$html->Anfang("Ganz elegantes Perl");
$html->Titel("Ganz elegantes Perl");
$html->Text("Popeliges HTML, aber sehr modern programmiert!");
$html->Ende();
</pre>
<h3 class="xpl">Erluterung:</h3>
<p>Die Moduldatei beginnt einfach mit einer <img src="../../src/dok.gif" width="15" height="10" alt="Seite"> <a href="../funktionen/module.htm#package">package</a>-Anweisung, die den Namen des Moduls nennt. Der Name sollte identisch mit dem Vornamen der Moduldatei sein. Wenn die Moduldatei also wie im Beispiel <var>HTMLprint.pm</var> heit, sollte die Anweisung <code>package HTMLprint;</code> lauten.</p>
<p>Die Moduldatei im Beispiel enthlt insgesamt fnf Subroutinen. Die erste davon ist die Konstruktorfunktion. Sie erhlt blicherweise den Namen <code>new</code>, knnte aber theoretisch auch einen anderen Namen erhalten. Wie eine Konstruktorfunktion aufgebaut ist, kann von Fall zu Fall variieren. In jedem Fall muss die Konstruktorfunktion jedoch einen Aufruf der Funktion <code>bless</code> enthalten. Diese bindet eine Referenz (einen Zeiger) an eine Klasse, sodass anschlieend ber diese Referenz auf das Objekt zugegriffen werden kann. Die im obigen Beispiel gezeigte Konstruktorfunktion leistet zwar schon ein wenig mehr als fr das Beispiel bentigt wird, doch sie eignet sich in dieser Form einfach gut als Standard-Konstruktorfunktion, bei der man wenig falsch machen kann.</p>
<p>Mit <code>my $Objekt = shift;</code> wird einfach der erste Parameter eingelesen, den die Konstruktorfunktion <code>new</code> bergeben bekommt. Sie bekommt nmlich, wenn sie aufgerufen wird, automatisch als ersten Parameter den Klassennamen bergeben, im Beispiel also den Namen <code>HTMLprint</code>. Das ist im Beispiel der Wert, der anschlieend in <code>$Objekt</code> steht.<br>
Mit <code>my $Referenz = {};</code> wird eine <img src="../../src/dok.gif" width="15" height="10" alt="Seite"> <a href="referenzen.htm">Referenz</a>, also ein Zeiger deklariert. Dieser Zeiger wird bentigt, damit die Funktion <code>bless</code> korrekt bedient werden und den Zeiger an das Objekt binden kann. Nun ist die Frage, wie aus der skalaren Variable <code>$Referenz</code> eine Referenz werden soll. Sie muss sich ja auf irgendetwas beziehen, worauf sie zeigt. Ideal ist fr diesen Zweck die Zuweisung <code>{}</code>. Dies ist einfach eine Referenz auf einen leeren unbenannten <img src="../../src/dok.gif" width="15" height="10" alt="Seite"> <a href="hashes.htm">Hash</a>. Ideal ist das deshalb, weil dieser Hash auch fr die Definition von Objektdaten geeignet ist - was allerdings in diesem ersten einfachen Beispiel noch nicht geschieht. So bleibt es bei dem leeren Hash, und <code>$Referenz</code> ist ein Zeiger.<br>
Mit <code>bless($Referenz,$Objekt);</code> wird die ntige Verbindung zwischen Referenz und Objekt hergestellt. Anschlieend wird <code>$Referenz</code> zurckgegeben.</p>
<p>Die vier brigen Subroutinen in der Moduldatei <var>HTMLprint.pm</var> sind sich alle recht hnlich. Sie erzeugen mit Hilfe von <code>print</code>-Anweisungen HTML-Code. Die Subroutine <code>Anfang</code> schreibt zudem zunchst den ntigen HTTP-Header fr HTML-Ausgaben.</p>
<p>Fr alle Subroutinen, die als Methoden eines Objekts fungieren, gilt: sie bekommen automatisch mindestens einen Parameter bergeben, und zwar den Zeiger auf das Objekt, der in der Konstruktor-Funktion erzeugt und an das Objekt gebunden wurde. Die Subroutinen im Beispiel bentigen diesen Zeiger nicht. Aber <code>Anfang</code>, <code>Titel</code> und <code>Text</code> erwarten noch einen zweiten ganz gewhnlichen Parameter, nmlich den Inhalt, den sie in HTML ausgeben sollen. Nun knnten sich die Routinen den Inhalt dieses zweiten Parameters auch direkt mit <code>$_[1]</code> holen. Aber die Notation mit dem Aufruf der <code>shift</code>-Funktion hat den Vorteil, dass die Parameterliste dabei sauber abgearbeitet und der Reihe nach gelscht wird. Mit dem jeweils zweiten Aufruf von <code>shift</code> kommen die drei erwhnten Subroutinen also an den zweiten Parameter.</p>
<p>Wichtig zu erwhnen ist noch, dass <var>pm</var>-Moduldateien am Ende stets eine einsame Anweisung <code>1;</code> (oder etwas hnliches) enthalten mssen. Das bedeutet, die Moduldatei gibt einen wahren Wert zurck. Andernfalls wrde der Perl-Interpreter einen Fehler melden.</p>
<p>Das eigentliche Perl-Script ist im Beispiel recht einfach. Mit der Funktion <img src="../../src/dok.gif" width="15" height="10" alt="Seite"> <a href="../funktionen/module.htm#use">use</a> und der Anweisung <code>use HTMLprint;</code> bindet es die Moduldatei <var>HTMLprint.pm</var> ein. In dieser Form eingebunden, muss sich die <var>HTMLprint.pm</var> entweder im gleichen Verzeichnis befinden wie das Script, oder in einem der zentralen Verzeichnisse, in denen Perl nach Modulen sucht (mehr darber im Abschnitt <img src="../../src/dok.gif" width="15" height="10" alt="Seite"> <a href="../module/intro.htm#speicherorte_inc">Speicherorte fr Module und die Liste @INC</a>).</p>
<p>Mit <code>my $html = HTMLprint -> new();</code> wird die Konstruktorfunktion der Moduldatei aufgerufen. Dies ist die entscheidende Anweisung, mit der eine neue Istanz des HTMLprint-Objekts erzeugt wird! Die Anweisung besteht darin, dass ein Skalar, der im Beispiel den Namen <code>$html</code> erhlt, deklariert und mit einem Wert initialisiert wird. Der zugewiesene Wert besteht darin, dass der Name der gewnschten Objektklasse, also <code>HTMLprint</code>, mit Hilfe des Zeigeoperators <code>-></code> auf die Konstruktorfunktion <code>new</code> zeigt. Da die Konstruktorfunktion eine Referenz zurckgibt, die durch den <code>bless</code>-Aufruf an das Objekt gebunden ist, wird <code>$html</code> automatisch zu einer Referenz, also zu einem Zeiger auf die neu erzeugte Objektinstanz. ber <code>$html</code> und den Zeigeoperator <code>-></code> kann das Script fortan auf die Subroutinen des eingebundenen Moduls zugreifen. Im Objektzusammenhang spricht man allerdings nicht mehr von Subroutinen, sondern von Methoden.<br>
Mit einer Anweisung wie <code>$html->Anfang("Ganz elegantes Perl");</code> greift das Script also auf eine Methode des <code>HTMLprint</code>-Objekts zu, und zwar auf die Objektinstanz, die an den Zeiger <code>$html</code> gebunden ist.</p>
<p class="doc"><a href="#top"><img src="../../src/up.gif" width="14" height="10" border="0" alt="nach oben"></a><a href="#bottom"><img src="../../src/down.gif" width="14" height="10" border="0" alt="nach unten"></a></p>
<h2><a class="an" name="vcard_beispiel">Beispiel mit Objektdaten: das VCard-Objekt</a></h2>
<p>Das folgende Beispiel zeigt, wie sich Daten mit Objekten verwalten lassen. Es handelt sich dabei um Adressdaten im international standardisierten <img src="../../src/de.gif" width="16" height="10" alt="deutschsprachige Seite"> <a target="_top" href="http://de.wikipedia.org/wiki/VCard">VCard-Format</a> (typische Dateiendung: *.vcf), wie es vom <img src="../../src/en.gif" width="16" height="10" alt="englischsprachige Seite"> <a target="_top" href="http://www.imc.org/">Internet Mail Consortium (IMC)</a> entwickelt und in der <img src="../../src/en.gif" width="16" height="10" alt="englischsprachige Seite"> <a target="_top" href="http://tools.ietf.org/html/rfc2426">RFC 2426</a> beschrieben wird. In der Moduldatei <var>VCard.pm</var> wird die VCard-Klasse mit den Objektdaten und Methoden definiert. Im Hauptscript werden dann zwei Objektinstanzen dieser Klasse angelegt, und die Methoden des Objekts werden ausprobiert.</p>
<h3 class="xmp">Beispiel der Moduldatei <var>VCard.pm</var>:</h3>
<pre>
package VCard;
$Objekte = 0;
sub new {
my $Objekt = shift;
my $Version = shift;
my $Referenz = {};
bless($Referenz,$Objekt);
$Objekte += 1;
$Referenz->VCinit($Version);
return($Referenz);
}
sub VCinit {
my $Objekt = shift;
my $Version = shift;
$Objekt->{BEGIN} = "VCARD";
$Objekt->{VERSION} = $Version;
$Objekt->{END} = "VCARD";
}
sub VCset {
my $Objekt = shift;
my $Schluessel = shift;
my $Wert = shift;
$Objekt->{$Schluessel} = $Wert;
}
sub VCget {
my $Objekt = shift;
my $Schluessel = shift;
return($Objekt->{$Schluessel});
}
sub VCsave {
my $Objekt = shift;
my $Datei = shift;
open(DATEI, ">$Datei") or return(-1);
print DATEI "BEGIN:VCARD\nVERSION:$Objekt->{VERSION}\n";
while ((my $Schluessel, my $Wert) = each %{ $Objekt } ) {
next if ($Schluessel eq 'BEGIN' or $Schluessel eq 'VERSION' or $Schluessel eq 'END');
$Schluessel =~ s/_/\;/g;
print DATEI "$Schluessel:$Wert\n";
}
print DATEI "END:VCARD\n";
close(DATEI);
return($Datei);
}
sub VCopen {
my $Objekt = shift;
my $Datei = shift;
$Objekt->VCreset();
open(DATEI, "<$Datei") or return;
my @Zeilen = <DATEI>;
close(DATEI);
foreach (@Zeilen) {
(my $Schluessel, my $Wert) = split(/:/);
$Schluessel =~ s/\;/_/g;
$Objekt->{$Schluessel} = $Wert;
}
return( %{ $Objekt } );
}
sub VCreset {
my $Objekt = shift;
%{ $Objekt } = ();
}
1;
</pre>
<h3 class="xmp">Beispiel eines vollstndigen CGI-Scripts in Perl:</h3>
<pre>
#!/usr/bin/perl -w
use strict;
use CGI::Carp qw(fatalsToBrowser);
use VCard;
print "Content-type: text/html\n\n";
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
print "<html><head><title>Testausgabe</title></head><body>\n";
print "<h1>Tests mit dem VCard-Objekt</h1>\n";
my $Thilo = VCard->new("3.0");
my $Ina = VCard->new("3.0");
print "<p><b>Wert der im Modul erzeugte Objekteigenschaft BEGIN:</b> $Ina->{BEGIN}<br>\n";
my $Sicherung = $Ina->{BEGIN};
$Ina->{BEGIN} = "fangen wir an";
print "<b>BEGIN nach der Wert&auml;nderung:</b> $Ina->{BEGIN}<br>\n";
$Ina->{BEGIN} = $Sicherung;
print "Da dies aber Unsinn ist, wurde der Wert wieder auf '$Ina->{BEGIN}' gesetzt.</p>\n";
$Thilo->VCset("FN","Thilo Teufel");
$Thilo->VCset("TEL_CELL_VOICE","(0170) 398373740");
$Ina->VCset("FN","Ina Bikina");
$Ina->VCset("EMAIL_PREF_INTERNET","bikina\@example.org");
print "<p><b>Name:</b> ",$Thilo->VCget('FN'),"<br>\n";
print "<b>Handy:</b> ",$Thilo->VCget('TEL_CELL_VOICE'),"</p>\n";
print "<p><b>Name:</b> ",$Ina->VCget('FN'),"<br>\n";
print "<b>Handy:</b> ",$Ina->VCget('EMAIL_PREF_INTERNET'),"</p>\n";
print "<p><b>Anzahl angelegter Objekte:</b> $VCard::Objekte </p>\n";
if(my $Datei = $Thilo->VCsave("/daten/vcard/teufel.vcf")) {
print "<p>VCard von Thilo Teufel in <tt>$Datei</tt> gespeichert!<br>"
}
else {
print "VCard von Thilo Teufel konnte nicht gespeichert werden!";
}
$Thilo->VCreset();
print "<p><b>Name von Thilo nach Objekt-Reset:</b> ",$Thilo->VCget('FN'),"<br>\n";
print "<b>Handy von Thilo nach Objekt-Reset:</b> ",$Thilo->VCget('TEL_CELL_VOICE'),"</p>\n";
if($Thilo->VCopen("/daten/vcard/teufel.vcf")) {
print "VCard von Thilo Teufel wieder ge&ouml;ffnet!<br>";
print "<p><b>Name von Thilo nach Datei&ouml;ffnen:</b> ",$Thilo->VCget('FN'),"<br>\n";
print "<b>Handy von Thilo nach Datei&ouml;ffnen:</b> ",$Thilo->VCget('TEL_CELL_VOICE'),"</p>\n";
}
else {
print "VCard von Thilo Teufel konnte nicht ge&ouml;ffnet werden!";
}
print "</body></html>\n";
</pre>
<h3 class="xmp">Beispiel der erzeugten Datei <var>teufel.vcf</var>:</h3>
<pre>
BEGIN:VCARD
VERSION:3.0
TEL;CELL;VOICE:(0170) 398373740
FN:Thilo Teufel
END:VCARD
</pre>
<h3 class="xpl">Erluterung:</h3>
<p>Im Prinzip funktioniert dieses Beispiel genauso wie das Beispiel mit dem <img src="../../src/up.gif" width="14" height="10" alt="nach oben"> <a href="#htmlprint_beispiel">HTMLprint-Objekt</a> - deshalb interessieren an dieser Stelle nur diejenigen Dinge, die anders sind als im ersten Beispiel.</p>
<p>Objektdaten (oder die Eigenschaften eines Objekts) sind Variablen. Es gengt jedoch nicht, solche Variablen einfach irgendwo in der Moduldatei zu deklarieren. Eine Variable wie der Skalar <code>$Objekte</code>, der im Beispiel zu Beginn der Moduldatei <var>VCard.pm</var> deklariert wird und als Zhler fr Objektinstanzen dient, gehrt <strong>nicht</strong> zu den Objektdaten! Solche Variablen sind so genannte Klassenvariablen, da sie nur einmal fr die gesamte Klasse und fr jede Objektinstanz zur Verfgung stehen. Da das Modul genau einmal im Hauptscript eingebunden wird, stehen diese Variablen auch nur in einer einzigen Ausfhrung zur Verfgung. Das Hauptscript kann mit der Syntax <code>$VCard::Objekte</code> sehr wohl auf den Wert des Skalars <code>$Objekte</code> zugreifen. Aber trotzdem gehrt diese Variable nicht zum Objekt. Objektdaten sind vielmehr solche, die bei jeder neuen Instanz eines Objekts immer wieder neu zur Verfgung stehen.</p>
<p>Die einfachste Lsung fr Objektdaten ist ein <img src="../../src/dok.gif" width="15" height="10" alt="Seite"> <a href="hashes.htm">Hash</a>. In der Konstruktorfunktion <code>new</code> wird ein solcher Hash definiert - mit der Anweisung <code>my $Referenz = {};</code>. Viel zu sehen ist dabei nicht von einem Hash. Doch die leeren geschweiften Klammern symbolisieren einen leeren so genannten anonymen Hash. Dieser Hash ist damit eine Art leerer Behlter, der spter Objektdaten aufnehmen kann. Der Grund dafr, dass man in der Regel einen Hash fr Objektdaten whlt, ist der, dass ein Hash eine dynamische Anzahl von Daten speichern kann. Ein solcher Hash erlaubt es, Objektdaten sowohl im Modul selbst vorzudefinieren, wie auch Objektdaten im Hauptscript zu definieren (im obigen Beispiel passiert beides). Ein Array knnte das zwar theoretisch auch, aber dann wre im Hauptscript die Suche nach einem gewnschten Objektdatum schwieriger. Hashes erleichtern den Direktzugriff auf Daten durch die benannten Schlssel. Durch die Zuweisung des anonymen Hashes an einen Skalar - im Beispiel an <code>$Referenz</code> - wird dieser Skalar eine <img src="../../src/dok.gif" width="15" height="10" alt="Seite"> <a href="referenzen.htm">Referenz</a>, also ein Zeiger auf den anonymen Hash. ber diesen Zeiger ist der Zugriff auf den anonymen Hash mglich.</p>
<p>Objektdaten werden erzeugt, indem der zunchst anonyme Hash der Konstruktorfunktion mit Daten angefllt wird. Im Beispiel geschieht das erstmals in der Subroutine bzw. Methode <code>VCinit</code>. Diese Methode wird bereits in der Konstruktorfunktion <code>new</code> aufgerufen, nmlich mit <code>$Referenz->VCinit($Version);</code>. Da <code>$Referenz</code> innerhalb der Konstruktorfunktion der Objektzeiger ist, knnen Sie dort ber das Schema <code>$Referenz->Methode()</code> andere Subroutinen aufrufen, die dadurch an das Objekt gebunden werden. Durch diese Form des Aufrufs bekommen die Subroutinen auch stets automatisch als ersten Parameter einen Zeiger auf das Objekt bergeben, mit dem sie dann arbeiten knnen. So auch die Methode <code>VCinit</code> im Beispiel. ber den Objektzeiger, den sie sich mit <code>my $Objekt = shift;</code> aus der bergebenen Parameterliste holt, kann sie auf das Objekt und damit auch auf den anonymen Hash zugreifen.</p>
<p>Mit einer Anweisung wie <code>$Objekt->{BEGIN} = "VCARD";</code> wird eine vorgegebene Objekteigenschaft erzeugt. <code>$Objekt->{BEGIN}</code> zeigt auf den anonymen Hash und sagt so viel wie: "hiermit erhlt der anonyme Hash einen Schlssel mit Namen <code>BEGIN</code>". Auerdem wird diesem Schlssel bereits ein Wert zugewiesen, nmlich <code>VCARD</code>. Auf die gleiche Weise werden in <code>VCinit</code> insgesamt drei Objekteigenschaften erzeugt. Die beiden anderen heien <code>VERSION</code> und <code>END</code>. Der Grund fr diese Namen ist im Beispiel, dass diejenigen Namen von Eigenschaften als Schlsselnamen verwendet werden, die eine Datei vom Typ <var>.vcf</var> enthalten knnen. Wie so eine Datei aussieht, sehen Sie in der dargestellten vom Beispiel erzeugten Datei <var>teufel.vcf</var>. Alle Zeilen einer VCard-Datei bestehen aus einer Eigenschaft und ihrem Wert, getrennt durch einen Doppelpunkt. Drei Zeilen sollten in jeder vcf-Datei vorkommen: <code>BEGIN:VCARD</code>, <code>VERSION:[Versionsangabe]</code> und <code>END:VCARD</code>. Fr diese drei Standardzeilen werden im Beispiel die drei gleichnamigen Objekteigenschaften erzeugt.</p>
<p>Weitere Objekteigenschaften werden im Beispiel im Hauptscript erzeugt. Zunchst muss dazu wieder eine Instanz der VCard-Klasse erzeugt werden. Im Beispiel werden zwei Instanzen erzeugt:<br>
<code>my $Thilo = VCard->new("3.0");<br>
my $Ina = VCard->new("3.0");</code><br>
Beim Aufruf der Konstruktorfunktion wird die Versionsnummer fr das gewnschte VCard-Format bergeben. Derzeit ist da die Version 3.0 zu notieren.</p>
<p>Nachdem die beiden Objektinstanzen angelegt sind, ist der Zugriff auf smtliche Objektdaten mglich. Im Hauptscript wird dies zunchst mit dem Objekt fr Ina demonstriert. ber den Objektzeiger <code>$Ina</code> ist es mglich, mit <code>$Ina->{BEGIN}</code> auf den Wert der Objekteigenschaft <code>BEGIN</code> zuzugreifen. Das Script zeigt auch, wie sich der Wert einer solchen vorgegebenen Objekteigenschaft ndern lsst. Das Konstrukt <code>$Ina->{BEGIN}</code> kann wie ein ganz normaler Skalar behandelt werden.<br>
Da bei der objektorientierten Programmierung das Objekt eine abstrakte Einheit ist, dessen Interna Sie als Benutzer des Objekts eigentlich nichts angehen, sollten Sie darauf verzichten, direkt auf Objekteigenschaften zuzugreifen. Erstens ist nmlich nicht gesagt, dass bei einem (beliebigen) Objekt die Daten berhaupt in einem Hash gehalten werden, und zweitens kann sich die interne Datenhaltung ber die verschiedenen Versionen des Moduls hinweg ndern.</p>
<p>Das Hauptscript erzeugt aber auch noch weitere neue Objekteigenschaften und versorgt diese mit Werten. Denn eine VCard-Datei soll ja diverse Adressdaten enthalten. Dies ist im Beispiel durch Aufruf der Methode <code>VCset</code> mglich, die in der Moduldatei definiert ist. Mit einer Anweisung wie:<br>
<code>$Thilo->VCset("FN","Thilo Teufel");</code><br>
wird fr das Objekt von Thilo eine neue Objekteigenschaft namens <code>FN</code> angelegt, die den Wert <code>Thilo Teufel</code> zugewiesen bekommt. Im Beispiel sehen Sie, dass sowohl das Objekt von Thilo als auch das Objekt von Ina die Objekteigenschaft <code>FN</code> erhalten, jeweils mit eigenen Werten. Daran ist sehr schn erkennbar, dass es sich tatschlich um verschiedene Instanzen des Objekts <code>VCard</code> handelt, wobei jede Instanz ihre eigene Datenwelt hat, ohne dass es Kollisionen mit anderen gleichzeitig existierenden Objektinstanzen gibt.</p>
<p>Whrend der Aufruf der Methode <code>VCset</code> so weit gut nachvollziehbar ist, ist das, was in der Moduldatei innerhalb dieser Methode geschieht, nicht so leicht zu verstehen. Auch <code>VCset</code> bekommt - wie alle Methoden - als ersten Parameter automatisch den Objektzeiger bergeben. <code>VCset</code> tut nun nichts anderes, als mit <code>$Objekt->{$Schluessel} = $Wert</code> dem anonymen Hash des Objekts einen Schlsselnamen und einen zugehrigen Wert hinzuzufgen. Beides, also den Schlsselnamen und den Wert, erwartet die Methode als Parameter - daher auch die voranstehenden Anweisungen wie <code>$Schluessel = shift;</code>. Die Aufrufe dieser Methode im Hauptscript bergeben ja auch die geforderten beiden Parameter.</p>
<p>Die brigen Methoden der Moduldatei sind ganz hnlich aufgebaut. Sie bernehmen verschiedene Aufgaben, was man mit VCard-Daten so alles anstellen kann:<br>
<code>VCget</code> liefert zu einem Schlssel den zugehrigen Wert. Gut fr Abfragen. Genaugenommen ist eine Abfrage im Hauptscript wie <code>$Thilo->VCget('FN')</code> das gleiche, als ob dort stehen wrde <code>$Thilo->{FN}</code>. Entscheidungen, ob man solche Methoden braucht, gehren einfach zum Design eines Objekts. Um die Programmpflege zu erleichtern, sollten Sie jedoch immer Methoden dafr bereitstellen.<br>
<code>VCsave</code> speichert die Daten eines Objekts in eine vcf-Datei nach dem VCF-Standard. Im Script wird diese Funktion einmal aufgerufen und schreibt dabei die Datei <var>teufel.vcf</var>, deren Inhalt ja dargestellt ist.<br>
<code>VCopen</code> liest eine beliebige VCF-Datei und speichert deren Inhalt im zugeordneten Objekt. Diese Methode knnen Sie also etwa verwenden, wenn Sie existierende VCF-Dateien haben, z.B. durch Export aus den Adressdaten eines VCard-fhigen E-Mail-Programms.
<code>VCreset</code> lscht alle Daten eines Objekts. Es stellt also den Ursprungszustand des anonymen Hashes wieder her. Bentigt wird diese Methode innerhalb der Moduldatei von <code>VCopen</code>. Aber Sie knnen diese Methode natrlich auch aus dem Hauptscript aufrufen, um eine Objektinstanz wieder in ihren jungfrulichen Zustand zu versetzen. Im Hauptscript des obigen Beispiels wird dies am Objekt von Thilo demonstriert.</p>
<p>Wenn Sie das VCard-Objekts des Beispiels in der Praxis einsetzen wollen, mssen Sie die VCard-Eigenschaftsnamen kennen. Diese sind beim Internet Mail Consortium dokumentiert. Wichtig ist, dass Sie ein Semikolon immer durch Unterstrich ersetzen. So wird eine VCard-Eigenschaft wie <code>TEL;CELL;VOICE</code> bei einem Methodenaufruf wie <var>VCset</var> als <code>TEL_CELL_VOICE</code> notiert. Einige der mglichen VCard-Eigenschaften enthalten auch noch andere Zeichen wie <code>=</code> und <code>-</code>. Um diese korrekt zu verarbeiten, mssen Sie die Methoden <code>VCopen</code> und <code>VCsave</code> des Objekts vermutlich noch erweitern, worauf im Beispiel der Einfachheit halber verzichtet wurde.</p>
<table cellpadding="4" cellspacing="0" border="0" width="100%">
<tr><td colspan="2" class="doc">
<a href="#top"><img src="../../src/up.gif" width="14" height="10" border="0" alt="nach oben"></a>
</td></tr>
<tr><td class="doc"><a href="cgitypisch.htm"><img src="../../src/next.gif" width="10" height="10" border="0" hspace="10" alt="weiter"></a></td>
<td width="100%"><img src="../../src/dok.gif" width="15" height="10" alt="Seite"> <a href="cgitypisch.htm">CGI-typische Aufgaben in Perl</a>
</td></tr>
<tr>
<td class="doc"><a href="tokens.htm"><img src="../../src/prev.gif" width="10" height="10" border="0" hspace="10" alt="zurck"></a></td>
<td><img src="../../src/dok.gif" width="15" height="10" alt="Seite"> <a href="tokens.htm">Tokens</a>
</td>
</tr>
<tr><td colspan="2" class="doc"> </td>
</tr>
<tr>
<td colspan="2" class="nav"><a class="an" name="bottom"><img src="../../src/refkap.gif" width="16" height="13" alt="Teil von"></a> <a href="../../index.htm">SELFHTML</a>/<a href="../../navigation/index.htm" target="_parent" class="navh">Navigationshilfen</a> <img src="../../src/refkap.gif" width="16" height="13" alt="Teil von"> <a href="../index.htm">Perl</a> <img src="../../src/refkap.gif" width="16" height="13" alt="Teil von"> <a href="index.htm">Perl-Sprachelemente</a></td>
</tr>
</table>
<p>© 2007 <img src="../../src/dok.gif" width="15" height="10" alt="Seite"> <a href="../../editorial/impressum.htm">Impressum</a></p>
</body>
</html>
|