Schrift
Wiki:Tipp zum Debugging: use Data::Dumper; local $Data::Dumper::Useqq = 1; print Dumper \@var;
[thread]2092[/thread]

Programmgerüst und Gültigkeitsbereiche

Leser: 3


<< |< 1 2 3 >| >> 21 Einträge, 3 Seiten
tonewheel
 2007-04-13 12:24
#23664 #23664
User since
2006-10-01
182 Artikel
BenutzerIn
[default_avatar]
Hallo,

bevor ich in "Allgemeines zu Perl" wegen offtopic eins um die Ohren kriege, frage ich lieber hier, könnte ja sein, dass es sinnlos ist. :-)

Nach der letzten Diskussion gebe ich Perl den Vorzug vor Ruby und will nun mal beginnen, irgendwas zu programmieren (nein, ich programmiere kein 3D-Spiel und ich frage auch nicht nach einem Baukasten dafür!)

Ich dachte an eine Dateiverwaltung in der Form, dass man verschiedene Dokumente auf der Platte und diverse eMails in einem eMail-Client in einem Projekt zusammenfassen und bei Bedarf aufrufen kann (naja, ist halt was Allgemeines und Kleines).

Ich arbeite unter Linux, obwohl ich beim Mail-Client Outlook im Sinn habe, was dann Automation (Ole32) betrifft. Aber diesen Teil schiebe ich vorerst nach hinten.

Was mir zum Start eigentlich wichtig ist, sind folgende Dinge;

Gibt es in/für Perl gewisse Regeln, um das Klassendesign festzulegen? Wie ich das anhand von Doku und Beispielen gesehen habe, handelt es sich dabei um eine gleichnamige Verzeichnisstruktur. Das ist die Frage nach dem Grüst im Subjekt.

Dazu käme, wenn man nach MVC-Modell programmieren will, ist dann die Model-Klasse = DBI und alle Zugriffe (z.B. mySql) werden im View-Teil implenentiert, oder baut man eine extra Model-Klasse, die nur DBI included? (Hierzu muss ich erwähnen, dass mir die Existenz und Funktionsweise von SQL, bzw. mySQL bewusst ist, ich das aber z.B. bei C# noch nie benutzt habe)

Kann kurz jemand Gültigkeitsbereiche von Variablen erklären, wenn sie in Modulen, bzw. Klassen enthalten sind? Kann man Variablen überhaupt kapseln? Und würde das auch für das Moose Modul so zutreffen?

Kurzum, wie würdet Ihr sowas aufbauen? Ich will keine Programmcodes oder Vorlesen der Dokus, sondern einfach nur ein paar Tipps und vielleicht eine Angabe zu den benötigten Modulen, damit ich mir diese in Perldoc genauer ansehen kann.

Danke und Grüße
renee
 2007-04-13 12:39
#23665 #23665
User since
2003-08-04
14371 Artikel
ModeratorIn
[Homepage] [default_avatar]
TIMTOWTDI! (There is more than one way to do it)

Frage 3 Perl-Programmierer und Du wirst 5 Antworten erhalten ;-)

Aber nun zu Deinen Fragen...

In der Regel werden die Klassen in der Verzeichnisstruktur abgebildet, aber man *kann* auch mehrere Klassen in eine Datei schreiben (was ich aber *nicht* empfehlen würde).

Wie weit Du die Aufsplittung der Klassen betreibst hängt von den persönlichen "Vorlieben" ab. Gerade Java-Programmierer übernehmen häufig ihre Gewohnheiten und haben ruckzuck eine riesige Sammlung von Klassen.

Wenn Du auf SQL verzichten willst, solltest Du Dich mit Modulen wie CPAN:Class::DBI oder CPAN:DBIx::Class befassen. Damit lässt sich die Datenbank sehr leicht vom Perl-Code trennen.

In den View-Teil würde man keine SQL-Abfragen schreiben, das ist eher was für den Controller-Teil.

Richtig Kapseln kannst Du Variablen nur, wenn Du my einsetzt.

Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/perl

package Test;

use strict;
use warnings;

my $test = 'Test';
our $VERSION = 0.01;

package main;

print $Test::test,"\t",$Test::VERSION,"\n";


Das hat aber den Nachteil, dass es nur eine Variable für die Klasse gibt

Code (perl): (dl )
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
#!/usr/bin/perl

package Test;

use strict;
use warnings;

my $test = 'Test';
our $VERSION = 0.01;

sub new{
    my ($class,$value) = @_;
    $test = $value;
    bless {},$class;
}

sub ptest{
    print $test,"\n";
}

package main;

my $obj1 = Test->new(1);
$obj1->ptest;
my $obj2 = Test->new(2);
$obj2->ptest;
$obj1->ptest;


Üblicherweise nimmt man die Objektattribute mit ein den Hash des Objekts. Dann kann man zwar "von außen" zugreifen, aber normalerweise macht man das nicht.

Mit Moose kann man das Kapseln ganz gut nachbilden, aber das wird Dir Ronnie besser erklären können.
OTRS-Erweiterungen (http://feature-addons.de/)
Frankfurt Perlmongers (http://frankfurt.pm/)
--

Unterlagen OTRS-Workshop 2012: http://otrs.perl-services.de/workshop.html
Perl-Entwicklung: http://perl-services.de/
Ronnie
 2007-04-13 12:47
#23666 #23666
User since
2003-08-14
2022 Artikel
BenutzerIn
[default_avatar]
Es gibt Frameworks wie Catalyst, Jifty, oder Gantry - die können dir viel Arbeit abnehmen. Für MVC Applikationen verwende ich (also völlig subjektiv), die Regel das der Controller die Datenbankverbindung herstellt und an die Modelle übergibt, sodass nur ein DBH benötigt wird. Die Modelle sind Klassen, die z.B. die CRUD-Operationen auf eine Zeile der Tabelle abbilden und Klassen, die auf diese Basisklassen zurückgreifen um komplexere Operationen zu ermöglichen. Prinzipiell besteht die Möglichkeit einen OR-Mapper wie CPAN:DBIx::Class zu verwenden, aber ich bevorzuge eigene Klassen zu erstellen. Die Views sind bei mir ausschließlich Templates, i.A. CPAN:HTML::Template::Compiled Templates.
Variablen haben, wenn sie mit my deklariert sind, einen lexikalischen Gültigkeitsbereich. Wenn man direkt auf Variablen aus Modulen zugreifen will, muss man diese exportieren. Ich bevorzuge eh objektorientierte Module, dann schreibt man einen Getter/Setter oder überlässt das z.B. CPAN:Moose.
tonewheel
 2007-04-13 17:03
#23667 #23667
User since
2006-10-01
182 Artikel
BenutzerIn
[default_avatar]
Hallo,

Erstmal danke für die Antworten!

@renee: my $x ist also nur paketweit (oder innerhalb blöcken) gültig. Und our $y wäre dann wie static bei C/Java? Sind diese dann innerhalb der Datei (in verschiedenen Namensräumen) oder Systemweit gültig (also auch in den Modulen, die dieses Modul included haben)? Mit den Modulen muss ich mir wohl einen Überblick verschaffen, ich dachte, es gäbe nur DBI::nnn, wobei nnn für verschiedene Datenbanken (mySql, Postgresql, etc) steht. Dass es Class::DBI und DBIx::Class gibt, bzw, was der Unterschied ist, ist mir im Moment noch unklar.

@ronnie: Ich wollte vorerst in Richtung Programmieren gehen, also mit irgendeinem WidgetSet, nicht auf Web-Basis, in dessen Richtung Catalyst laut letzter Diskussion geht. Nochwas zum Verständnis; sind alle Module automatisch Klassen, oder erstmal nur Namensräume mit Ansammlungen von statischen Methoden? Falls ich ein Modul verwende (und im Falle dessen, das eine Klasse ist), kann ich dessen Instanzen als sowohl Aggregation als auch als Assoziation in meine eigenen Klassen/Objekte einbinden, bzw. macht das überhaupt Sinn, oder geht man bei Perl andere Wege?
Falls ich Moose verwende, lässt sich dieses Konzept dann mit den "normalen" Klassen (vorhandener Module wie z.B. DBI) kombinieren (also was Aggregation und Assoziaion betrifft)?
tonewheel
 2007-04-13 17:04
#23668 #23668
User since
2006-10-01
182 Artikel
BenutzerIn
[default_avatar]
(Hmmm, sorry, war doppelter Beitrag)\n\n

<!--EDIT|tonewheel|1176469499-->
renee
 2007-04-13 18:46
#23669 #23669
User since
2003-08-04
14371 Artikel
ModeratorIn
[Homepage] [default_avatar]
[quote=tonewheel,13.04.2007, 15:03]Hallo,

Erstmal danke für die Antworten!

@renee: my $x ist also nur paketweit (oder innerhalb blöcken) gültig. Und our $y wäre dann wie static bei C/Java? Sind diese dann innerhalb der Datei (in verschiedenen Namensräumen) oder Systemweit gültig (also auch in den Modulen, die dieses Modul included haben)? Mit den Modulen muss ich mir wohl einen Überblick verschaffen, ich dachte, es gäbe nur DBI::nnn, wobei nnn für verschiedene Datenbanken (mySql, Postgresql, etc) steht. Dass es Class::DBI und DBIx::Class gibt, bzw, was der Unterschied ist, ist mir im Moment noch unklar.[/quote]
Ja, die sind ähnlich wie die static-Variablen bei Java. Du kannst von jedem Modul, das die Klasse einbindet die Variable über den vollen Namen (also $PACKAGE::variable) ansprechen.

CPAN:Class::DBI bzw. CPAN:DBIx::Class sind einfach nur Module, die einem die Arbeit mit SQL abnehmen. Allerdings muss man trotzdem SQL-Kenntnisse haben, damit man vernünftig damit arbeiten kann. Man muss ja schließlich wissen, welche Tabellen wie miteinander verknüpft werden sollen.

In der Frühjahrs-Ausgabe von $foo gibt's einen kleinen Einführungsartikel in CPAN:DBIx::Class.
OTRS-Erweiterungen (http://feature-addons.de/)
Frankfurt Perlmongers (http://frankfurt.pm/)
--

Unterlagen OTRS-Workshop 2012: http://otrs.perl-services.de/workshop.html
Perl-Entwicklung: http://perl-services.de/
tonewheel
 2007-04-14 09:49
#23670 #23670
User since
2006-10-01
182 Artikel
BenutzerIn
[default_avatar]
Quote
In der Frühjahrs-Ausgabe von $foo gibt's einen kleinen Einführungsartikel in CPAN: DBIx::Class.

Ok.
Ich verstehe die Syntax der Form __PACKAGE__->method nicht. Ist das eine Art Vererbung oder Überschreiben von Methoden? Ist __PACKAGE__ ein Schlüsselwort oder hier als Platzhalter eingesetzt?
renee
 2007-04-14 11:24
#23671 #23671
User since
2003-08-04
14371 Artikel
ModeratorIn
[Homepage] [default_avatar]
Das ist eine besondere Variable und liefert Dir den aktuellen Package-Namen:
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/perl

use strict;
use warnings;

package Test;

sub test{
    print __PACKAGE__,"\n";
}

package NochEinTest;

sub test{
    print __PACKAGE__,"\n";
}

package main;

print __PACKAGE__,"\n";
Test->test;
NochEinTest->test;


Ausgabe:
Code: (dl )
1
2
3
4
C:\>perl package.pl
main
Test
NochEinTest


Hier noch was zu CPAN:Class::DBI: http://www.perl.com/pub/a/2003/07/15/nocode.html
OTRS-Erweiterungen (http://feature-addons.de/)
Frankfurt Perlmongers (http://frankfurt.pm/)
--

Unterlagen OTRS-Workshop 2012: http://otrs.perl-services.de/workshop.html
Perl-Entwicklung: http://perl-services.de/
Ronnie
 2007-04-14 13:04
#23672 #23672
User since
2003-08-14
2022 Artikel
BenutzerIn
[default_avatar]
[quote=tonewheel,13.04.2007, 15:03]Nochwas zum Verständnis; sind alle Module automatisch Klassen, oder erstmal nur Namensräume mit Ansammlungen von statischen Methoden? Falls ich ein Modul verwende (und im Falle dessen, das eine Klasse ist), kann ich dessen Instanzen als sowohl Aggregation als auch als Assoziation in meine eigenen Klassen/Objekte einbinden, bzw. macht das überhaupt Sinn, oder geht man bei Perl andere Wege?
Falls ich Moose verwende, lässt sich dieses Konzept dann mit den "normalen" Klassen (vorhandener Module wie z.B. DBI) kombinieren (also was Aggregation und Assoziaion betrifft)?[/quote]
Also, Module sind erstmal nur Namensräume. Nur wenn man den Perl-typischen weg wählt und einen Konstruktor definiert, wird daraus eine Klasse. Moose-Objekte sind quasi klassische Perl-Objekte, also 'gesegnete' Hash-Referenzen. Sie habe auch die selben Schwächen, also eine nur bedingt taugliche Kapselung. Wer direkt auf den Inhalt des Hashs zugreift wird daran nicht gehindert. Die Accessoren können dies aber sehr wohl, sogar mit Typprüfung wenn es sein muss. Wer echte Kapselung in Perl will, der kommt um eine InsideOut Lösung wie CPAN:Class::InsideOut nicht drumrum.

Deine Frage mit der Aggregation und Assoziation ist mir nicht klar, kann also erstmal keine vernünftige Antwort bieten.
sid burn
 2007-04-14 18:51
#23673 #23673
User since
2006-03-29
1520 Artikel
BenutzerIn

user image
Also die Variablenarten von Perl nämlich lexikalische Variablen und Package Variablen finde ich da doch etwas schwerer sie vernünftig zu erklären. Und reenes Beispiel fande ich auch eher ein schlechtes Beispiel ohne weitere Erklärung. Und wenn du reenees beispiel etwas abänderst:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/perl

package Test;

use strict;
use warnings;

my $test = 'Test';
our $VERSION = 0.01;

package main;

print $test,"\t",$Test::VERSION,"\n";

Dann würde als Ausgabe nun sehr wohl "test" und "0.01" ausgegeben werden.

Um es sogar kurz zu sagen hat eine lexikalische Variable überhaupt keine Auswirkung in welchem Package du dich befindest. In Reenees Beispiel wird überhaupt gar nix gekapselt.

Es erscheint nur deswegen nicht 'Test' in der Ausgabe weil er auf eine Package Variable Namens $Test::test zugegriffen hat. Die hat er aber nie angelegt. Er hat eine lexikalische Variable angelegt.

Er hätte genauso gut $Test::birne hinschreiben können. Wäre das selbe gewesen. Das ganze hat nichts mit Kapselung am Hut.

----------

1) Es gibt zwei Arten von Variablen. Wie bereits gesagt existieren sogenannte Lexikalische Variablen und sogenannte Package Variablen.

2) Lexikalische Variablen haben ihren eigen Namesraum. Der Namensraum wird durch einen Block, oder wenn er nicht vorhanden maximal auf die Datei begrenzt

3) Package Variablen sind wie gesagt an Ihrem package gebunden. Sie sind letztendlich auch von überall aus zugreifbar und änderbar.

4) Um es nochmal Explizit zu sagen. Lexikalische Variablen sind "NICHT" an einem Package gebunden. Ob du eine lexikalische variable nun im Package A, B oder C deklarierst interessiert die lexikalische variable nicht. Sie wird lediglich durch einen Block oder die Datei begrenzt. Wenn du also eine lexikalische Variable deklarierst im package A und danach ins package Z wechselt hat es einen Effekt auf Package variablen, aber nicht auf die lexikalische. Bei dem wechseln hast du keinen Block oder die Datei ist zu ende. Es gilt also immer noch der selbe Gültigkeitsbereich für lexikalische Variablen

5) Wenn du Package Variablen mit "our" Deklarierst wird als Nebeneffekt noch zusätzlich eine lexikalische Variable erzeugt, die auf die Package variable zeigt.

6) Lexikalische Variablen werden immer vor Package Variablen genutzt.

So hier mal Beispiele:

Code: (dl )
1
2
3
4
5
6
7
8
9
#!/usr/bin/perl
use strict;
use warnings;

package Test;
my $string = "Hallo, Welt!\n"

package main;
print $string;

Dieses Beispiel gibt "Hallo, Welt!\n" aus. Es wurde eine lexikalische Variable $string erzeugt. Wie bereits gesagt haben lexikalische Variablen Ihren eigenen gültigkeitsbereich, und sind an Blöcke oder die Datei begrent. Bei der Deklaration befand sich $string in keinem Block, ist also für die ganze Datei gültig. Das du nebenbei noch vorher und nachher das package änderst Interessiert die lexikalische Variable nicht die Bohne!

Code: (dl )
1
2
3
4
5
6
7
8
9
#!/usr/bin/perl
use strict;
use warnings;

package Test;
our $string = "Hallo, Welt!\n"

package main;
print $string;

Dieses Codeschnipsel funktioniert identisch zum Oberen und gibt wieder "Hallo, Welt!\n" aus. Es wurde zuersteinmal eine package variable in Test abgelegt: $Test::string und du wechselt danach nach main. Wenn du nun $string aufrufst passiert folgendes: Es wird zuerst geschaut ob eine lexikalische Variable vorhanden ist. Existiert keine dann wird versucht eine VAriable aus dem aktuellen package aufzurufen. Dies wäre dann eigentlich $main::string die es nicht gibt.

Aber halt! Es existiert eine lexikalische Variable! Les dir nochmal Punkt 5 durch. Als Nebeneffekt wird durch "our" eine lexikalische Variable erzeugt die letztendlich ein Alias auf die aktuelle Package variable. Sprich es wird zeitglich dazu eine lexikalische Variable erzeugt die auf $Test::string zeigt.

Und da Punkt 6 greift und lexikalische Variablen vor Package Variablen benutzt werden wird halt erfolgreich die Package Variable $Test::string ausgegeben.


Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/perl
use strict;
use warnings;

my $test = 'welt';

package X;
our $test = 'hallo';

package Y;
our $test = 'foo';

package main;
print $test;

Was wird ausgegeben?
Es wird "foo" ausgegeben. Als erstes erzeugst du zwar eine lexikalische Variable, aber diese wird durch den "our" Befehl überschrieben. Die lexikalische Variable zeigt nun auf $X::test anstatt den String "welt" zu enthalten.

Da das ganze ein Nebeneffekt von our ist, bekommst du nichtmal eine Fehlermeldung angezeigt das du eine variable überschreibst!

Danach wird wieder eine Package Variable in Y angelegt. Diese überschreibt wieder die lexikalische Variable und legt zuletzt ein Alias auf $Y::test an.

Zuletzt gibst du $test aus. Das letzte was halt passiert ist war das $test eine Zuweisung nach $Y::test war. Also wird auch $Y::test ausgegeben.

Wenn du die Variable aus dem Package X haben möchtest musst du dort nun den vollen Namen nutzen.

"print $X::test;"

Die Package Variablen an sich wurden ja nicht überschrieben, nur die lexikalische Variable immer wieder die ein Alias auf die Package Variable ist.

Das einzige worauf du nie mehr zugreifen kannst ist die erste Deklaration. Den es wurde ja genau diese Variable immer wieder überschrieben.


Um die Problematik zu umgehen kannst du bei mehreren Package Definition in einer Datei noch einen extra Block drum herum machen:
Code: (dl )
1
2
3
4
5
6
7
8
9
#!/usr/bin/perl
use strict;
use warnings;

{
package Test;
my $string = "Hallo, Welt!\n";
}
print $string;

Das wäre eine erfolgreiche Kapselung gewesen. Allerdiengs darf man sich wie gesagt nicht Irritieren lassen. $string ist nur deswegen nicht beim print zugreifbar weil die lexikalische Variable nur im Block Verfügbar ist. Die Package Deklaration hat damit überhaupt nichts zu tun.

Oberes beispiel könntest du also auch so schreiben
Code: (dl )
1
2
3
4
5
6
#!/usr/bin/perl
use strict;
use warnings;

{ my $string = "Hallo, Welt!\n" }
print $string;

Es wird eine Variable $string angelegt, allerdiengs ist der Block danach schon sofort wieder zu ende, sprich die Variable wird danach sofort wieder Zerstört (eigentlich wird der Referenzcounter um 1 Reduziert und nur wenn er 0 ist wird die Variable Zerstört, aber das ist jetzt erstmal unwichtig. ;) )


So ich hoffe abschließend das ich dich jetzt vollständig verwirrt habe. ;)

Wie gesagt man muss sich bewusst werden das es zwei Arten von Variablen gibt. Eigentlich ist das Konzeot dahinter nicht besonders schwer. Aber ich finde es am anfang doch recht verwirrend.\n\n

<!--EDIT|sid burn|1176562484-->
Nicht mehr aktiv. Bei Kontakt: ICQ: 404181669 E-Mail: perl@david-raab.de
<< |< 1 2 3 >| >> 21 Einträge, 3 Seiten



View all threads created 2007-04-13 12:24.