OOP in PHP – Teil 2: Klassen und Objekte

Nachdem wir uns im letzten Teil der Serie einen groben Überblick über die Objektorientierte Programmierung verschafft haben geht es nun ans Eingemachte: Wir benötigen Klassen und die daraus erzeugten Objekte. In diesem Artikel beleuchten wir genau, wie wir Klassen definieren und wie wir aus einer Klasse Objekte erzeugen können.

Was ist eine Klasse?

Eine Klasse können wir uns vorstellen wie den Bauplan für ein Haus. Sie enthält Informationen, wie die späteren Objekte aufgebaut sind, welche Eigenschaften und Fähigkeiten sie besitzen können und ähnliches. Genau wie bei einem Bauplan können aber auch aus einer Klasse beliebig viele Objekte erzeugt werden. Und genau wie das erste Haus blau und das zweite Haus grün angestrichen sein kann sind auch die Werte der Eigenschaften bei jedem erzeugten Objekt verschieden. Ich definiere also innerhalb einer Klasse, welchen Eigenschaften man in einem Objekt einen Wert zuweisen kann und welche Fähigkeiten jedes Objekt haben soll.

 

Wie definiere ich eine Klasse?

Eine Klasse besteht grundsätzlich aus nur drei Einzelteilen:

  1. Das Schlüsselwort class
  2. Ein eindeutiger Name
  3. Ein Codeblock, in dem dann später Attribute und Methoden definiert werden

Mit diesen wenigen Zeilen Code informieren wir den PHP Interpreter darüber, dass es eine Klasse mit dem Namen MyClass gibt. Doch wie wir sehen ist der Codeblock noch leer, MyClass besitzt also bisher weder Eigenschaften noch Methoden.

Eigenschaften

Geben wir unserer Klasse nun noch Eigenschaften. Dafür erweitern wir den Codeblock einfach um folgende Zeilen:

Damit haben wir MyClass um zwei Eigenschaften erweitert: color und age. Jedes Objekt, dass nun aus dieser Klasse erzeugt wird, besitzt die möglichen Eigenschaften Farbe und Alter. Der Wert kann sich aber für jedes Objekt unterscheiden, wir können also beispielsweise ein grünes, ein blaues und ein rotes Objekt haben.

Die beiden Schlüsselwörter public und private vor den Eigenschaften sind sogenannte Sichtbarkeiten. Diese regeln den Zugriff auf diese Eigenschaften, public bedeutet die Eigenschaft kann von überall (auch außerhalb der Klasse) verändert werden, private kann nur von innerhalb der Klasse verändert werden. Doch dazu kommen wir später nochmal genauer. Bei Eigenschaften muss eine solche Sichtbarkeit bei der Definition angegeben werden.

Unseren beiden Eigenschaften haben wir hier direkt einen Standardwert gegeben, nämlich blau und 10. Wird dieser Wert nicht überschrieben haben alle Objekte aus dieser Klasse standardmäßig die Farbe blau und das Alter 10.

 

Methoden

Genau wie unsere Eigenschaften können wir auch Methoden innerhalb des Codeblocks definieren. Die Reihenfolge ist hierbei vollkommen egal, eine Konvention ist aber, Eigenschaften vor den Methoden zu definieren.

Wie wir sehen werden Methoden in einer Klasse gleich definiert wie Funktionen außerhalb. Der einzige Unterschied ist die Sichtbarkeit. Diese kann bei Methoden allerdings auch ausgelassen werden, Methoden ohne Sichtbarkeit sind automatisch public!

In der printAge() Methode sehen wir zwei Besonderheiten:

  1. Die Variable $this steht innerhalb einer Methode immer für das aktuelle Objekt. Sie verweist also auf das Objekt, von dem die Methode aufgerufen wurde. Innerhalb von Methoden greifen wir also mithilfe dieser Variable auf die Eigenschaften des Objekts zu.
  2. Der Pfeil ( -> ) hinter $this ist der Operator, mit dem wir auf Eigenschaften und Methoden eines Objekts zugreifen. Dieser wird immer im Objektkontext eingesetzt. Ganz wichtig: Wenn wir mit einem Pfeil auf eine Eigenschaft zugreifen benötigen wir kein Dollarzeichen nach dem Pfeil!

Auch bei den Methoden haben die Sichtbarkeiten die gleiche Funktion. Ich kann die Methode printAge() also nicht von außerhalb meiner Klasse MyClass aufrufen, ich kann sie jedoch zum Beispiel innerhalb der Methode helloworld() mit $this->printAge() aufrufen.

Das Objekt

Nachdem wir uns nun ausgiebig darum gekümmert haben, das spätere Objekt zu beschreiben, gilt es nun, dieses auch zu erzeugen. Das funktioniert ganz einfach mit dem Schlüsselwort new:

Mit dieser Zeile erzeuge ich ein Objekt vom Typ MyClass mit allen Eigenschaften, die ich in der Klasse definiert habe, und speichere es in der Variable $myObject ab. Über diese Variable kann ich ab sofort auf mein Objekt zugreifen indem ich zum Beispiel die Farbe (da diese die Sichtbarkeit public hat) auf rot ändere:

Auch hier ist wieder der Pfeil zu beachten und nicht vergessen: Nach einem Pfeil benötigen wir kein Dollarzeichen!

3 Kommentare zu “OOP in PHP – Teil 2: Klassen und Objekte

  1. Hallo Frank,

    ich habe da mal eine wahrscheinlich ziemlich blöde Frage aber ich hoffe du kannst da kurz etwas zu sagen.

    Wenn ich mit (new) ein neues Klassenobjekt erstelle, dann ist der Name doch die Referenz für eine Datei auf dem Server, oder?
    Nach durchlaufen des Codes wird diese Datei dann wieder gelöscht. Bekommt jeder Benutzer bei einem Seitenaufruf eine eigene Instanz?

    Wie soll ich das nur beschreiben?
    Für ein Projekt wollte ich mir eine Klasse schreiben, die Seitennamen überprüft und dann über include einbindet. Die Idee war, die Sicherheit zu erhöhen, in dem Projektseiten außschließlich über einen bestimmten Seitenaufruf möglich sein sollen. An die Adresse wird einfach ein GET Parameter angehängt. (http://www.adresse.de?go=seitenname) Eine htaccess Datei verhindert, dass die Seiten direkt über die Adresszeile angesprochen werden können.
    Soetwas wie (http://www.adresse.de/pages/seite.php) ist also nicht möglich.

    Der Konstruktor liest jetzt diesen GET Parameter aus und vergleicht den Inhalt mit einer whitelist. Das ist ein einfaches Array, in dem der Dateiname steht und dazu noch eine Berechtigung eingetragen ist. Darüber wird entschieden ob die Seite öffentlich ist oder nur nach einer Anmeldung angeschaut werden darf.
    ($page_rights = array(„home“ => 0, „contact“ => 0, admin => 1);)

    Ist die Seitenanforderung in Ordnung, wird die jeweilige Datei eingebunden. Wenn nicht, dann wird immer die Startseite des Projektes angezeigt.

    So weit so gut, es funktioniert bis hierher aber ich teste die Anwendung ja auch nur für mich alleine. Wenn ich die Seite aufrufe, wird für mich ein neues Klassenobjekt erstellt. Es wurde z.B. ein Klassenobjekt $page angelegt. Wenn die Anwendung jetzt von mehreren gleichzeitig benutzt wird, dann wird doch immer nur dasselbe Klassenobjekt mit dem Namen $page benutzt. Dabei ist $page ja nur der Zeiger auf die Systemdatei. Hier wird es doch dann zu Überschneidungen kommen. Die einen URL Requests sind völlig in Ordnung, andere vielleicht nicht.

    Jedes mal wenn die Seite neu geladen wird, dann wird ein neues Klassenobjekt erstellt, aber immer unter demselben Namen. Müßte nicht, damit jeder Überprüfungsvorgang für sich eigenständig abläuft, für jeden Seitenaufruf ein eigenständiges Klassenobjekt erstellt werden? Zum Beispiel durch das Anhängen einer uniqid().

    Dasselbe würde ja dann auch bei einer Klasse für z.B. einen Fileupload passieren wenn zwei Benutzer gleichzeitig ein Bild hochladen.

    Es ist wahrscheinlich totaler Käse was ich schreibe aber es iritiert mich im Moment. Bevor ich das nicht weiß, brauche ich ja garnicht weiter arbeiten.

    Gruß
    René

    • Hi René,

      wow, was für ein Roman. 😉

      Da hast du noch was falsch verstanden, Klassen haben nichts mit Dateien zu tun. Eine Klasse ist einfach eine Sammlung von Werten im Speicher.
      Wenn du beispielsweise die Variable $x = 5; speicherst bekommt ja auch nicht jeder Besucher, der das Script gleichzeitig ausführt, dieselbe Variable $x sondern jeder einzelne Besucher hat eine eigene Version davon. Besucher 1 hat seine Variable $x z.B. an Speicheradresse 10, Besucher 2 hat sie aber an Speicheradresse 20 (natürlich sind die Werte anders ;)).

      Klassen funktionieren genau gleich. Wenn du Klassen anlegst und dann instanzierst (also ein Objekt mit new daraus erzeugst) werden alle Werte des Objekts (bei dir zum Beispiel die page_rights) im Speicher angelegt – aber für jeden Besucher der Seite woanders. Genau aus diesem Grund benötigst du ja auch eine Datenbank, damit du Daten unter mehreren Benutzern „teilen“ kannst (also wenn Benutzer 1 zum Beispiel einen Kommentar hinzufügt damit Benutzer 2 diesen auch sieht). Würde sich das nicht unterscheiden könnte man ja einfach ein Array mit Kommentaren befüllen und alle Nutzer können diese sehen.

      Was Klassen mit Dateien zu tun haben ist eigentlich nur, dass es ein Standard ist, dass jede Klasse in einer eigenen Datei definiert wird. Das hat zwei Vorteile:

      1. Der Code wird übersichtlicher. Mit ein oder zwei Klassen kann man auch alles in eine Datei schreiben aber versuch das mal mit zweihundert Klassen – da findest du nix mehr. Deshalb strukturiert man das in verschiedenen Ordnern und in einzelne Dateien. Dabei heißt die Datei normalerweise genau gleich wie die Klasse was zu Vorteil 2 führt:
      2. Man kann in PHP sogenanntes Autoloading einstellen. Das heißt ganz einfach ich muss nicht mehr mit require() arbeiten, um bestimmte Klassen „bekannt“ zu machen sondern wenn es richtig eingestellt wurde erkennt PHP automatisch „Ah, er will eine Klasse und ich hab Autoloading definiert. Schauen wir doch mal, ob es eine Datei mit dem Namen der Klasse gibt und binden diese automatisch ein.“. Auch hierbei bekommt natürlich jeder Besucher wieder eine eigene „Version“ davon (wie gesagt, Scripts teilen untereinander nichts).

      Ich hoffe, das hat geholfen. Wenn nicht, frag ruhig nochmal nach.

      Viele Grüße
      Frank

      • Hallo Frank,

        einach super erklärt, genau das wollte ich wissen.
        Meine Angst war, dass sich da ggf. was überschneidet. Mich hat es iritiert, dass PHP weiß, dass der Aufruf des Klassenobjekts $page bei Benutzer A auf die Speicherstelle x verweist und ebefalls das Klassenobjekt $page von Benutzer B auf die Speicherstelle y.
        Denn wenn ich verschiedene Klassenobjekte haben möchte, dann würde ich sie ja mit ($page1 und $page2) aufrufen.

        Der blanke Horror, dass Seitenbesucher 2 Werte aus dem $page von Besucher 1 bekommt. Eine Methode meldet, die URL ist in Ordnung, da haut es schon die nächste Seitenanfrage von einem anderen Besucher rein, die vielleicht nicht in Ordnung ist. Denn eines ist klar, jede Anfrage muss für sich überprüft werden. Dafür schreibe ich ja extra eine Methode.

        Ein anderes Beispiel wäre, dass 2 verschiedene Benutzer zeitgleich ein Bild auf den Server laden. Die Klasse bei Benutzer 1 meldet, dass die ausgewählte Datei zu gross ist, das Bild von Benutzer 2 ist aber in Ordnung.

        Wunderbar wenn sich PHP um die Verwaltung kümmert, das vereinfacht die Sache natürlich enorm.
        Okay, die Idee mit uniqid() für jedes neue Klassenobjekt war Mumpitz.

        Vielen Dank für deine Hilfe, dann kann ich ja jetzt weiter rumstümpern. 😉

        Gruß
        René

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

*