Hallo und herzlich willkommen!
Mit diesem Tutorial will ich versuchen das Objektorientierte Programmieren, was auch OOP gennant wird, ein wenig näher zu bringen.
Nun fragt ihr euch bestimmt, was das eigentlich ist.Grob gesagt betrachtet man alles, was man als Objekt bzw. Gegenstand betrachten kann auch als dieses. Mit den sog. Klassen werden quasi Schablonen angefertigt, die man dann vielseitig nutzen kann.
Stellt euch vor ihr programmiert ein Computerspiel. Da liegt es doch nahe, dass man nicht für jede Waffe eine Funktion schreibt und für jede Funktion dieser Waffe diverse andere Funktionen. Tut man dies, so wird man ziemlich schnell den Überblick verlieren und bei großen Projekten wird man sogar nicht sehr weit kommen. Deswegen fertigt man einfach eine >>Schablone<< an, die die ganze Eigenschaften und Funktionen beinhaltet. So kann man im Verlauf mit ein paar Zeilen Code eine menge erreichen und behält den Überblick.
Beim Programmieren hat man doch eigentlich gar keine Gegenstände oder?
Das stimmt so nicht ganz. Man kann zum Beispiel die verschiedensten Parser schreiben und da Parser wie Maschinen funktionieren, kann man sie auch als Objekt bzw. Klasse programmieren.
Läuft das auch auf meinem Webserver?
OOP wurde bei PHP 4 eingeführt und bei PHP 5 >>extrem<< erweitert. Man kann eigentlisch schon sagen, dass der PHP 4-Code zu PHP 5 in den meisten Fällen kompatibel ist. Andersrum natürlich nicht. Trotzdem bietet PHP4 genug Möglichkeiten, um einiges auf die Beine zu stellen. Auf http://www.lima-city.de funktionieren solche Scripte eigentlich einwandfrei.
In diesem Tutorial werden wir uns einen Template-Parser programmieren. Der Vorteil von diesem ist, dass man den Code und Design komplett trennen kann. Außerdem ist es so einfacher, das Design zu wechseln.
Desweiteren setze ich voraus, dass ihr bei den gröbsten Fragen zu erst http://php.net befragt. Auf dieser Seite steht eigentlich alles zu PHP, was man benötigt.
Doch nun zum eigentlichen Tutorial.
Wie erstellt man eine neue Klasse?
Grundsätzlich nimmt man für eine neue Klasse eine eigene Datei, d.h. nicht mehrere Klassen in eine Datei packen!
Ich habe die Datei einfach tplparser.php genannt. Manchmal sieht man auch die Endung class.php, aber das dient eigentlich nur zur bessere Identifizierung.
Eine Klasse definiert man fast genauso wie eine Funktion:
<?php
class TPLParser{
//kekse...
}
?>
Klassen schreibt man im Gegensatz zu Funktionen meistens groß. Das hat sich so eingebürgert und hilft beim Lesen fremder Scripte ein wenig.
In diesem Bereich kann man nun alle möglichen Funktionen schreiben. Doch bevor man wild drauf loslegt schreibt man sich erstman den groben Aufbau auf.
<?php
class TPLParser{
//Konstruktor
function TPLParser(){
}
//Funktion zum Laden des Template-Files
function load(){
}
//Funktion zum Parsen des Templates
function parse(){
}
//Funktion fuer die If-Abfragen im Tempate
function doIf() {
}
}
?>
Wie ihr sehen könnt heißt eine der Funktionen genau so, wie die Klasse. Eine solche Funktion nennt man Konstruktor. Sie wird beim aufrufen der Klasse automatisch aufgerufen. Das kann sehr praktisch sein, wenn man zum Beispiel dort eine MySQL-verbindung o.ä. aufbauen will. Meistens initialisiert man dort einfach nur Variablen.....Variablen...Ja, auch sowas gibt es in der Funktion:
<?php
class TPLParser{
//Deklaration der Variablen
var $template; // Variable zum Speichern des Templates
var $vars = array(); //Der Key wird spaeter mit Value ersetzt
//Konstruktor
function TPLParser(){
}
//Funktion zum Laden des Template-Files
function load(){
}
//Funktion zum Parsen des Templates
function parse(){
}
//Funktion fuer die If-Abfragen im Tempate
function doIf() {
}
}
?>
Das Deklarieren der Variablen ist nicht schwer. Man braucht nur ein >>var<< davor zu setzen. Theoretisch könnte man die Variablen auch schon hier initialisieren, abe man macht dies meistens im Konstruktor. Wichtig zu wissen ist auch, dass man nicht ohne weiteres von außen auf die Variablen zugreifen kann, aber dazu später mehr.
Jetzt haben wir schon Variablen und die Gerüste der Funktionen. Dann wollen wir diese doch mal füllen.
Als erstes schreiben wir den Konstruktor.
<?php
class TPLParser{
//Deklaration der Variablen
var $template; // Variable zum Speichern des Templates
var $vars = array(); //Der Key wird spaeter mit Value ersetzt
//Konstruktor
function TPLParser($vars = array(), $file, $path = 'templates'){
//Variablen abspeichern
$this->vars = $vars;
//Laden des Templates
$this->load($path.'/'.$file.'.tpl');
//Parsen des Templates
$this->parse();
}
//Funktion zum Laden des Template-Files
function load(){
}
//Funktion zum Parsen des Templates
function parse(){
}
//Funktion fuer die If-Abfragen im Tempate
function doIf() {
}
}
?>
Dem Konstruktor werden einige Variablen übergeben, natürlich die Datei und bei bedarf noch einen besonderen Pfad zu den Templatedateien.
Und gleich am Anfang findet man auch schon was neues.
Mit dem "$this->" gibt man an, dass er auf die Klasse zugreifen soll, in der sich der Parser gerade befindet. Würde man dies weglassen, so würde der Parser nicht wissen, was er wo aufrufen muss. Das wird später aber noch deutlicher.
Man speichert also die Variablen in der Klasse ab und ruft die Funktion zum Laden eines Template-Files auf. Wie diese aussieht seht ihr hier:
<?php
class TPLParser{
//Deklaration der Variablen
var $template; // Variable zum Speichern des Templates
var $vars = array(); //Der Key wird spaeter mit Value ersetzt
//Konstruktor
function TPLParser($vars = array(), $file, $path = 'templates'){
//Variablen abspeichern
$this->vars = $vars;
//Laden des Templates
$this->load($path.'/'.$file.'.tpl');
//Parsen des Templates
$this->parse();
}
//Funktion zum Laden des Template-Files
function load($file){
//Falls die Datei existiert, wird sie Zeilenweise in ein Array gelesen
if(file_exists($file)) {
$this->template = @implode('', @file($file));
}
else {
//Andernfalls wird ein Fehler ausgegeben
print "Die Datei $file existiert nicht!";
exit;
}
}
//Funktion zum Parsen des Templates
function parse(){
}
//Funktion fuer die If-Abfragen im Tempate
function doIf() {
}
}
?>
Die Funktion überprüft, ob die Datei existiert und liest sie dann zeilenweise in ein Array ein.
Dach wird im Konstruktor der eigentlich Parser aufgerufen.
<?php
class TPLParser{
//Deklaration der Variablen
var $template; // Variable zum Speichern des Templates
var $vars = array(); //Der Key wird spaeter mit Value ersetzt
//Konstruktor
function TPLParser($vars = array(), $file, $path = 'templates'){
//Variablen abspeichern
$this->vars = $vars;
//Laden des Templates
$this->load($path.'/'.$file.'.tpl');
//Parsen des Templates
$this->parse();
}
//Funktion zum Laden des Template-Files
function load($file){
//Falls die Datei existiert, wird sie Zeilenweise in ein Array gelesen
if(file_exists($file)) {
$this->template = @implode('', @file($file));
}
else {
//Andernfalls wird ein Fehler ausgegeben
print "Die Datei $file existiert nicht!";
exit;
}
}
//Funktion zum Parsen des Templates
function parse(){
//Variablen fuer das Parsen initialisieren
$search = array();
$replace = array();
//Uebergebene Variablen in die Masken einlesen
foreach($this->vars as $key => $value) {
$search[] = '{'.$key.'}';
$replace[] = $value;
}
//Ersetzen der Schluesselwoerter und gleichzeitiges abspeichern der Templates
$this->template = str_replace($search, $replace, $this->template);
//Loeschen der alten Suchmuster
unset($search);
unset($replace);
//Suchmuster fuer If-Bedingungen und Kommentare
$search = array(
//Muster fuer If-Bedingungen wie z.B.:
//<if condition="{condition}"><then>dies</then><else>das</else></if>
'`<if\s*condition=(["\'])(.*?)\\1>\s*<then>(.*?)</then>\s*<else>(.*?)</else>\s*</if>`ies',
//Muster fuer Kommentare wie
// <!-- Kommentar -->
'`<\!\-\-(.*?)\-\->`s'
);
$replace = array(
//Macht aus der Bedingung folgendes
//$condition ? $true : $false;
'$this->doIf(\\2, "\\3", "\\4")',
//Loescht die Kommentare
''
);
$this->template = preg_replace($search, $replace, $this->template);
}
//Funktion fuer die If-Abfragen im Tempate
function doIf($condition, $true, $false) {
return $condition ? $true : $false;
}
}
?>
Hier seht ihr auch schon die Funktion doIF, mit der If-Abfragen in der Templatedatei möglich seien sollen.
Die Kommentare sollten eigentlich genug erklären. Man lässt im Prinzip nur die Schlüsselwörter in der Template-Datei durch Inhalt ersetzen. Desweiteren werden Kommentare in der Templatedatei vor der Ausgabe "unschädlich" gemacht. Die muss ja nicht jeder lesen können. ;)
Das Template an sich wird dann einfach nur in der dafür vorgesehenen Variable gespeichert.
Wie ruft man Klassen denn nun auf??
<?php
//Klasse implementieren
include("classes/tplparser.php");
//Der Key ist das Wort, welches ersetzt werden soll und der Wert ist der Inhalt, mit dem es ersetzt wird
$vars = array('BUTTON_CAPTION'=> 'Kekse', 'BUTTON_DESCRIPTION' => 'test', 'description'=> 0);
//Aufrufen der Klasse
$tpl = new TPLParser($vars, 'acp_navi_button');
//Ausgabe
print $tpl->template;
?>
Eine Klasse ruft man wie gesagt einfach mit "new Name();" auf. Dabei wird eine Referenz erzeugt, d.h. man speichert nicht den ganzen Inhalt in dieser Variable sondern nur, wo es steht. Deswegen muss man dies auch in eienr Variable speichern.
Nachdem man den Parser mit new initialisiert hat und auch Werte übergeben hat, ist das Template schon geparst. Man muss jetzt nur noch auf die Variable zugreifen. Das geschieht so ähnlich wie vorhin. Nur diesmal benutzt man den Namen der Variable. in die man die Referenz gespeichert hat. Das kann man dann einfach ausgeben und fertig ist das Templatesystem.
Doch wie haben solche Template-files nun auszusehen?
Hier mal ein Beispiel:
<a href="#" class="navi_button">
<if condition="{description}">
<then>
<span class="navi_button_description">
{BUTTON_DESCRIPTION}
</span>
</then>
<else></else></if>
<span class="navi_button_text">{BUTTON_CAPTION}</span>
<span class="navi_button_bottom"></span>
</a>
Die Wörter in den geschweiften Klammern werden jetzt einfach mit Inhalt ersetzt. Hier sieht man sogar eine If-Abfrage.
Wir haben der Klasse ja in den Variablen "'description'=> 0" übergeben. Die 0 steht für false, also wird in diesem Fall das zwischen dem <else></else> ausgeführt. Da heir aber nichts steht, passiert auch nichts. Würde man eine 1 übergeben, dann würd das zwischen den <then></then> ausgeführt werden. Das kann in einigen Fällen sehr praktisch werden.
Natürlich kann man den letzten feinschliff noch mit CSS machen, was sogar ratsam ist, aber was das Template-System betrifft war es das eigentlich. Falls ihr noch Fragen dazu haben solltet, beantworte ich sie natürlich gerne. Probiert einfach ein bisschen mit Klassen rum und nach einer Weile hat man dann den Dreh raus. ;)
LG Spacke
P.S.: Was den Code betrifft basiert dieses Tutorial wahrscheinlich stark auf ein Tutorial, was man auch bei gfx-world.net finden kann, jedoch habe ich den Code meiner Meinung nach sehr stark vereinfacht, dabei aber nicht die Funktionalität eingeschränkt.