Missbrauch statischer Methoden

Als erstes, praktisches Beispiel fuer einen Singleton habe ich mir
meine (bis dahin noch PHP4)-Datenbankabstraktion etwas netter
gestaltet. Funkioniert, wie zu erwarten war, einwandfrei.

Bloss: jetzt gibt es doch tatsaechlich in den Tiefen der Appikation
ein Programm, in dem _mehrere_ Datenbankverbindungen gehalten werden
muessen. Damit ist der reine Singleton nicht tragbar, ein
erweitertes Konzept muss her. Zunaechst einmal wird der Konstruktor
wieder public, damit klappen dann:

| DB::Init();
| $db = new DB();

....gleichermassen. Nun moechte ich aber, primaer aus Gruenden der
angenehmen Lesbarkeit, gerne ein SQL-Statement so:

| DB::execute();
| $db->execute();

....ausfuehren, also beim Singleton-Aufruf _nicht_ jedesmal ueber
Init gehen muessen. execute wird dazu als "public static" definiert
und kann damit sowohl mit oder ohne Instanz aufgerufen werden.

Aber: kann ich beim Aufruf von $db->execute() dann noch _irgendwie_
auf das aufrufende Objekt zugreifen? $this ist, wie es sich fuer
statische Methoden ja eigentlich gehoert, naemlich NULL.

Servus,
Stefan

--
http://kontaktinser.at/ - die kostenlose Kontaktboerse fuer Oesterreich

Ein Hauch von Ewigkeit - Stefan: riechen, welch fröhliches Sehnen!
(Sloganizer)
Stefan+Usenet [ So, 11 November 2007 09:41 ] [ ID #1868006 ]

Re: Missbrauch statischer Methoden

Stefan Froehlich schrieb:
>
> Bloss: jetzt gibt es doch tatsaechlich in den Tiefen der Appikation
> ein Programm, in dem _mehrere_ Datenbankverbindungen gehalten werden
> muessen. Damit ist der reine Singleton nicht tragbar, ein
> erweitertes Konzept muss her. Zunaechst einmal wird der Konstruktor
> wieder public, damit klappen dann:
>
> | DB::Init();
> | $db = new DB();
>
Wenn der Konstruktor public ist, hast du halt gar keine Kontrolle mehr
über die Anzahl der Instanzen. Wenn du Init() einen (optionalen)
Parameter schenkst, kannst du damit auch weitere (definierte)
DB-Verbindungen aufbauen.

> ....gleichermassen. Nun moechte ich aber, primaer aus Gruenden der
> angenehmen Lesbarkeit, gerne ein SQL-Statement so:
>
> | DB::execute();
> | $db->execute();
>
> ....ausfuehren, also beim Singleton-Aufruf _nicht_ jedesmal ueber
> Init gehen muessen. execute wird dazu als "public static" definiert
> und kann damit sowohl mit oder ohne Instanz aufgerufen werden.

Wenn du das dann statisch aufrufen willst, brauchst du halt auch noch
einen Parameter, welche Verbindung benutzt werden soll.

> Aber: kann ich beim Aufruf von $db->execute() dann noch _irgendwie_
> auf das aufrufende Objekt zugreifen? $this ist, wie es sich fuer
> statische Methoden ja eigentlich gehoert, naemlich NULL.

Meinst du self::varname?

Gruß
David
David Fuhr [ So, 11 November 2007 11:35 ] [ ID #1868008 ]

Re: Missbrauch statischer Methoden

Stefan Froehlich meinte:
> Als erstes, praktisches Beispiel fuer einen Singleton habe ich mir
> meine (bis dahin noch PHP4)-Datenbankabstraktion etwas netter
> gestaltet. Funkioniert, wie zu erwarten war, einwandfrei.
>
> Bloss: jetzt gibt es doch tatsaechlich in den Tiefen der Appikation
> ein Programm, in dem _mehrere_ Datenbankverbindungen gehalten werden
> muessen. Damit ist der reine Singleton nicht tragbar, ein
> erweitertes Konzept muss her. Zunaechst einmal wird der Konstruktor
> wieder public, damit klappen dann:
>
> | DB::Init();
> | $db = new DB();
>
> ...gleichermassen. Nun moechte ich aber, primaer aus Gruenden der
> angenehmen Lesbarkeit, gerne ein SQL-Statement so:

"Angenehme Lesbarkeit" finde ich ein schwaches Argument für schwache
Codequalität. Entweder eine statische Lösung oder eben "richtige" Objekte.

> | DB::execute();
> | $db->execute();
>
> ...ausfuehren, also beim Singleton-Aufruf _nicht_ jedesmal ueber
> Init gehen muessen. execute wird dazu als "public static" definiert
> und kann damit sowohl mit oder ohne Instanz aufgerufen werden.

> Aber: kann ich beim Aufruf von $db->execute() dann noch _irgendwie_
> auf das aufrufende Objekt zugreifen? $this ist, wie es sich fuer
> statische Methoden ja eigentlich gehoert, naemlich NULL.

Bei einer statischen Methode existiert ja kein "aufrufendes" *Objekt* -
vielleicht ist "self" schon eine ausreichende Lösung für dein "Problem".
Wenn du allerdings (sinnvollerweise) ein Objekt brauchst, dann
instanziere eines und fertig. Und mehrere DB-Verbindungen brauchen
verbindungsspezifische Parameter, die in einer statischen Klasse nicht
handhabbar sind.

Gruß, Gregor


--
http://www.gregorkofler.at ::: Landschafts- und Reisefotografie
http://www.licht-blick.at ::: Forum für Multivisionsvorträge
http://www.image2d.com ::: Bildagentur für den alpinen Raum
Gregor Kofler [ So, 11 November 2007 11:38 ] [ ID #1868009 ]

Re: Missbrauch statischer Methoden

On Sun, 11 Nov 2007 11:35:32 +0100 David Fuhr wrote:
> > jetzt gibt es doch tatsaechlich in den Tiefen der Appikation ein
> > Programm, in dem _mehrere_ Datenbankverbindungen gehalten werden
> > muessen. [...]
>
> > | DB::Init();
> > | $db = new DB();

> Wenn der Konstruktor public ist, hast du halt gar keine Kontrolle
> mehr über die Anzahl der Instanzen.

Das ist ja gewollt. Die Applikation greift im wesentlichen ueber
DB:: auf die Datenbank zu - aber wenn jemand partout meint, eine
eigene Verbindung zu brauchen, dann kann er das mit der zweiten
Zeile gerne (und uneingeschraenkt) tun. So weit funktioniert es ja
auch.

> > | DB::execute();
> > | $db->execute();

> Wenn du das dann statisch aufrufen willst, brauchst du halt auch
> noch einen Parameter, welche Verbindung benutzt werden soll.

Das ist dann:

| $db->execute($db)

...und somit alles andere als intuitiv. Eine andere Variante sind
auch noch zwei getrennte Methoden:

| DB::execute('SELECT 1');
| $db->execute2('SELECT 1');

Gefaellt mir ebenfalls nicht wirklich und schreit nach
Fluechtigkeitsfehlern.

> > Aber: kann ich beim Aufruf von $db->execute() dann noch _irgendwie_
> > auf das aufrufende Objekt zugreifen? $this ist, wie es sich fuer
> > statische Methoden ja eigentlich gehoert, naemlich NULL.

> Meinst du self::varname?

Nein. Ich haette gerne innerhalb des Aufrufs von

| $db->execute('SELECT 1');

....eine Referenz auf das aufrufende Objekt $db zur Verfuegung. self
gibt mir ja (richtigerweise) die Referenz auf den Singleton zurueck.
Dass das mit dem Paradigma statischer Funktionen bricht, ist mir
schon klar. Ich faende den resultierenden Code aber gnadenlos
besser lesbar, als seine moeglichen Alternativen - und vielleicht
gibt es ja doch einen Weg dorthin, den ich bloss noch nicht gefunden
habe.

Servus,
Stefan

--
http://kontaktinser.at/ - die kostenlose Kontaktboerse fuer Oesterreich

Stefan!? Ja! Denn kosten ist hinreissender als flörten.
(Sloganizer)
Stefan+Usenet [ So, 11 November 2007 11:48 ] [ ID #1868010 ]

Re: Missbrauch statischer Methoden

Stefan Froehlich schrieb:
> On Sun, 11 Nov 2007 11:35:32 +0100 David Fuhr wrote:

> Das ist ja gewollt. Die Applikation greift im wesentlichen ueber
> DB:: auf die Datenbank zu - aber wenn jemand partout meint, eine
> eigene Verbindung zu brauchen, dann kann er das mit der zweiten
> Zeile gerne (und uneingeschraenkt) tun. So weit funktioniert es ja
> auch.
>
>>> | DB::execute();
>>> | $db->execute();
>
>> Wenn du das dann statisch aufrufen willst, brauchst du halt auch
>> noch einen Parameter, welche Verbindung benutzt werden soll.
>
> Das ist dann:
>
> | $db->execute($db)
>
> ...und somit alles andere als intuitiv.

Ich bezog das mit dem Parameter auf die statische Methode. Zum Beispiel:

DB::execute("conn1");

Den Parameter kannst ja optional machen, und somit bei dem Aufruf über's
Objekt weglassen (in der methode auf !is_null($this) prüfen).

$conn1 = DB::Init("conn1");
$connt->execute();

> Eine andere Variante sind
> auch noch zwei getrennte Methoden:
>
> | DB::execute('SELECT 1');
> | $db->execute2('SELECT 1');
>
> Gefaellt mir ebenfalls nicht wirklich und schreit nach
> Fluechtigkeitsfehlern.

Da hast du recht, das ist Quatsch. Dann eher in einer statischen Methode
eine Instanz einer zweiten (nicht-statischen) DB-Klasse zurückgeben.

> Nein. Ich haette gerne innerhalb des Aufrufs von
>
> | $db->execute('SELECT 1');
>
> ....eine Referenz auf das aufrufende Objekt $db zur Verfuegung. self
> gibt mir ja (richtigerweise) die Referenz auf den Singleton zurueck.

Ähm... steh ich auf dem Schlauch oder du? Bei
$db->execute() enthält $this das Objekt
und bei
DB::execute() enthält self das Objekt

Falls du irgendwelchen anderen Traces brauchst, schau dir mal
debug_backtrace() an...

Gruß
David
David Fuhr [ So, 11 November 2007 12:03 ] [ ID #1868012 ]

Re: Missbrauch statischer Methoden

Stefan Froehlich wrote:
> Bloss: jetzt gibt es doch tatsaechlich in den Tiefen der Appikation
> ein Programm, in dem _mehrere_ Datenbankverbindungen gehalten werden
> muessen. Damit ist der reine Singleton nicht tragbar, ein
> erweitertes Konzept muss her. Zunaechst einmal wird der Konstruktor
> wieder public, damit klappen dann:
>
> | DB::Init();
> | $db = new DB();
>
> ...gleichermassen. Nun moechte ich aber, primaer aus Gruenden der
> angenehmen Lesbarkeit, gerne ein SQL-Statement so:
>
> | DB::execute();
> | $db->execute();

Das ist nicht möglich! Ich kenne auch keine Sprache in der sowas gehen
würde.

Wenn Du dieses Vorhaben unbedingt durchziehen willst kannst Du nur eine
extra Wrapperklasse um ein DB-Objekt legen welche die statischen
Methoden anbietet.

In anderen Sprachen bei denen Methodennamen nicht caseless sind kann man
sowas zwar durch Änderung der Groß/Kleinschreibung hinbekommen aber das
ist auch da eher suboptimal, da es schnell zu einer Verwechslung kommen
kann.

MfG, Ulf

--
_,
_(_p> Ulf [Kado] Kadner
\<_)
^^
Ulf Kadner [ So, 11 November 2007 13:03 ] [ ID #1868013 ]

Re: Missbrauch statischer Methoden

David Fuhr schrieb:
> Stefan Froehlich schrieb:
>> On Sun, 11 Nov 2007 11:35:32 +0100 David Fuhr wrote:

> Ich bezog das mit dem Parameter auf die statische Methode. Zum Beispiel:
> DB::execute("conn1");

> Den Parameter kannst ja optional machen, und somit bei dem Aufruf über's
> Objekt weglassen (in der methode auf !is_null($this) prüfen).

> $conn1 = DB::Init("conn1");
> $connt->execute();

Entweder ist die Methode statisch, dann gibt es $this logischerweise
nicht oder sie ist nicht statisch, dann kannst du sie auch nicht
statisch aufrufen.

class A {
public function x() {}
}

A::x();

"Debug Strict (PHP 5): Non-static method A::x() should not be called
statically"

Ich würde mich also nicht darauf verlassen, dass soetwas funktioniert.

>> Nein. Ich haette gerne innerhalb des Aufrufs von
>>
>> | $db->execute('SELECT 1');
>>
>> ....eine Referenz auf das aufrufende Objekt $db zur Verfuegung. self
>> gibt mir ja (richtigerweise) die Referenz auf den Singleton zurueck.

> Ähm... steh ich auf dem Schlauch oder du? Bei
> $db->execute() enthält $this das Objekt

Richtig.

> DB::execute() enthält self das Objekt

self ist kein Objekt, sondern nur ein Alias für die Klasse in der sich
die Methode befindet. self ist in diesem Fall also DB. Hier wird jedoch
nirgendwo ein Objekt dieser Klasse erzeugt, deswegen kannst du über self
auch nur auf statische Members und Methoden bzw. Konstanten zugreifen.
dafox [ So, 11 November 2007 13:32 ] [ ID #1868016 ]

Re: Missbrauch statischer Methoden

Stefan Froehlich schrieb:
> Als erstes, praktisches Beispiel fuer einen Singleton habe ich mir
> meine (bis dahin noch PHP4)-Datenbankabstraktion etwas netter
> gestaltet. Funkioniert, wie zu erwarten war, einwandfrei.

Bist du sicher, dass du das Pattern verstanden hast?

> Bloss: jetzt gibt es doch tatsaechlich in den Tiefen der Appikation
> ein Programm, in dem _mehrere_ Datenbankverbindungen gehalten werden
> muessen. Damit ist der reine Singleton nicht tragbar, ein
> erweitertes Konzept muss her.

Ich würde die DB-Connection (bei dir repräsentiert durch DB) und die
Factory (also das Teil, das die Verbindungsobjekte erzeugt) von einander
trennen.

class DBConnection {
public function __construct($host, $port, ...) {
$this->pdo = new PDO(...);
}

public function execute($stmt) {
...
}
}

class DB {
private static $defaultConnection = null;

public static function createConnection($host, $port, ...) {
return new DBConnection($host, $port, ...);
}

public static function getDefaultConnection() {
if(self::$defaultConnection != null) {
// Das hier kommt aus ner Konfigfile oder sonstwo her
$host = 'mysql-server';
$port = 3306;
...

self::$defaultConnection = self::getConnection(...);
}

return self::$defaultConnection;
}

public static function execute($stmt) {
return self::getDefaultConnection()->execute($stmt);
}
}

> Zunaechst einmal wird der Konstruktor
> wieder public, damit klappen dann:

> | DB::Init();
> | $db = new DB();

Wenn ich dich richtig verstanden habe, dann willst du normalerweise
immer die Default-Connection verwenden und willst dem Entwickler dennoch
die Möglichkeit bieten, weitere Verbindungen zu erzeugen. Mit der
skizzierten Klasse kannst du:

1. Standardverbindung nutzen

$db1 = DB::getDefaultConnection();

2. Beliebige weitere Verbindungen erzeugen

$db2 = DB::createConnection('mysql-server-2', ...);

> Nun moechte ich aber, primaer aus Gruenden der
> angenehmen Lesbarkeit, gerne ein SQL-Statement so:

> | DB::execute();
> | $db->execute();

Ich verstehe zwar nicht, warum du execute() statisch ausführen willst,
aber das geht dann auch:

1. Statischer Call (verwendet Default-DBConnection)

DB::execute('select ...');

2. DBConnection verwenden

$conn = DB::getDefaultConnection();
$conn->execute('select ...');

> ...ausfuehren, also beim Singleton-Aufruf _nicht_ jedesmal ueber
> Init gehen muessen. execute wird dazu als "public static" definiert
> und kann damit sowohl mit oder ohne Instanz aufgerufen werden.

Wie "beim Singleton-Aufruf nicht jedesmal über Init gehen"? Entweder du
rufst Init() auf oder du hast kein Singleton mehr.
dafox [ So, 11 November 2007 13:48 ] [ ID #1868017 ]

Re: Missbrauch statischer Methoden

On Sun, 11 Nov 2007 13:03:46 +0100 Ulf Kadner wrote:
> > | DB::execute();
> > | $db->execute();

> Das ist nicht möglich! Ich kenne auch keine Sprache in der sowas
> gehen würde.

Naja, in PHP geht immer wieder einiges, was ich nicht fuer moeglich
gehalten haette. Insofern war eine gewisse Hoffnung vorhanden, dass
es vielleicht auch hier Wege gibt - die Unlauterkeit meines
Vorhabens war mir ja durchaus bewusst, wie das Subject beweist :-)

> Wenn Du dieses Vorhaben unbedingt durchziehen willst kannst Du nur
> eine extra Wrapperklasse um ein DB-Objekt legen welche die
> statischen Methoden anbietet.

So ward es nun auch erledigt, ja.

Servus,
Stefan

--
http://kontaktinser.at/ - die kostenlose Kontaktboerse fuer Oesterreich

Fescher geht's nimmer - Stefan: lächeln, welch grauses Verzehren!
(Sloganizer)
Stefan+Usenet [ Mo, 12 November 2007 13:53 ] [ ID #1868675 ]

Re: Missbrauch statischer Methoden

On Sun, 11 Nov 2007 13:48:37 +0100 Thomas Hamacher wrote:
> > Als erstes, praktisches Beispiel fuer einen Singleton habe ich mir
> > meine (bis dahin noch PHP4)-Datenbankabstraktion etwas netter
> > gestaltet. Funkioniert, wie zu erwarten war, einwandfrei.

> Bist du sicher, dass du das Pattern verstanden hast?

An sich schon, ja :-)

Allerdings bin ich nach Fertigstellung der ueblichen Implementierung
(ein immer gleiches Objekt, welches mit getInstance() geholt, und auf
das dann ueber normale Methoden zugegriffen wird) recht schnell zu
statischen Methoden uebergegangen.

Grund dafuer war genau das:

> $conn = DB::getDefaultConnection();
> $conn->execute('select ...');

....zu vermeiden. Es mag zwar einen Tick eleganter sein, aber dafuer hat

| DB::execute()

den Charme, sich in beliebig grossen Quelltexten zielsicher aufspueren
zu lassen (ebenso natuerlich die anderen Methoden), waehrend ich sonst
nur alle Dateien finden wuerde, die _irgendetwas_ mit
DB::getDefaultConntextion anstelle (was nicht notwendigerweise execute()
sein muss).

> Entweder Du rufst Init() auf oder du hast kein Singleton mehr.

Hm. Wie immer man das dann nennt, was ich habe. Im Prinzip ist es
deutlich eleganterer Ersatz fuer frueher verwendete globale Variable mit
dem Verbindungs-Handle zur Datenbank, die sich zudem noch beim ersten
Aufruf selbst initialisiert, falls notwendig. Funktional sehe ich
allerdings keinen Unterschied zum Singleton.

Servus,
Stefan

--
http://kontaktinser.at/ - die kostenlose Kontaktboerse fuer Oesterreich

Stefan - die schlankste Verkündigung der Leichtigkeit.</B
(Sloganizer)
Stefan+Usenet [ Mo, 12 November 2007 13:59 ] [ ID #1868676 ]

Re: Missbrauch statischer Methoden

Stefan Froehlich schrieb:
> On Sun, 11 Nov 2007 13:48:37 +0100 Thomas Hamacher wrote:
>>> Als erstes, praktisches Beispiel fuer einen Singleton habe ich mir
>>> meine (bis dahin noch PHP4)-Datenbankabstraktion etwas netter
>>> gestaltet. Funkioniert, wie zu erwarten war, einwandfrei.

>> Bist du sicher, dass du das Pattern verstanden hast?

> An sich schon, ja :-)

> Allerdings bin ich nach Fertigstellung der ueblichen Implementierung
> (ein immer gleiches Objekt, welches mit getInstance() geholt, und auf
> das dann ueber normale Methoden zugegriffen wird) recht schnell zu
> statischen Methoden uebergegangen.

Moment. Geht es jetzt um die Diskussion Singleton vs. Statische Methoden
oder verfolgst du immer noch das Ziel, ggf. auch Verbindungen zu anderen
Datenquellen zu erzeugen?

Letzteres kannst du mit einem Singleton nicht erreichen, dazu brauchst
du eine Factory oder ähnliches. Wenn du anstatt einem Singleton jetzt
eine Klasse mit lediglich statischen Methoden hast, dann hab ich noch
ganz andere Argumente dagegen :)

> Grund dafuer war genau das:

>> $conn = DB::getDefaultConnection();
>> $conn->execute('select ...');

> ...zu vermeiden. Es mag zwar einen Tick eleganter sein, aber dafuer hat

> | DB::execute()
> den Charme, sich in beliebig grossen Quelltexten zielsicher aufspueren
> zu lassen ...

Ich habe dir ja dafür eine mögliche Lösung genannt, die genau das macht
was du willst. Wenn du statt den zwei Zeilen einfach

DB::execute()

aufrufst, dann wird intern die Default-Connection verwendet. Das ist ja
genau die Idee gewesen. Nur dann, wenn du eine andere Verbindung haben
willst, musst du explizit createConnection() aufrufen. Ich hatte das in
meinem Beispiel blöd geschrieben. Also nochmal:

1. Statischer Call (verwendet intern Default-Connection)

DB::execute()

2. Alternativ: Andere Verbindung

$conn = DB::createConnection(...);
$conn->execute()

ODER

DB::createConnection()->execute()

3. Wenn du ein Handle zur Default-Connection brauchst

$conn = DB::getDefaultConnection()

>> Entweder Du rufst Init() auf oder du hast kein Singleton mehr.

> Hm. Wie immer man das dann nennt, was ich habe. Im Prinzip ist es
> deutlich eleganterer Ersatz fuer frueher verwendete globale Variable mit
> dem Verbindungs-Handle zur Datenbank, die sich zudem noch beim ersten
> Aufruf selbst initialisiert, falls notwendig.

Wenn du execute() sowohl statisch als auch nicht statisch aufrufen
willst, dann kannst du keinen Singleton verwenden. Es geht dann (mit
PHP5) nur mit zwei Klassen.

Wie hast du es denn jetzt gelöst?
dafox [ Mo, 12 November 2007 19:32 ] [ ID #1868680 ]

Re: Missbrauch statischer Methoden

On Mon, 12 Nov 2007 19:32:16 +0100 Thomas Hamacher wrote:
> > Allerdings bin ich nach Fertigstellung der ueblichen
> > Implementierung (ein immer gleiches Objekt, welches mit
> > getInstance() geholt, und auf das dann ueber normale Methoden
> > zugegriffen wird) recht schnell zu statischen Methoden
> > uebergegangen.

> Moment. Geht es jetzt um die Diskussion Singleton vs. Statische
> Methoden oder verfolgst du immer noch das Ziel, ggf. auch
> Verbindungen zu anderen Datenquellen zu erzeugen?

Sowohl, als auch - ich entwickle und verwerfe gerade immer wieder
neue Ideen :)

> Letzteres kannst du mit einem Singleton nicht erreichen, dazu
> brauchst du eine Factory oder ähnliches. Wenn du anstatt einem
> Singleton jetzt eine Klasse mit lediglich statischen Methoden
> hast, dann hab ich noch ganz andere Argumente dagegen :)

Inzwischen habe ich eine generische Datenbankklasse fuer beliebige
Verbindungen, und zusaetzlich das aequivalent zu einer globalen
Variable, also eine Klasse mit ausschliesslich statischen Methoden,
die sich beim ersten Aufruf selbst initialisiert und intern ein
einzelnes Objekt ihres eigenen Typs verwaltet.

> Ich habe dir ja dafür eine mögliche Lösung genannt, die genau das macht
> was du willst. [...] Ich hatte das in meinem Beispiel blöd
> geschrieben. Also nochmal:

Ok, jetzt habe ich es kapiert - war nicht bloed geschrieben, sondern
ich hatte DB und DBConnection durcheinandergebracht. Im Prinzip ist
das aehnlich zu meinem eigenen Ansatz, nur eleganter... Vielleicht
stelle ich das sogar noch um, nach aussen hin macht es ja keinen
Unterschied.

Servus,
Stefan

--
http://kontaktinser.at/ - die kostenlose Kontaktboerse fuer Oesterreich

Stefan - denn beschwerliche Liebe macht nimmerdar.
(Sloganizer)
Stefan+Usenet [ Di, 13 November 2007 12:34 ] [ ID #1869629 ]
PHP » de.comp.lang.php.misc » Missbrauch statischer Methoden

Vorheriges Thema: Suche Bildergalerie die bestehende Verzeichnisstruktur nutzt
Nächstes Thema: Dynamisch erzeugtes PDF als Mail-Anhang