Du bist nicht eingeloggt.

Login

Pass

Registrieren

Community
Szene & News
Locations
Impressum

Forum / Bits und Bytes

( Tutorial ) Erweiterte PHP-Techniken

Zwerg1982 - 43
Halbprofi (offline)

Dabei seit 06.2004
125 Beiträge

Geschrieben am: 07.07.2004 um 16:23 Uhr
Zuletzt editiert am: 07.07.2004 um 16:30 Uhr

Teil 1

Einführung:

Ich heiße Dich willkommen und freue mich, daß Du Interesse gefunden hast, mein Tutorial anzugucken. Erstmal möchte ich natürlich festlegen, wem das Tutorial hilfreich sein könnte und was genau das Ziel ist.

Wenn erstmal die Zeit reif wird, in der man in der Lage ist eigene Scripte mit PHP zu entwerfen, stellt sich die Frage ob man nun viel/genug weiß, oder gibt es noch etwas, was PHP zu bieten hat? Die Antwort lautet eindeutig: "Ja, und ob!". Man lernt nie aus, egal in welcher Branche man sich befindet. Als Anfänger lernt man die Sprachkonstrukte der Sprache, die Benutzung und Sinn dessen. Die Praxis fördert dann eine Denkweise beim Entwurf und Verwirklichung von Ideen, die sich streng an den gelernten Stoff hällt - die Möglichkeiten und Einsatzgebiete der Sprache. Oft wird ein falscher Weg genommen und man lernt die Funktionen auswendig, was natürlich bedingt Fortschritte in der Entwicklung bringt und man auch nicht begreift, wozu PHP fähig ist.

Ohne, dass ich jetzt als Einführung einen Roman verfasse, zähle ich die Punkte auf, die als Voraussetzung dienen sollten, um mit dem Tutorial was anfangen zu könen:

- Du hast mit PHP bereits einige (kleine) Projekte entwickelt
- Du möchtest tiefer in PHP eindringen, Theorie verstehen
- Du möchtest erfahren, in welchen Bereichen sich OOP nützlich machen kann

Logik und Sinn einer Programmiersprache

Zwar ist PHP keine echte Programmiersprache, aber dennoch kann man sowohl eine schlechte wie auch eine gute Anwendung/Script damit schreiben. Aber wo sind die Grenzen von gut und schlecht? Unter schlecht kann/sollte man eine leichtsinnige, unüberlegte, „draufgemotzte“ Software vorstellen, die ohne sich als Programmierer Gedanken über das Design des Codes zu machen erstellt wurde. Eine gute braucht dagegen viel mehr als das. Aber das ist auch die Kunst, nach der ein guter Programmierer streben sollte.

Ich möchte jetzt auf Einzelheiten von PHP eingehen, die oft gar nicht beachtet werden und daher auch viele Fehler hervorrufen können, die nicht immer gleich erkennbar sind.

1 Operatoren
Operatoren sind in Programmiersprachen die Schnittstelle für den Programmierer, wenn es um logische Zusammenhänge geht. Daher liegt es klar auf der Hand, dass man damit bereits ein mächtiges Werkzeug hat, was aber auch unter Umständen zur Verwirrung führen kann. Lange Ausdrücke brauchen oftmals Klammern, um vor anderen Teilen des Ausdrucks ausgewertet zu werden. Zu beachten ist hier auch die Rangfolge von Operatoren. Es würde nichts als Unfug entstehen, wenn Operatoren diese nicht hätten.

Es folgen ein paar Beispiele:

PHP-Code:
// Rangfolge der Operatoren
$a = 5;
$b = 10;

$a + $a * 2 || 2 * $a + $a; // Ausdruck 1
$a == 10 && $a; // Ausdruck 2
$a == $a && 10; // Ausdruck 3
$b += $a != 10 + $a; // Ausdruck 4


Versuche diese vier Ausdrücke im Kopf zu durchlaufen. Danach kannst Du die Ausdrücke in einem PHP-Script ansehen. Stimmen die Ergebnisse überein? Wenn ja, dann arbeitest du wie ein PHP-Parser und zwar Schritt für Schritt. Sollten verschiedene Ergebnisse deine Welt in den Wahnsinn treiben – keine Panik, für alles gibt es eine logische Erklärung!

Im Ausdruck 1 werden der Operator +, * und || benutzt. Um auf ein Ergebnis zu gelangen, muss man wissen was zuerst zusammengefasst und ausgewertet wird. Dabei geht es nach der Priorität der drei Operatoren. Höchstens in der 6. Klasse weiß man, dass „Punkt- vor Strichrechnung“ kommt, was in PHP auch nicht anders ist. PHP wertet zuerst die *-, /-, %-Operatoren aus, bevor +, - und . dran sind. Erst danach findet der endgültige Vergleich der beiden Werte mit || statt. Also erhalten wir hier den Wert 1, true um genauer zu sein, da die Vergleichsoperatoren nur bool zurückliefern. Bei dem Ausdruck 2 kann schnell ein Denkfehler entstehen, obwohl da nur zwei Operatoren zur Wahl stehen. Tatsächlich ist der Operator == „stärker“ als && und es wird daher der boolesche Wert von $a == 10 schlussendlich mit dem &&-Operator verglichen, was in unserem Fall zu true führt. Die letzten zwei Beispiele enthalten ebenfalls leichte Verwirrungen, die man aber höchstens nach dem Durchgehen der Rangtabelle im PHP-Handbuch (s. Operatoren->Operator-Rangfolge) bewältigen sollte.

Jedenfalls verwirrend fand ich die Tatsache, dass die Operatoren and und or zwar das gleiche wie && und || tun, allerdings niedrigere Ränge haben, was manchmal vorteilhaft sein kann (häufigste Verwendung von or fiel mir bei „$var = $var2 or die();“ auf).

Was ist eher schlecht an folgendem Design?

PHP-Code:
// if-Verschachtelung
if ($var1)
{
if ($var2)
{
if ($var3)
{
//… usw.
}
}
}


Man versucht in der Hoffnung, dass soweit eine der drei Variablen false liefert, der Vorgang der weiteren Überprüfung sofort beendet wird, um keinen zusätzlichen Laufzeitaufwand zu erzeugen. Dabei wäre die Möglichkeit, die Ausdrücke mit && zusammenzufassen gar nicht schlechter/langsamer, sondern kürzer und übersichtlicher.

PHP-Code:
if ($var1 && $var2 && $var3) { /* … */ }


Sollte $var1 false zurückliefern, wird es gar nicht erst dazu kommen, dass $var2, $var3 auf false überprüft werden. Es bringt uns also keine Nachteile, die kurze Variante zu bevorzugen.
Um es an einem Beispiel zu demonstrieren kann es der Wert einer Funktion sein, die einen String auf Inhalt prüft, bei Erfolg und auch erst danach kann eine weitere Funktion aufgerufen werden, um den gleichen String in die Datenbank einzutragen.

Die meisten haben was von den Bit-Operatoren gehört. Einen Einsatz finden diese allerdings recht selten, vielleicht auch deswegen, weil man sie gar nicht beachtet, wenn eine Lösung gefunden werden soll. Dabei sind gerade diese Operatoren die Logik, der Grundstein für alles, was man mit den anderen Operatoren erreicht. Wie man vielleicht weiß, funktioniert ein CPU nur mit einem Paar an „Schaltungen“, die für den Menschen als logisch erscheinen sollen. Baut man diese weiter auf, so sind der Fantasie (fast) keine Grenzen gesetzt. Doch wo können die Bit-Operatoren eine praktische Verwendung finden?
Sagen wir mal Flags… was fällt uns dazu ein? Also Flags sind einfache Integers, die zur Übersicht als Konstanten definiert sind. Was könnte man denn machen, wenn eine Funktion mehrere von solchen Konstanten erwarten könnte? Sagen wir mal, wenn wir eine Funktion zur Darstellung einer Figur hätten. Es könnte ein Kreis sein, der im 2D, 3D, Farbe, Glanz usw. dargestellt werden könnte. Dabei kann es sein, dass man 3D, Farbe und Glanz in der Ausgabe haben will. Was nun? Sollte man für jede Einstellung einen Parameter anlegen? Und wenn es 10 Einstellungen möglich sein sollten? Eine Hilfe wäre jetzt eine Klasse oder Array, um die Elemente zusammenzufassen. Doch auch da müsste man jedes Mal viel Schreibarbeit anwenden, auch wenn nicht direkt in dem Funktionsrumpf. Angenehmer wäre es, wenn man die Einstellungen in einem Ausdruck übergeben könnte, ohne dafür besondere Methoden anzuwenden. Und da schaffen die Bit-Operatoren eine Abhilfe:
Wenn man bedenkt, dass jede dezimale Zahl vom CPU nur binär verstanden werden kann, heißt es auch, dass die einzelnen Bits sich nur zu verschieben brauchen, damit eine eindeutige Zahl entsteht. Im Dezimalsystem ist das natürlich nicht anders, wenn man 10 um eine Stelle (im Dezimalsystem ist die Basis 10) nach links verschiebt, bekommt man 100. Danach würde 1.000, 10.000… rauskommen. Was diese Tatsache allerdings für das Binärsystem interessant macht ist, dass man unsere Flags mit den Bitoperatoren zusammenfassen kann, auf die gleiche Weise wie das Beispiel mit der Zahl 10 als Basis. Im Binärsystem ist es die 2 als Basis, auf die die Bit-Operatoren auch spezialisiert sind.
Es folgt ein Beispiel mit unserer Funktion für Kreisdarstellung: (vereinfacht)

PHP-Code:
// Konstanten
define('OPTION_2D', 0x1); // Binär: 0001
define('OPTION_3D', 0x2); // Binär: 0010
define('OPTION_FARBE', 0x4); // Binär: 0100
define('OPTION_GLANZ', 0x8); // Binär: 1000

function Zeichne_Kreis($einstellungen)
{
if ($einstellungen & OPTION_2D) { /* … */ }
// …
}

// Aufruf der Funktion und Zusammenfassung von Einstellungen
Zeichne_Kreis(OPTION_2D | OPTION_FARBE | OPTION_GLANZ);


Was wir nun geschaffen haben ist ein zusammengesetzter Wert, der die einzelnen Einstellungen nicht „stört“. Es ist also nicht von Bedeutung, ob ich alle Einstellungen zusammenfasse oder nur eine einzelne an die Funktion übergebe – es wird das getan, was ich an die Funktion als Aufgabe/Argument übergebe. (vorausgesetzt die Funktion verhält sich richtig)
Ich empfehle denen, für die etwas Derartiges neu erscheint den Vorgang genauer anzugucken. Warum wird zum Vergleichen der &- und nicht der ==-Operator verwendet? Was macht man, wenn man den zusammengesetzten Wert auf viele Einstellungen hin in einem Rutsch überprüfen will? (z.B. OPTION_3D und OPTION_2D) (s. PHP-Handbuch->Operatoren->Bit-Operatoren)
Bit-Operatoren werden u.a. in der Kryptografie und Netzwerk verwendet. Interessiert sich einer z.B. für Verschlüsselungstheorien und Algorithmen, so ist es unausweichlich, die Bit-Operatoren zu benutzen.

Fazit: Prinzipiell sollte man immer die Operator-Ränge im Auge behalten, wenn ein komplexer Ausdruck geplant ist. Dabei spielen Klammern eine wichtige und manchmal unausweichliche Rolle.
Bit-Operatoren verstehen können kann nie direkt schaden, es öffnen sich neue Türen bei der Programmierung, die man durchaus auch nutzen könnte/sollte.

Tipps:
Vermeide nach Möglichkeit zu lange Ausdrücke mit vielen unterschiedlichen Operatoren. (fasse dich möglichst kurz)
Vermeide unüberlegte Ausdrücke (man kann sehr oft etwas verbessern, wenn man sich ein wenig Zeit lässt)
Benutze Klammern, um Übersicht im Ausdruck zu haben und/oder Teile mit niedrigen Operator-Rängen zuerst auswerten zu lassen


Teil 2

2 Funktionen
Was Funktionen sind brauche ich wohl nicht zu erklären, allerdings möchte ich einige extra Sachen hervorrufen, die mit Funktionen realisierbar sind.

So ziemlich jeder kennt die eingebaute PHP-Funktion printf(). Mit dieser lassen sich beliebig viele Argumente an die Funktion übergeben. Für eigene Funktionen gibt es diese Möglichkeit ebenfalls: ab PHP 4 stehen die speziellen Funktionen func_num_args() (für die Anzahl der übergebenen Argumenten), func_get_arg($x) (für ein Argument mit der Nummer $x) und func_get_args() (für ein Array mit allen Argumenten, die übergeben wurden) zur Verfügung. Obwohl die variable Anzahl an Argumenten praktisch erscheint, ist in den meisten Fällen ein Array die bessere Entscheidung. Mit Arrays lässt es sich einfach besser weiterarbeiten. Für Funktionen wie printf() eignet sich ein Array allerdings eher weniger, die Argumente können eine Beziehung zueinander haben und man sieht diese gleich im Funktionsrumpf. Außerdem ist der Aufruf einer solchen Funktion „konstant“, ich kann nicht wie bei einem Array zur Laufzeit des Scripts die Anzahl der Werte erhöhen, Werte entfernen und dann die Funktion aufrufen. Daher soll es gut überlegt sein, bevor man etwas Derartiges verwendet, wie ich aber bereits sagte ist es oftmals überflüssig.

Ein Thema, was vielen Anfängern Angst macht ist u.a. Rekursion. Man sagt auch, dass man erstmal die Rekursion verstehen muss, um die Rekursion zu verstehen. (oh ja, das heißt so) Warum sich viele davor fürchten ist mir nicht wirklich klar, denn es gibt Sachen, die hat ein Anfänger recht schnell drauf und die sind schwieriger als Rekursion zu verstehen. Ich versuche es aber trotzdem so gut es geht zu erklären, damit es eine gewisse Klarheit schafft.
Und zwar geht es darum, dass eine Funktion sich selbst aufrufen kann, ein Beispiel:

PHP-Code:
// Rekursive Funktion
function foo($arg)
{
if ($arg Untermenü). Man spart in dem Fall eine Schleifenstruktur, die unter Umständen komplexer aussehen könnte. Man sollte einfach einmal den Weg verfolgen, den der Aufruf von Funktionen macht. Es ist mit einem Telefonat vergleichbar, die Sekretärin verbindet den Kunden mit einem Fachangestellten, der wiederum mit einer weiteren Hotline… und schließlich wird man mit der richtigen Person verbunden - return übergibt den richtigen Wert aus den weiteren, verschachtelten Funktionsaufrufen.

Tipps:
Behalte im Auge, dass man Funktionen mit einer variablen Anzahl an Parametern definieren kann. Überlege Dir allerdings gut, ob das deiner Funktion gut tut
Eine Rekursion kann Schleifen ablösen und eine gut strukturierte Funktion aufbauen, ein Menü oder Stammbaum sind zwei Beispiele, für die es in Frage käme
3 Klassen
Viele wissen nicht, warum man Klassen und Objekte verwenden sollte. Wenn man schon ohne sie etwas bewegen konnte, stören die doch nur… Und das stimmt nicht, denn Klassen sind eine Abhilfe, um Übersicht im Code zu schaffen. Außerdem können Klassen eigene Variablen haben und stören deshalb nicht die „Außenwelt“. Eine gewisse Struktur und erweiterte Möglichkeiten bilden sich, wenn man das Prinzip von Klassen verstanden hat. Dabei muss es natürlich gut überlegt sein, wo Klassen geeignet wären.
Ein Beispiel wäre ein CMS, was die User verwaltet, es müssen User angelegt, gelöscht, editiert… werden. Macht man einzelne Funktionen für jede der Aktionen, so muss man jedes mal die Daten übergeben, die gefordert werden, um den User zu identifizieren. Gut, globale Variablen zu benutzen wäre eine Alternative, aber hätte man da noch eine Übersicht, wenn es komplexere Aufgaben z.B. mit mehreren Usern gelöst werden müssten? Mit einer Klasse wäre es einfacher – man würde sich auf die Gemeinsamkeiten der Userverwaltung alleine konzentrieren und hätte alles schöner und strukturierter realisieren können. Wir bauen also eine Klasse „User“ mit Methoden für das Editieren, Löschen, Anlegen der User. Im Konstruktor könnte man die Klassenelemente einmal initialiseren, mit denen man dann alle Methoden zum Laufen bringen würde. Und auch wenn zwei User verglichen werden müssten, geschieht es fast genauso wie mit eingebauten Variablen. Das schafft ein schönes Design und viele Möglichkeiten, die mit Funktionen für viel Wirbel sorgen würden.
Die Klasse:

PHP-Code:
class User
{
var $name;
var $passwort;
var $alter;
var $wohnort;

function User($name, $passwort, $alter, $wohnort)
{
$this->name = $name;
$this->passwort = $passwort
// …
}

function loeschen() { /* Lösche User */ }
function aendern() { /* Ändern */ }
function anlegen() { /* Anlegen */ }
}

// Objekte erzeugen:

$user_vater = &new User('Mustermann', 'geheim', 29, 'Berlin');
$user_sohn = &new User('Mustermann jr.', 'geheim', 10, 'Berlin');

// Wie alt wird Mustermann, wenn Mustermann jr. 18 ist?
$antwort = 18 - $user_sohn->alter + $user_vater->alter;


So lässt sich mit Klassen einiges anstellen, mein Beispiel ist das mindeste, was man machen könnte. Man hat mit PHP 4 allerdings recht wenige Techniken, um mit Klassen zu arbeiten, wenn man C++ oder Java anschaut. Trotzdem lassen sich in PHP 4 die Klassen vererben (s. extends), mit der Vererbung der Klasse kann man diese erweitern, die Möglichkeiten der Klasse werden also erweitert. Eine Klasse wie Wohnung könnte in der Klasse Haus vererbt werden, die Klasse Haus würde weitere Methoden definieren, was u.a. die erneute Schreibarbeit sparen würde.

Tipps:
Benutze ruhig Klassen, wenn Du der Meinung bist, dass bestimmte Operationen zusammengefasst werden könnten. Eine Klasse lässt sich leichter pflegen und erweitern
Bei vielen Methoden, die logisch gesehen weiter gespalten werden könnten, sollte man eine oder mehrere Vererbungen durchführen
JK91 - 35
Profi (offline)

Dabei seit 11.2006
465 Beiträge

Geschrieben am: 12.01.2007 um 20:58 Uhr

soll man das alles durchlesen ?!

bzzz ..

  [Antwort schreiben]

Forum / Bits und Bytes

(c) 1999 - 2026 team-ulm.de - all rights reserved - hosted by ibTEC Team-Ulm

- Presse - Blog - Historie - Partner - Nutzungsbedingungen - Datenschutzerklärung - Jugendschutz -