Einzelnen Beitrag anzeigen

Benutzerbild von alcaeus
alcaeus

Registriert seit: 11. Aug 2003
Ort: München
6.537 Beiträge
 
#4

Re: [PHP] Wozu Klassen in PHP?

  Alt 6. Sep 2008, 15:48
Moin,

wenn du nur eine Mail-"Klasse" hast, mag das nicht viel Unterschied machen. Sobald die Anwendung groesser wird, wirds kritisch. Meine aktuelle Webanwendung besteht aus ueber 30 Klassen, die alle ihren Sinn und Zweck erfuellen. Wenn ich die Funktionalitaeten dieser Klasse einfach in normale Funktionen auslager, hab ich Hunderte Funktionen, die meinen Namespace vollmuellen. Wenn ich dann auch noch die Properties dieser Klassen raushau, wirds richtig uebel.

Um auf das Mail-Beispiel zu kommen: Nehmen wir eine send_mail-Funktion an. Du brauchst auf alle Faelle Parameter fuer Empfaenger, CC, BCC, Absender, Titel und Text. Dann kommen noch Headers dazu. Also koennte die Deklaration so aussehn:
Code:
mail_send($from, $to, $cc, $bcc, $subject, $text, $extra_headers = '')
Ein Aufruf wuerde dann so aussehn:
Code:
mail_send('me@me.com', array('you@you.com', 'he@he.com'), array('them@them.com'), array('we@we.com'), 'Some mail', 'This is a sample text.');
Wenn ich es in eine Klasse reinbau, koennte das so aussehn:
Code:
$mail = new email('me@me.com');
$mail->add_to('you@you.com', 'he@he.com');
$mail->add_cc('them@them.com');
$mail->add_bcc('we@we.com');
$mail->set_subject('Some mail');
$mail->set_text('This is a sample text');
$mail->send();
Auf einen Schlag mag das umstaendlicher erscheinen, aber nehmen wir an, ich lese E-Mail-Adressen aus ner Datenbank aus:
Code:
while ($row = $db->get_row())
{
  $mail->add_bcc($row['email']);
}
Ich brauch also nicht ein eigenes Array, um die Adressen erstmal zwischenzuspeichern. Ausserdem, wenn ich nur ne Mail an eine Person schick muss ich nicht so viele leere Parameter hinstellen.

Ein weiterer Pluspunkt: Sichtbarkeiten. Ich koennte kotzen wenn ich ein Projekt seh, welches zig Funktionen der Art
Code:
function __do_something_private()
enthaelt. Wenn diese Funktion privat sein soll, dann gehoert sie zu irgendeiner Funktion, die sie aufruft. Also gehoeren die Funktionalitaeten wahrscheinlich zusammen und deshalb in eine eigene Klasse. Als private markiert kann sie dann auch nicht mehr versehentlich aufgerufen werden, und meine Code-Completion zeigt mir nicht erstmal die ganzen "privaten" Funktionen an, weil "_" in der Sortierung vor "a" kommt.

Was genau kannst du am Sinn von Klassen nicht auf PHP anwenden? Klassen gruppieren Funktionen und binden sie an ein Objekt. Nehmen wir noch ein Beispiel:
Ich hab nen Haufen FTP-Funktionen (darunter ftp_do_connect() und ftp_do_login()) und nen Haufen SMTP-Funktionen (darunter smtp_do_connect() und smtp_do_login()).

die _do_connect-Funktionen geben mir das jeweilige Handle zurueck, das ich an die _do_login-Funktion uebergeben muss. Dann geht auch sowas:
Code:
$handle = ftp_do_connect('foo.bar.com', 21);
smtp_do_login($handle, 'user', 'pass');
In dem Fall isses weniger schlimm: der Server gibt mir "nur" ne virtuelle Ohrfeige, weil er die Sprache nicht versteht und denkt ich haette ihn als Schlampe bezeichnet. Sowas kann aber auch Schaden anrichten.
Code:
$ftp = new ftp();
$ftp->do_connect('foo.bar.com', 21);
$ftp->do_login('user', 'pass');
Sowas kann erstens keinen Schaden mehr anrichten, zweitens muss ich nicht aufpassen dass ich nicht versehentlich das Handle ueberschreib. Schliesslich kann es ja sein dass ich zwischendrin noch ne SMTP-Verbindung aufmach, den Code von ner anderen Stelle rueberkopier und nicht dran denk, dass $handle ja schon vergeben ist. Dann kassier ich wieder ne Ohrfeige und dann gehts irgendwann aufs Ego *g*.

Es ist an sich schwer, die Vorteile von OOP zu erklaeren. Ich fuer meinen Teil kann sagen, dass ich v.a. oben erwaehntes "Gruppieren" und Verstecken mag. Nur weil ich ne Funktion mit __something() bezeichne heisst das nicht, dass es nicht nen dummen Add-On-Programmierer gibt der denkt "oh, die ist nuetzlich" und sie verwendet. Wenn die Funktion als private in ner Klasse liegt, ist es schon besser. Und um noch einen ganz wichtigen Vorteil zu nennen: Vererbung. Im oben erwaehnten Projekt arbeite ich u.a. mit Tarballs. Nun ist die Frage, wie koennte man sowas am geschicktesten implementieren? Funktionen waeren overkill, ich braeuchte mindestens 15 Hilfsfunktionen, die alleine aufgerufen allerhoechstens Scheisse bauen. Ausserdem, wenn ich jetzt nicht nur Tarballs, sondern auch gzip-komprimierte Tarballs bearbeiten will, muss ich schlimmstenfalls die Haelfte der Funktionen kopieren und geringfuegig anpassen. Und mit OOP?

Ich habe eine abstrakte Grundklasse (compress), welche gewisse Standardoperationen durchfuehrt. Dazu gehoeren das Hinzufuegen von Dateien (das geschieht an der Stelle in ein internes Array, welches spaeter weiterverarbeitet wird, das Oeffnen von Dateien, etc.). Gleichzeitig definitiert die Klasse die Funktionen read_data() und write_data(), welche dafuer zustaendig sind, beim Oeffnen die Daten korrekt aus der Datei ins interne Array zu lesen, bzw. beim Speichern die Daten korrekt in die Datei zu schreiben.
compress_tar leitet sich von compress ab und implementiert diese beiden Funktionen, zusammen mit dem eigenen Set Hilfsfunktionen. So, jetzt will ich auch noch tgz reinbringen, also definier ich compress_tgz, welche sich von compress_tar ableitet, die Daten anders einliest als compress_tar aber anschliessend die Hilfsfunktionen von compress_tar verwendet um die Daten parsen zu lassen. Schliesslich unterscheiden sich die beiden nur dadurch, dass compress_tgz vor dem Parsen noch ein gz_deflate() laufen lassen muss, waehrend compress_tar einfach nur einlesen muss. Wenn ich die Funktionalitaet ohne Klassen implementieren wuerde, haette ich zig Hilfsfunktionen, die nur unnoetig im globalen Namespace rumliegen und "im Weg sind". So hab ich die Hilfsfunktionen da wo ich sie brauch, und jeder der die Klasse verwendet muss gar nicht wissen dass sie da sind. Ausserdem muss ich nicht fuer jede Kompressionsmethode eigene Dokumentationen schreiben. Schliesslich koennt ich auch sowas machen:
Code:
$classname = ($do_gzip) ? 'compress_tgz' : 'compress_tar';
$archive = new $classname($filename);
$archive->add($root_dir);
$archive->close();
Alle Kompressionsklassen haben dasselbe Interface, d.h. es waere ein leichtes, die ganze Sache auf ZIP umzustellen: den Klassennamen ersetzen und fertig

Greetz
alcaeus
Andreas B.
Die Mutter der Dummen ist immer schwanger.
Ein Portal für Informatik-Studenten: www.infler.de
  Mit Zitat antworten Zitat