Alexander (HH): FileHandle in Objekt mitführen

Beitrag lesen

Moin Moin!

Moin,

Tie::StdHash und Tie::ExtraHash sind bekannt?

Ich muss nochmal nachfragen, ein tied(%hash) sieht z.B. so aus:

bless({ 1 => "Eins", 2 => "Zwei" }, "HashFile")

Fang mal RTFM mit Tie::ExtraHash an.

Das Innenleben eines tied Hash und seine Außendarstellung müssen nicht zwangsläufig etwas miteinander zu tun haben.

Du kannst z.B. aus TIEHASH() auch völlig schmerzfrei eine blessed Array Reference zurückgeben (oder beliebige andere blessed References, seien es Scalare, Hashes oder Globs; Code- und Regexp-Referenzen müßten auch funktionieren, fraglich nur, ob das sinnvoll ist). Perl will nur irgendein Objekt haben, auf dem es die diversen Methoden aufrufen kann. Wie die Methoden zu ihren Ergebnissen kommen, ist völlig egal. Du mußt nicht einmal zwingend von irgendeiner Klasse erben, Du mußt nur die paar benötigten Methoden zur Verfügung stellen.

Tie::ExtraHash ist als blessed Array Reference implementiert, bei der das erste Array-Element (Index 0) eine Hash-Referenz enthält, aus der die in Tie::ExtraHash definierten Methoden die normale Funktion eines Hashes nachbauen. Die restlichen Elemente des Arrays stehen zur freien Verfügung. Dort könntest Du z.B. ein Filehandle ablegen.

Es ist nicht einmal notwendig, dass Du im Inneren des Objekts überhaupt irgendwelche Daten speicherst. In Deinem Beispiel könntest Du den Filehandle selbst als Objekt benutzen (blessed Glob Reference à la IO::Handle), oder (für etwas leichter lesbaren Code) als erstes und einziges Element in eine blessed Array Reference packen. Jeder Zugriff auf den tied Hash würde dann direkt zu Dateizugriffen führen. Mit Storable ist der Zugriff auf einzelne Hash-Elemente allerdings nicht sonderlich einfach (weil nicht vorgesehen). Letztlich müßtest Du jedes mal eine temporäre Variable mit dem gesamten, deserialisierten Dateiinhalt füllen.

Würdest Du stattdessen den Hash in einer primitiven SQLite-Tabelle vorhalten (und die Werte auf Strings beschränken), wäre es problemlos möglich, im Objekt nur ein DBI-Connection-Handle zu halten, das STORE() via insert/update, FETCH() via select, EXISTS() und SCALAR() via select count(*), DELETE() und CLEAR() via delete implementiert. Für FIRSTKEY()/NEXTKEY() müßtest Du entscheiden, ob Du beim Aufruf von FIRSTKEY() einmalig alle Keys in ein Hilfsarray ziehst oder ein DBI-Statement-Handle aktiv läßt; das dürfte vom Umfang der Tabelle abhängen. Bei einer Arrayref-basierenden Implementierung böte es sich an, das Connection-Handle im Index 0 zu halten und je nach Lösungsweg entweder das Statement-Handle im Index 1 oder ab Index 1 temporär alle gelesenen Keys. Wahlweise natürlich auch in Index 1 eine Arrayref mit allen Keys.

Um noch einmal auf die Klasse zurückzukommen, die den tied Hash implementiert: Du mußt wie gesagt nicht von einer "magischen" Klasse erben, Du kannst, wenn es Dir hilft, von JEDER Klasse erben. IO::Handle und die davon abgeleitete IO::File-Klasse implementieren die für tied Hashes notwenigen Methoden nicht, aber sie bieten alles, was Du brauchst, um ein Dateihandle in ein Objekt zu verpacken. Wenn Du also Deine tied-Hash-Klasse von IO::File erben läßt und einfach nur die tied-Hash-Methoden hinzufügst, bekommst Du automatisch ein Objekt, dass ein Dateihandle beinhaltet. Eigene Objekt-Attribute kannst Du beliebig hinzufügen, das ist z.B. in IO::Socket zu sehen, die Konventionen sind in IO::Handle dokumentiert.

Alexander

--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".