PHP 5.3
1. August 2008
Heute erschien PHP 5.3 alpha1. Ich habe bisher nur die Doku dazu gelesen, aber das was dazu kommt bringt Spaß!
Namespaces
Mit Hilfe von Namespaces lassen sich Klassen zusätzlich Ordnen und sich so Kollisionen vermeiden. Mehr kann ich nicht dazu schreiben im Moment, da die Doku scheinbar schon wieder veraltetet ist, ich hoffe jedoch nicht, dass das wie in der aktuellen Doku umgesetzt wird, denn das ist Quark. Python hat das cool gelöst, wieso nicht davon ein bisschen abschauen?
Zusätzliche magische Methoden
Mit __call lassen sich bereits nicht-existente Funktionen von Objekten abfangen, nun funktioniert das auch mit statischen Funktionen. Hurra!
Die Methdoe __invoke erlaubt Objekte wie Funktionen zu behandeln.
Late static Binding
Mit dem neuen “static” Keyword soll das verkorkste Handling bei vererbten statischen Methoden korrigiert werden. Mehr dazu sowie ein gutes Beispiel findet sich auch in der Doku.
Echte anonyme Funktion
Seit PHP4 gibt es create_function, eine lieblose Methode um anonyme Funktionen zu erstellen. Mag praktisch sein, die Beispiele und die merkwürdige Handhabung haben mich jedoch bisher davon abgehalten. Mit 5.3 bekommt PHP ähnliche Funktionen wie Javascript:
$lambda = function () { echo "Hello World!\n"; };
Was mich verwundert: entgegen der restlichen PHP-Syntax brauchen anonyme Funktionen nach dem schließenden } ein Semikolon.
Quelle des Beispiels und einige weiteren Informationen
Auf diese Funktion freue ich mich am meisten (:
Nowdoc
Keine große Neuerung ist die Nowdoc genannte Syntax. Ähnlich der Heredoc mit dem Unterschied, dass Variablen im Text nicht ersetzt werden. siehe Doku
PHP-Gtk - Einleitung
28. Mai 2008
Vor knapp zwei Wochen wurde die Version 2.0.1 von PHP-Gtk veröffentlicht. Da diese Version sehr stabil ist, wird es Zeit, einmal näher auf das Thema einzugehen.
PHP-Gtk ist eine Erweiterung für PHP um die Funktionen des (nicht nur) GUI-Frameworks Gtk zu nutzen. Einfach gesagt: Grafische Oberflächen mit PHP bauen.
Ich beschäftige mich schon seit knapp zwei Monaten damit und habe schon einige kleinere Dinge wie etwa ein Quiz erstellt und arbeite gerade an einem Offline-CMS. Der Anfang ist mühsam wenn man noch keine Erfahrungen hat da man selbst für kleine Anwendungen viele Klassen und deren Methoden kennen muss.
Ein einfaches Hallo-Welt-Programm ist schnell geschrieben:
// Fenster erzeugen $wnd = new GtkWindow(); // Standardgröße festlegen $wnd->set_default_size(500,500); // Titel festlegen $wnd->set_title('Hallo Welt'); // Beim Klick auf den Schließen-Button Programm sauber beenden $wnd->connect_simple('destroy', array('Gtk', 'main_quit')); // Textlabel erzeugen $label = new GtkLabel('test'); // Label ans Fenster hängen $wnd->add($label); // Alles anzeigen $wnd->show_all(); Gtk::main();
Screenshot kann ich leider gerade nicht machen, da ich diesen Artikel in der Schule schreibe.
Viele deutsche Webseiten zum Thema gibt es nicht, auf englischsprachigen findet man viele Informationen, vor allem im php-gtk2 Cookbook, welches sehr viele gut erklärte Beispiele enthält.
PHP: Text in Sätzen zerlegen
2. März 2008
Für ein Projekt habe ich eine Funktion gesucht, um einen Text in seine Sätze zu zerlegen. Klingt nach einer einfachen Aufgabe, ist es aber nicht.
Zuerst versuchte ich die scheinbar einfachste Methode: explode(). Mit dieser Funktion lässt sich ein String anhand eines Trennzeichens zerlegen. Nun habe ich aber drei (Punkt, Fragezeichen und Ausrufezeichen).
Also musste eine intelligentere Funktion ran: preg_split(). Dieser reguläre Ausdruck brachte ein sehr gutes Ergebnis, hatte jedoch ein Problem: am Ende fehlten alle Satzzeichen.
$sentences = preg_split('#\.|!|\?#', $source, -1, PREG_SPLIT_NO_EMPTY);
Da ich sonst nichts fand, schrieb ich kurzerhand meine eigene Funktion, die arbeitet wie ich möchte:
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 28 29 30 31 | /** * Teilt einen String in Sätze auf * * @param string $source Text zum Trennen * @author Michael Mayr (http://michfrm.net) * @return array */ function SplitSentences($source) { $s = array(); $marks = array('.', '!', '?'); // count strlen every loop because $source can change while loop for ($i = 0; $i < strlen($source); ++$i) { $c = $source[$i]; foreach ( $marks as $mark ) { if ( $c == $mark ) { $s[] = substr($source, 0, $i) . $mark; $source = trim(substr($source, $i + 1)); $i = 0; } } } return $s; } $text = 'This ist ein Satz. Dies ein Ausruf! Und das einfach nur eine Frage?'; print_r(SplitSentences($text)); |
Ausgabe:
Array
(
[0] => This ist ein Satz.
[1] => Dies ein Ausruf!
[2] => Und das einfach nur eine Frage?
)
Ich hoffe, diese Funktion kann noch anderen nützlich sein.
Yanix TableEditor
5. Februar 2008
Was ist nun das? Ein Tabelleneditor für Yanix? Was soll das sein?
Ganz einfach, die Manipulation von Datenbanken mit reinem PHP Code!
Hier mal ein kleines Beispiel der aktuellen Entwicklungsversion:
1 2 3 4 5 6 | $tbl = DB::getTable('test', false); $tbl->Insert(array( 'test' => 'blubb', 't_char' => 'lol', 't_int' => 10 )); |
Erklärung: Die erste Zeile holt ein Tabellenobjekt von der Datenbank-Klasse ab, diese erstellt ein Objekt falls nötig und gibt es zurück. Das Objekt holt sich dann alle Informationen über die genannte Tabelle vom Datenbank-Server (aktuell nur MySQL getestet) und merkt sich diese. Bei Abfragen werden dann die Felder überprüft, sollten die Typen nicht überein stimmen, wirft das Objekt eine Exception (In diesem Beispiel habe ich aus der Zahl im vorherigen Beispiel eine Zeichnenkette gemacht):
* Catched Exception: * Message: Invalid value for t_int. Expected int, got string * File: /home/michael/Desktop/PHP/Yanix/lib/TableEditor.class.php (129)
Jetzt wurde die Exceptions direkt von Yanix gefangen, natürlich können auch Plugins diese fangen, mehr dazu im PHP-Manual unter Exceptions.
Ich mache mich jetzt weiter ans Werk um das möglichst weit fertig zu bekommen, die erste öffentliche Yanix-Beta rückt immer näher!
Was kostet dein PC im Jahr (Strom)?
22. Januar 2008
Einfach mal nachrechnen!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // Wieviel Watt braucht der PC? $watt = 478; // Wieviele Stundne läuft er am Tag? $stunden = 8; // Aktueller Strompreis pro KWh? (Beispiel: 22ct = 0.22) $kwh_cost = 0.22; $day = $watt * $stunden; $year = $day * 365; $kwh = $year / 1000; $all_cost = $kwh * $kwh_cost; echo "Kosten: {$all_cost} €\n"; |
Quelle der Berechnung und weitere Informationen
Ich komme auf etwa 307 €.
Helferfunktion: GetDir
13. Januar 2008
Dieses Szenario haben PHP-Entwickler sicher das eine oder andere Mal: Ein Verzeichnis auslesen. Unter PHP gibt es dafür eine Reihe von Funktionen, welche aber meist einiges an Arbeit machen. Zuerst das Verzeichnis öffnen, dann Eintrag für Eintrag auslesen und dann die virtuellen Verzeichnisse . und .. ausfiltern. Mit einer Funktion lässt sich das viel einfacher lösen. Hier ist meine GetDir():
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 | /** * Reads a dir and returns it as array * @author Michael Mayr (http://michfrm.net) * @param string $path Path to read (absolute preferred) * @param bool $absolute Return absolute or relative paths? (Default: false) * @return mixed */ function GetDir($path, $absolute = false) { if ( substr($path, -1, 1) != '/' ) $path .= '/'; $files = array(); $dir = opendir($path); if ( $dir === false ) return false; while ( ( $file = readdir($dir) ) !== false ) { if ( substr($file, 0, 1) != '.' && $file != '..' ) { $files[] = ($absolute === false) ? $file : $path . $file;; } } return $files; } |
Die Funktion stammt aus der functions.php von Yanix und ist daher GPL v2
Im Detail: Der Paramter ist der Pfad $path, welcher ausgelesen werden soll. Wenn der 2. Parameter $absolute auf true steht, gibt die Funktion absolute Pfade zurück, ansonsten relative. Es werden keine Unterverzeichnisse untersucht!
Hier ein praktisches Beispiel:
1 2 3 4 5 6 7 8 9 10 | $dir = dirname(__FILE__); // Check, ob das Verzeichnis existiert if ( is_dir($dir) ) { foreach ( GetDir($dir) as $file ) { echo "Datei {$file} gefunden!"; } } |
Im Beispiel von foreach sollte immer ein Check erfolgen, denn falls die Funktion false zurück gibt, falls das Öffnen der Verzeichnisses fehl schlägt (z.B. wenn es nicht existiert), wirft foreach einen Fehler.
Helferfunktion: SimpleBacktrace
10. Januar 2008
Nun beginne ich meine schon lang geplante Reihe: Helferfunktionen. Ich meine damit Funktionen, die nicht groß sind aber sehr bei der Entwicklung und im allgemeinen Betrieb helfen können. Angefangen mit SimpleBacktrace.
Jeder der einmal mit Exceptions gearbeitet hat kennt die Backtraces. Damit kann man bequem den Stacktrace (welche Funktion hat welche aufgerufen) nutzen und ihn auch ausgeben. Es gibt jedoch keine Funktion, damit PHP dies auch ohne Exceptions ausgeben kann. Mit debug_backtrace() erhält man zwar einen Backtrace, jedoch nur ein riesen Array. Diese Funktion formatiert diesen ähnlich wie bei Exceptions.
Der Parameter $jumpover ist dazu da, um eine bestimmte Anzahl von Einträgen zu überspringen. Standard ist 1, damit die Funktion selbst nicht im Trace auftaucht. Bei Funktionen die das PHPsche Error-Reporting ersetzen, sollte man diesen Wert auf mind. 2 setzen.
Diese Funktione funktioniert vielleicht mit PHP4, gestetet hab ich es nicht.
Code anzeigen
Als ich diesen Beitrag fast fertig hatte, kam mir eine noch bessere Idee. Nutz Exceptions!Nachteile: Überspringen von Zeilen und eigene Anpassungen sind nicht möglich.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /** * Rückgabe eines formatierten Stacktraces von jedem Ort aus. * @author Michael Mayr (http://michfrm.net) * @return string */ function SimpleBacktrace() { try { throw new Exception('SimpleBacktrace'); } catch ( Exception $e ) { return $e->getTraceAsString(); } } |
Ein Experiment
10. Januar 2008
Gestern fragte ich mich beim Einschlafen: Was ist, wenn ich eine Objektmethode aufrufe, welches eine andere Methode aufruft, welche das Objekt zerstört? Stürzt PHP ab oder läuft es einfach weiter. Was soll es dannn tun? Das Ergebnis hat mich überrascht:
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | class Helper { public $blubb = true; public function Bye() { global $c; echo "Helper::Bye(): Calling Control::Kill()\n"; $c->Kill(); $c->End(__CLASS__); var_dump($this); } } class Control { public $obj = null; public function __construct() { echo "Control::__construct(): Making object of Helper...\n"; $this->obj = new Helper; } public function Kill() { echo "Control::Kill(): Good bye Helper\n"; unset($this->obj); $this->obj = null; } public function End($caller) { echo "Control::End(): Called by {$caller}\n"; if ( is_object($this->obj) && get_class($this->obj) == 'Helper' ) { echo "Object exists\n"; } else { echo "Object not exists\n"; } } } $c = new Control; $c->obj->Bye(); $c->End('main'); |
Kurz erklärt: Zuerst erstelle ich eine neue Instanz von Control, welche in seine Eigenschaft $obj eine Instanz von Helper erstellt. Dann rufe ich die Instanz von Helper auf, welche Control den Befehl gibt den Helfer zu zerstören.
Nun die Ausgabe, man beachte den fetten Teil:
michael@michfrm-home:~/Desktop$ php badstack.php
Control::__construct(): Making object of Helper…
Helper::Bye(): Calling Control::Kill()
Control::Kill(): Good bye Helper
Control::End(): Called by Helper
Object not exists
object(Helper)#2 (1) {
["blubb"]=>
bool(true)
}
Control::End(): Called by main
Object not exists
Obwohl das Objekt nicht mehr existiert, kann es sich selber auslesen.
Ich kenne mich mit der PHP-Interna nicht so aus aber denke Folgendes: PHP löscht nicht direkt das Objekt sondern erst die Referenz und zerstört dann das Objekt, wenn es wirklich nicht mehr gebraucht werden kann. Wieder was gelernt.