Doctrine Naming Strategy in Zend Framework 2

Database Table Prefixes are easy to configure with the Doctrine Naming Strategies.
Just create and register a new Strategy in your global config:

config/autoload/global.php

<?php
 
 
namespace Album\Doctrine\Strategy;
 
 
use Doctrine\ORM\Mapping\DefaultNamingStrategy;
 
class PrefixNamingStrategy extends DefaultNamingStrategy
{
    /**
     * {@inheritdoc}
     */
    public function classToTableName($className)
    {
        return '_' . substr($className, strrpos($className, '\\') + 1);
    }
}
<?php
return array(
     /* ... */
    'doctrine' => array(
        'configuration' => array(
            'orm_default' => array(
                'naming_strategy' => new \Album\Doctrine\Strategy\PrefixNamingStrategy()
            ),
        ),
 
    ),
   /* ... */  
);

References:
Doctrine Manual Implementing a NamingStrategy

Bequem Phar Files erzeugen

Ich schreibe sehr gerne Bash Scripte, aber noch lieber Scripte in PHP. Solange man alles in ein File bekommt ist das auch kein Problem. Bei größeren Geschichten oder bei der Verwendung von Libs streut das Script leider auf mehrere Dateien. Entsprechend sind Installation und Updates dann auch aufwendiger. Irgendwer hat sich für diese Problematik Phar (PHP Archive) ausgedacht. Dabei werden alle Abhängigkeiten in ein komprimiertes Archiv gepackt – vom Prinzip her wie ein Jar in Java. Das manuelle Erzeugen von diesen Dateien ist leider recht unangenehm und verbraucht nach zuviel Zeit. Viel schneller geht’s mit dem PHP PHAR Compiler von Christian Neff. Bevor man loslegen kann muß die php.ini angepasst werden:

phar.readonly = 0

Anschließend den Compiler via Composer installieren und ein Script zum Bauen anlegen:

<?php
/**
 * User: ms
 * Date: 29.08.15
 * Time: 20:22
 * @see https://github.com/secondtruth/php-phar-compiler
 */
require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'vendor/autoload.php';
use Secondtruth\Compiler\Compiler;
$compiler = new Compiler('./');
$compiler->addIndexFile('cli.php');
$compiler->addFile('vendor/autoload.php');
$compiler->addDirectory('vendor/composer', '!*.php');
$compiler->addDirectory('vendor/electrolinux', '!*.php');
$compiler->addDirectory('vendor/zendframework', '!*.php');
$compiler->addDirectory('src', '!*.php');
$compiler->compile("build/mvv-cli.phar");

Fertig.

Led Lampen mit WLAN Anbindung

Ein Thema das mich immer wieder fasziniert ist die Vernetzung von Gegenständen des Alltags. Meine Wohnzimmerlampe glänzt nicht nur durch hässliche Form sondern auch durch kaltes Licht und Quecksilber im Leuchtmittel. Deshalb ersetze ich nach und nach Kompaktleuchtstofflampen durch LED Lampen. Der Zufall brachte mich zu diesem Lampenset mit WLAN Anbindung (Affiliate) vom Hersteller LimitlessLED. Die Lampen passen in E27 Sockel, haben 6 Watt Leistung und können mit 230V ~  betrieben werden. Die Grundidee ist die Lampen via Smartphone oder auf anderen Wegen einzuschalten, die Farben zu ändern und dimmen.Neben den 3 Lampen werden eine Fernbedienung und was viel interessanter ist einem Controller mit dokumentierter API geliefert. Apps gibt es auch! Pro Fernbedienung und Controller kann man 4 Lampen steuern. Dabei kann man die Parameter Helligkeit, Farbe regeln.

2013-10-15 16.56.18

 

Impressionen

Inbetriebnahme

Lampen

Jede Lampe muß konfiguriert werden. Dabei spielt es keine Rolle, ob man sie der Fernbedienung oder in der App konfiguriert.

Lampe in Fassung drehen und binnen 2 Sekunden nach Anlegen von Spannung auf der Fernbedienung einen Kanal aktivieren – die Lampe ist nun dem entsprechenden Kanal zugewiesen. Die erfolgreiche Zuweisung  wird durch Blinken quittiert. Um die Lampe aus dem Kanal zu lösen innerhalb von 2 Sekunden nach dem Einschalten 5 mal den entsprechenden Kanal auf der Fernbedienung aktivieren.

Controller

Der Controller wird per Micro-USB Kabel mit Spannung versorgt. Ich nutze ein Ladegerät für Smartphones. Nach dem Booten sollte man ein WLAN mit der SSID milight finden. Nun kann man der Anleitung folgen oder was ich als angenehmer per Webinterface konfigurieren. Dazu ins eigene WLAN verbinden und http://192.168.0.100/home.html aufrufen – ob die IP immer die gleiche ist kann ich nicht sagen. Hier muß in den STA Interface Settings das eigene WLAN konfiguriert werden.

App

Momentan nutze ich die in der Anleitung vorgeschlagene App Es gibt auch noch eine puristischere Version mit
Anbindung an Tasker – die  ohne Anpassungen leider nicht läuft.

LED Lampen ansteuern

Beim Hersteller gibt es eine Dokumentation.  Die Beispiele sind leider ein wenig inkonsistent, da irgendwann die Portnummer von 50000 auf 8899 umgestellt wurde.

Die Lampen werden per UDP Kommandos gesteuert. Dabei werden immer 3 Byte übertragen.

Byte 1 ist das Kommando an welches immer der Suffix 0x00  0x55 angehängt werden muß.

In PHP kann mit diesen Zeilen alle Kanäle einschalten:

&lt;?php
define("CONTROLLER_IP", "192.168.0.100");
function executeCommand( $ip, $command, $suffix1=00, $suffix2='55'){
	fwrite(fsockopen("udp://$ip", 8899), chr(hexdec($command)) . chr(hexdec($suffix1)) . chr(hexdec($suffix2)));
}
 
executeCommand(CONTROLLER_IP, 42);

Wer php5-cli installiert hat kann das Script auch auf der Kommandozeile nutzen. Für Freunde der Bash gibt es auch ein Script (geklaut bei Smileytechadventures)

#!/bin/bash 
 
if [ -z "$1" ] ; then 
    echo "You must enter a parameter: "  
    echo "  e.g. $0 allon" 
    exit 1 
fi 
 
incmd="$1" 
ipaddress="192.168.0.201" 
portnum="50000" 
 
allon="\x35\00\x55" 
alloff="\x39\00\x55" 
zone1on="\x38\00\x55" 
zone1off="\x3B\00\x55" 
zone2on="\x3D\00\x55" 
zone2off="\x33\00\x55" 
zone3on="\x37\00\x55" 
zone3off="\x3A\00\x55" 
zone4on="\x32\00\x55" 
zone4off="\x36\00\x55" 
 
eval incmd=\$$incmd 
 
echo -n -e "$incmd" &gt;/dev/udp/"$ipaddress"/"$portnum"

Ein wenig Heimautomatisierung ist auch schnell betrieben. Dieses Skript prüft, ob die Sonne untergegangen ist und schaltet in diesem Fall alle Lampen ein.

#!/usr/bin/php
&lt;?php define("CONTROLLER_IP", "192.168.0.100"); define("ZEIT_FUER_BETT", "23:59"); function executeCommand( $ip, $command, $suffix1=00, $suffix2='55'){ fwrite(fsockopen("udp://$ip", 8899), chr(hexdec($command)) . chr(hexdec($suffix1)) . chr(hexdec($suffix2))); } function getIp(){ return file_get_contents("http://icanhazip.com/"); } function getLatLongByIp($ip){ $geoplugin = unserialize( file_get_contents('http://www.geoplugin.net/php.gp?ip='.$ip) ); if ( is_numeric($geoplugin['geoplugin_latitude']) &amp;&amp; is_numeric($geoplugin['geoplugin_longitude']) ) { $ret['lat']= $geoplugin['geoplugin_latitude']; $ret['lon']=$geoplugin['geoplugin_longitude']; return $ret; } } $ret= getLatLongByIp(getIp()); $dateSunset=date_sunset(time(), SUNFUNCS_RET_TIMESTAMP,$ret['lat'], $ret['lon'], 90, 1); $dateSunrise=date_sunrise(time(), SUNFUNCS_RET_TIMESTAMP, $ret['lat'], $ret['lon'], 90, 1); //Zu einer festen Uhrzeit ausschalten if(date("H:i")&gt;= date(ZEIT_FUER_BETT)){
echo "schlafen";
	executeCommand(CONTROLLER_IP, 41);
	exit;
}  
//Nach Sonnenuntergang und vor Aufgang
if ( time() &gt;=$dateSunset &amp;&amp; $dateSunset &gt;$dateSunrise){
 
	executeCommand(CONTROLLER_IP, 42);
}else {
	executeCommand(CONTROLLER_IP, 41);
}

Das kleine Skript fühlt sich auf kleinen Linuxrechnern im eigenen Netzwerk sehr wohl und sollte per Cronjob alle 1 Minuten angestoßen werden.

*/1 *    * * *   /home/pi/sunrise.php

Inzwischen habe ich die Lampen seit einer Woche in Betrieb und viel Spaß damit. Die Lichtausbeute ist ausreichend, der Stromverbrauch in Ordnung. Der Preis ist mit 99 EUR schon sehr happig, aber es macht auch sehr sehr viel Spaß Skripte für die Lampen zu schreiben.

PHP Unit ohne Pear usw. installieren

Unit Tests machen nicht nur Sinn, sondern auch Spaß und erleichtern das Leben. Für PHP gibts PHPUnit.

Auf die Schnelle  geht’s so (bin Verzeichniss in ~ benötigt):

[schmimi2@cepheus ~]$ cd ~/bin
[schmimi2@cepheus bin]$ wget http://pear.phpunit.de/get/phpunit.phar
[schmimi2@cepheus bin]$ mv phpunit.phar phpunit
[schmimi2@cepheus bin]$ chmod +x phpunit
[schmimi2@cepheus bin]$ bash

Zum Testen einfach das File StackTest.php mit folgendem Inhalt erzeugen:

<?php
 
 
class StackTest  extends PHPUnit_Framework_TestCase
{
    public function testPushAndPop()
    {
        $stack = array();
        $this->assertEquals(0, count($stack));
 
        array_push($stack, 'foo');
        $this->assertEquals('foo', $stack[count($stack)-1]);
        $this->assertEquals(1, count($stack));
 
        $this->assertEquals('foo', array_pop($stack));
        $this->assertEquals(0, count($stack));
    }
	public function testFail(){
		$this->assertEquals(false,true);
 
	}	
 
}

Test laufen lassen:

[schmimi2@cepheus unittests]$ phpunit StackTest.php 
PHPUnit 3.7.21 by Sebastian Bergmann.
 
.F
 
Time: 0 seconds, Memory: 2.75Mb
 
There was 1 failure:
 
1) StackTest::testFail
Failed asserting that true matches expected false.
 
/var/www/virtual/schmimi2/api.giftimessen.de/unittests/StackTest.php:19
 
FAILURES!
Tests: 2, Assertions: 6, Failures: 1.

Die Erzeugung von PHP Klassen mit Javascript

Eins vorweg. Ich kann kein Javascript. Ich mag es nicht und defaultmäßig führt mein Browser auch keins aus. Der Geburt meines Skripts gingen 2 Stunden lesen und wildestes googeln nach DOM Bezeichnungen und irgendwelchen Events voraus. Variablen werden nicht geprüft und Attribute mit Zeichenlänge 0 werden auch verarbeitet

Worum gehts also und warum zu Teufel mach ich Sachen die mir keine Freude machen? Angenommen Du schreibst eine PHP Klasse. Attribute wollen gekapselt werden und das kann durchaus in getBla() setBla($bla) oder meinen persönlichen Favorit bla($blavalue=““){/**/} Copy  & Paste Orgien ausarten – macht auch keinen Spaß

Mein wundervolles Skript hilft mir indem es  aus Variablen in UML Notation rudimentäre Klassengerüste erzeugt mit Zugriffsfunktionen auf die Attribute. Einrückungen werden nicht gemacht, das ist wie ich finde Geschmackssache und Aufgabe der persönlichen IDE.

Wer Verwendung dafür hat oder es einfach nur mal ausprobieren möchte kann das hier tun.  Über Verbesserungsvorschläge oder Alternativen freue ich mich natürlich immer.

Stapelverarbeitung mit PHP

Heute mal ein Klassiker der Computerei: Batchjobs. Man knallt einem Programm einen Stapel voll Aufträge vor die Nase und die müssen abgearbeitet werden.  Die Jobs sollen in einem Webinterface vergeben werden und dann von einem anderen Programm weiterverarbeitet werden.

Die Grundlage für dieses Projekt ist der Stapelspeicher oder Stack. Der kennt in seiner klassischen Form drei Funktionen: Push, Pop und Peek.

Push legt etwas auf dem Stapel ab, Pop nimmt es herunter. Mit Peek kann man sich das oberste Element anschauen, ohne es zu entfernen.

Meinen Stapel halte ich mit einer Textdatei persistent.  Noch einfacher geht es nicht. Die Methode Pop nimmt bei meinem Stack das unterste Element vom Stapel.

Der Stapel wird in einer Klasse mit diesem Rumpf implementiert:

Die Klasse wird wie der Name schon sagt die Grundlage für meine Stapelverarbeitung sein.

Nun werden 2 Skripte benötigt. Ein Skript (Sklaventreiber) legt Aufträge auf den Stapel und das andere (Sklave) arbeitet den Stapel ab. Der Sklave könnte im inneren so aussehen:

#!/usr/bin/php

<?php

$stack = new Stack(‘joblist’);
$job=$stack->peek();

echo „$job wird verarbeitetn“;

sleep(60); //ist ja nicht wirklich was zu tun da
echo „fertig“;

$stack->pop();

?>


Der Sklaventreiber ist einfach zu implementieren. Es muß ja nur pushjob() aufgerufen werden.  Man kann auch selbst zum Sklaventreiber werden indem man eine neue Zeile in die Jobliste einfügt:).Für meine Stapelverarbeitung ist es wichtig, daß immer nur ein Sklave am arbeiten ist.  Wenn der Sklave gestartet wird, muß er vor Arbeitsbeginn prüfen, ob er auch wirklich alleine ist.  Bei meinem Linux ist der wunderbare Befehl pgrep dabei. Das Programm findet heraus, ob ein Programm gestartet ist und gibt die Prozess Id(s) zurück.

Diese Prüfung realisiere ich mit slaveRunning():

if (!$stack->slaveRunnig()){

$job=$stack->peek();
if ($stack->count()>0){

while ($stack->count()>0){

echo „$job wird verarbeitetn“;

sleep(15);

$stack->pop();

}

}else {

echo „Jobliste leern“;

}

} else {

echo „da is schon wer am arbeitenn“;

}echo „fertign“;

Die Methode habe ich nicht in die Klasse Stack gepackt, sondern einfach eine neue Klasse namens „Batch“ geschrieben die von Stack erbt. Leider kann Eclipse das nicht anzeigen:(:

Wenn man nun seine Crontab um einen Eintrag für dieses Skript ergänzt läuft die Geschichte automatisch ab. Ich habe das mal für den Interessierten bei Github eingecheckt.

Persistenz und Reflexion mit PHP

City Refraction, City Reflection
Attribution License by lrargerich
Reflexion oder Introspektion bedeutet dass ein Objekt seine eigene Struktur kennt und diese Modifizieren kann.
Sehr praktisch ist dies, wenn es um Typsicherheit oder die Persistenz von Daten geht. PHP stellt dafür die Klasse ReflectionClass zur Verfügung. Ich möchte hier beschreiben, wie man mit Reflexion die Typen und Werte von Attributen auslesen kann, um diese z.B. persistent zu halten.
Zuerst ein Beispiel für Reflexion:

class ReflectionExample{
	protected $attribute1;
	protected $attribute2;
	protected $attribute3;
	public 	  $attribute4;

	public function method1(){}
	public function method2(){}

	public function __construct(){
		Reflection::export(new ReflectionClass($this));

	}
}//class
$reflect = new ReflectionExample();

Die Ausgabe:

Class [  class ReflectionExample ] {
  @@ /home/schmiddi/web/gloria2/Reflection.php 8-21

  - Constants [0] {
  }

  - Static properties [0] {
  }

  - Static methods [0] {
  }

  - Properties [4] {
    Property [  protected $attribute1 ]
    Property [  protected $attribute2 ]
    Property [  protected $attribute3 ]
    Property [  public $attribute4 ]
  }

  - Methods [3] {
    Method [  public method method1 ] {
      @@ /home/schmiddi/web/gloria2/Reflection.php 14 - 14
    }

    Method [  public method method2 ] {
      @@ /home/schmiddi/web/gloria2/Reflection.php 15 - 15
    }

    Method [  public method __construct ] {
      @@ /home/schmiddi/web/gloria2/Reflection.php 17 - 20
    }
  }
}

Wie man sieht bekommt man jegliche Information über die Klasse geliefert. Ich möchte wie gesagt Daten bequem in einer Datenbank speichern, bearbeiten oder löschen. Der funktionale oder „PHP Tutorial“ Weg sähe so aus, dass man für jedes Objekt / Aspekt der PHP Seite die SQL Befehle INSERT, UPDATE und DELETE schreibt. Das ist nicht nur sehr Aufwändig, sondern benötigt auch große Aufmerksamkeit, wenn Attribute oder Variablen wegfallen oder neue hinzukommen.

Schauen wir uns noch einmal das Anfangsbeispiel an, um ein kleines Problem mit der Reflection Class zu verdeutlichen:

reflect

Die Klasse Reflect liest die Attribute der erbenden Klasse ReflectMe ein und macht eine Ausgabe:

abstract class Reflect{
	private $types = array();
	private $values= array();
	private $parentAttribute ;
	protected  $parentAttribute2;
	public function getAttributes(){
		$reflection = new ReflectionClass($this);
		$types=$this->types;
		$values=$this->values;
		foreach ($reflection->getProperties() as $key ){
			$value=str_replace("$",' ',$key->name);
			$type =  gettype($this->$value);
			$types[$key->name] = gettype($this->$value);
			$values[$key->name] = $this->$value;
			echo gettype($this->$value).
				" {$key->name} {$this->$value}
";
		}//each
	}//getAtrributes
}//class

Die Kindklasse ReflectMe hat nur ein paar Attribute die ich ausgeben möchte:

class ReflectMe extends Reflect{
	protected $child_attribute1= "Hallo Otto";
	protected $child_attribute2= 3.1415;
	protected $child_attribute3= 1337;
	private	  $child_attribute4= array();

	public function method1(){}
	public function method2(){}

}//class

$reflect = new ReflectMe();
$reflect->getAttributes();

Ein Blick in die Ausgabe verdeutlicht 2 Probleme:

string child_attribute1 Hallo Otto
double child_attribute2 3.1415
integer child_attribute3 1337
NULL parentAttribute2
Fatal error: Cannot access private property ReflectMe::$child_attribute4 in /home/schmiddi/web/gloria2/Reflection.php on line 30

Die ReflectionClass kann nicht auf private Attribute der Kindklasse zugreifen. Für meinen Geschmack ist dieser Grad der Kapselung ein wenig übertrieben. Mit Version 5.3 von PHP wird die Methode ReflectionMethod::setAccessible eingeführt, die den Zugriff erlaubt. Ein weiteres Problem wäre, dass wir auch die protected Werte der Elternklasse bekommen, da diese ja vererbt werden. Dies kann man Umgehen, indem man die Attribute von Reflect private deklariert. Damit schießt man sich jedoch in Sachen Vererbung ins Bein. Eleganter ist es die Elternklasse ebenfalls zu „reflektieren“ und die Schnittmenge der beiden Reflektionen zu entfernen:

/* ... */
	public function getAttributes(){
		//neues ReflectionObject für die Eltern Klasse erzeugen
		$reflectParent = new ReflectionClass(__CLASS__);
		$parentTypes=array();
		//Attribute in ein Array speichern
		foreach ($reflectParent->getProperties() as $key)
			$parentTypes[$key->name] = gettype($this->value);

		$reflection = new ReflectionClass($this);
		$types=$this->types;
		$values=$this->values;
		foreach ($reflection->getProperties() as $key ){
	//nur die Attribute der erbenden Klasse in die Array's schieben
			if(!array_key_exists($key->name, $parentTypes)){
				$value=str_replace("$",' ',$key->name);
				$type =  gettype($this->$value);
				$types[$key->name] = gettype($this->$value);
				$values[$key->name] = $this->$value;
				echo gettype($this->$value).
					" {$key->name} {$this->$value}
";
			}//if
		}//each
	}//getAtrributes

Nun können wir die Attribute der Klasse bequem auslesen, es sei denn sie sind als private deklariert. Für mein Skript möchte ich nicht PHP 5.3 voraussetzen, entsprechend muß darauf geachtet werden, dass nur gespeichert werden kann, was public oder protected ist.
Nun ist alles beisammen, was einen ordentlichen SQL Befehl ausmacht.
Zur Sache also:

private function generateInsertCommand(){
	$this->getAttributes();
		if ($this->insertCommand!=null)
			return $this->insertCommand;

		$classname =  $this->childClassName;
		$values = $this->attributeValues;

		$sql ="
		INSERT INTO  $classname (";
		$counter = 0;
		$count = count($this->attributeValues);
		foreach ($values as $key =>$value){
			$counter+=1;
			$sql.=$key;
			if($counter $count)
				$sql.=',';
		}
		$sql.=")VALUES (";
		$counter = 0;
		foreach ($values as $key =>$value){
			$counter+=1;
			$sql.='?';
			if($counter $count)
				$sql.=',';
		}//each

		$sql.=");";
		$this->insertCommand = $sql;
		return $this->insertCommand ;
	}//function

Die counts sind zwar nicht sehr schön, aber ich brauche sie für die Klammern. Wenn ich mal wieder ein wenig Zeit habe, stelle ich vielleicht den ORM Mapper hier vor.

Magische Methoden und Interzeptoren mit PHP

F18 High Contrast
Attribution-NonCommercial-NoDerivs License by SkipSteuart
In PHP gibt es sogennante magische Methoden. Diese werden nicht explizit aufgerufen, sondern werden vom Interpreter in gewissen Situationen ausgeführt. Dazu gehören Konstruktor, Dekonstruktor. Die Implementierung magischer Methoden ist optional. Die Interzeptoren sind eine Untermenge der magischen Methoden. Mit diesen Methoden kann man bequem Execeptions oder Laufzeitfehler im objekt-orientierten Umfeld abfangen.

Beginnen möchte ich mir der Funktion __toString(), die beim Debuggen sehr nützlich ist. Dazu ein kleines Beispiel:

class Post{
	private $title ="", $text = "";


	public function __construct($title="", $text=""){
		$this->title =  $title;
		$this->text=$text;
	}
}
$post = new Post("mein 1. Eintrag",  "Schönes Wetter, spazieren gegangen, Eis gegessen.");
echo $post;

Der Befehl echo post liefert einen Fehler. Wenn man ein Objekt in PHP genauer betrachten möchte, muß man dies mit print_r() oder var_dump() tun – oder mit __toString():

	public function __toString(){
		ob_start();
		var_dump($this);
		$retval=ob_get_clean();
		return $retval;
	}

Da __toString() eine Zeichenkette zurückgibt, kann man alle String Funktionen von PHP anwenden:

class Post{
	private $title ="", $text = "";


	public function __construct($title="", $text=""){
		$this->title =  $title;
		$this->text=$text;
	}

	public function __toString(){
		return "

{$this->title}

{$this->text}"; } } $post = new Post("mein 1. Eintrag", "Schönes Wetter, spazieren gegangen, Eis gegessen."); echo str_replace("ö", "ö", $post);

Mit __set() und __get() kann man Zugriffe auf nicht gesetzte oder geschützte Attribute abfangen.

class Post{
        /**....**/
        public $foo="bar";
	public function __get($attrib){
		echo "$attrib gibts nicht, oder du hast keinen zugriff darauf!

"; } } $post = new Post("mein 1. Eintrag", "viel passiert heute."); echo $post->bla; echo $post->title; echo $post->foo;

Die Rückgabe sieht dann so aus:

bla gibts nicht, oder du hast keinen zugriff darauf!
title gibts nicht, oder du hast keinen zugriff darauf!

bar

Der Zugriff auf nicht definierte oder geschützte Methoden läßt sich mit __call abfangen:

class Post{
	public function __call($meth, $args){
		echo "Die Methode $meth gibts nicht, oder du hast keinen Zugriff darauf!

"; if (!empty($args)){ echo "Parameter:
"; foreach ($args as $arg) echo "$arg
"; } } } $post->leaveComment("karl heinz", "echt super", "karl@heinz.de");

Die Ausgabe sieht dann so aus:

Die Methode leaveComment gibts nicht, oder du hast keinen Zugriff darauf!
Parameter:
karl heinz
echt super
karl@heinz.de

Die beiden Interzeptoren __isset() und __unset() können entsprechende Anfragen an das Objekt abfangen:

class Post{
	public function __isset($value){
		return isset($this->$value);
	}
	public function __unset($value){
		if(isset($this->$value))
			unset ($this->$value);
	}

}
$post = new Post();
echo isset($post->title);
unset ($post->title);

Statt nur Fehler mit den Interzeptoren auszuwerfen, kann man Klassen schreiben, die zwar ein wenig „dirty“ sind aber auch funktionieren:

class DirtyPost{
	public  $attributes = array();

	public function __construct($title="", $text=""){
		$this->attributes['title'] =  $title;
		$this->attributes['text'] =  $text;

	}

	public function __toString(){
		$retval ="

{$this->attributes['title']}

"; $retval .=$this->attributes['text']; $retval .=$this->getComments(); return $retval; } public function __get($attrib){ if (isset($this->attributes[$attrib])) return $this->attributes[$attrib]; } public function __set($attrib, $value){ $this->attributes[$attrib] = $value; } public function __call($meth, $args){ switch ($meth){ case 'addComment': array_push ($this->attributes, $args); break; default: echo "$meth gibt es nicht."; case 'getComments': $retval =""; foreach ($this->attributes as $attrib){ if(is_array($attrib)){ $retval.= "Kommentar:
"; foreach ($attrib as $a) $retval.= $a.'

'; } }//each return $retval; break; }//switch }//__call } $post = new DirtyPost(); $post->title="Mein 1. Eintrag

"; $post->text = "Heute wars nicht so schoen

"; $post->addComment('Hans', 'hans@hansi.de', 'das schert mich nicht :)'); $post->addComment('Ingo', 'ingo@web.de', 'Morgen wirds besser'); echo $post;

Ausgabe:

Mein 1. Eintrag

Heute wars nicht so schoen
Kommentar:
Hans

hans@hansi.de

das schert mich nicht :)

Kommentar:
Ingo

ingo@web.de

Morgen wirds besser

Ausgelassen habe ich __callstatic mit dem man Aufrufe von nicht existierenden statischen Methoden abfangen kann.
Mit den Interzeptoren kann man sich viel Arbeit sparen, aber auch viel Verwirrung stiften. Das letzte Beispiel funktioniert zwar (wenn man serialize() und unserialize() noch einbindet, hat man einen minimalistischen Blog) allerdings leiden Lesbarkeit, Wiederverwendbarkeit darunter.

Fehlerbehandlung mit Singleton Pattern in PHP

Anonymous Single Malt Scotch
Attribution-NonCommercial-ShareAlike License by clappstar

Heute gibt’s mal wieder ein nettes Erzeugungsmuster: das Singleton oder Einzelstück. Mit diesem Pattern kann man verhindern, dass mehr als ein Objekt einer Klasse instanziiert wird. Nützlich ist das Pattern für die Kapselung von Datenbankverbindungen, oder wie in meinem Fall zur Fehlerbehandlung.

Das Prinzip ist schnell erklärt:

Da wir keine neuen Objekt der Klasse erzeugen wollen, ist der Konstruktor uninteressant. Alles was benötigt wird ist eine Referenz auf das einzige erzeugte Objekt. Dafür gibt es die statische Methode getInstance(). In der Methode wird geprüft, ob schon ein Objekt der Klasse vorhanden ist. Falls nicht, wird eine Instanz erzeugt und die Referenz im Klassenattribut $uniqueInstance gespeichert In jedem Fall wird das statische Attribut $uniqueInstance zurückgegeben. .
Der Beispielcode:

class ErrorManager {
	private  $errors, $errorCodes;
	private static $uniqueInstance=NULL;

	private final function __clone(){}
	private function __construct(){
		/** **/
	}

	public static function getInstance(){
		if (self::$uniqueInstance === NULL)
			self::$uniqueInstance = new ErrorManager();
		return self::$uniqueInstance;
	}//getInstance
}

Copy Operator und Konstruktor werden überschrieben, damit niemand durch Vererbung das Pattern aushebeln kann. Die Referenz auf das Objekt können wir uns mit dem Scope Operator besorgen:

$err_manager = ErrorManager::getInstance();

Wer es nicht glaubt kann die Instanz 2 verschiedenen Variablen zuweisen und vergleichen:

$e1 = ErrorManager::getInstance();
$e2 = ErrorManager::getInstance();
if ($e1 === $e2)
    echo "equal";

Soviel zum Singleton Pattern und weiter mit der Fehlerbehandlung. Fehlermeldungen sind immer ein zweischneidiges Schwert, wenn es um Webapplikationen geht. Dem Entwickler helfen sie und irgendwelchen Scriptkiddies leider auch. In der php.ini kann man sie zwar komplett abschalten, aber vielleicht möchte man die Meldungen bestimmten angemeldeten Nutzern nicht vorenthalten. Meine Interpretation des Errorhandlings ist durchaus ausbaufähig aber schon recht brauchbar. Wichtig für die Funktionalität ist das Hochschrauben des Error Reportings:

error_reporting( -1 );

Nun muss ein Errorhandler angegeben werden . Das mache ich im Konstruktor:

	private function __construct(){
			$this->errors = array();
			error_reporting( -1 );
			set_error_handler ( array(__CLASS__, 'errorHandle' ) );
	}

Statt Warnungen und Fehler in die Ausgabe zu schreiben, wird alles nun an die Methode errorHandle übergeben. Ich habe ein Array mit abstrakten Datentypen – AdtError genannt -angelegt. Die Methode erzeugt nun AdtError Objekte und pusht diese in ein Array:

	public static function errorHandle( $code, $msg, $file, $line ){
		$error = new AdtError($code, $msg, $file, $line);
		$s = self::getInstance();
		array_push($s->errors, $error);
	}//errorHandle

Für die Ausgabe hat AdtError die Java-like Methode toString():

	public function getErrors(){
		$s = self::getInstance();
		foreach ($s->errors as $error)
			echo $error->toString().'

';

	}//getErrors

Wenn man nun den Errorhandler anmeldet und ein wenig Unfug schreibt, wird alles wunderbar abgefangen und bei Bedarf ausgegeben:

$err_manager = ErrorManager::getInstance();

foreach ($e_codes as $code => $value)
	echo $code ." ". $value."

";

$err_manager->getErrors();

Bildschirmausgabe:

E_NOTICE Undefined variable: e_codes /home/schmiddi/web/gloria/err_handling/CErrorhandling.php 93
E_WARNING Invalid argument supplied for foreach() /home/schmiddi/web/gloria/err_handling/CErrorhandling.php 93

Wunderbar. Wie schon gesagt gibts durchaus Raum für Verbesserungen. So könnte man der Klasse Abbruchbedingungen beibringen, optional in Textdateien schreiben, schöner Formatieren das Ding in ein MVC Muster hauen usw. Für Interessierte gibts noch den Quelltext: ErrorManager

Abstract Factory mit PHP

Battersea Power Station from Train, 29-04-06
Attribution-NonCommercial License by DG Jones

Inzwischen beschäftige ich mich fast nur noch mit PHP und aus Skripten wird langsam Programmieren. Ich möchte hier mit einem tatsächlich im RL vorkommendes Beispiel zeigen, dass Design Patterns nicht nur elegant und oo. sind sondern auch bei kleineren Skripts sehr nützlich sind.

Vor einigen Wochen habe ich mein unsägliches WordPress Plugin geschrieben. Dort werden unter anderem auch Urls mit verschiedenen Diensten verkürzt. Quick ’n Dirty habe ich eine Klasse angelegt und Methoden wie getShortUrlIsgd(), getShortUrlTinyUrl() erzeugt. Am Anfang gings noch relativ gut, bis ich Anfragen für andere Services bekam. Die wurden dann nach gleichem Schema in die Klasse gepastet. Die Auswahl des Urlshortener verläuft dann auch entsprechend unelegant über ein Switch Case Statement:

switch ($selected_shortener){
	case 'is.gd':
		$new_url=$this->getShortUrlIsgd();
		break;
	case 'bit.ly':
		$new_url=$this->getShortUrlBitly(	  get_option('schmie_tw_bitly_usr'),
					get_option('schmie_tw_bitly_api'));
		break;
	case 'i2h.de':
		$new_url=$this->getShortUrlI2h();
		break;
	case 'tinyurl.com':
		$new_url=$this->;getShortUrlTinyurl();
		break;
	}//switch

Mit einem Erzeugungsmuster wird die Geschichte wesentlich eleganter. Ich habe mich für die „Abstrakte Fabrik“ / Abstract Factory Kit entschieden. dabei wird eine abstrakte Klasse geschrieben, die zur Laufzeit die tatsächlich zu verwendende Klasse einbindet. Zur Übersichtlichkeit habe ich auf include und require Mechanismen in dem Beispiel verzichtet.

Betrachten wir zunächst die Factory Klasse:

abstract class ShortenerInterface{
	//some attributes
	protected  $login, $apikey,$serviceurl,$longurl;

	protected function __construct($login="", $apikey=""){
		$this->login = $login;
		$this->apikey = $apikey;
	}

	public static function factory($class,$login="", $apikey=""){
		return new $class($login=$login, $apikey=$apikey);

	}//factory

	protected function get_url($longurl) {
	/** ... **/
	}//get_url

       //diese Funktion will in jeder abgeleiteten Klasse implementiert werden
	public abstract function get_short_url($url);

}//class

Der Konstruktor ist relativ egal für das Designprinzip. Außer Attributzuweisungen macht er nicht viel. Wesentlich interessanter ist die Methode factory. Durch das Schlüsselwort static kann die Methode aufgerufen werden, ohne vorher das Objekt zu instanziieren (geht auch schlecht bei abstrakten Klassen).

Zurückgegeben wird eine Instanz der Gewünschten Klasse. Die beiden Argumente werden einfach durchgereicht. Die Abstrakte Methode get_url($longurl) muß in jeder abgeleiteten Klasse implementiert werden.

Ein Beispiel:

class CTinyurl extends ShortenerInterface{
	public function get_short_url($longurl){
		$this->serviceurl='http://tinyurl.com/api-create.php?url=';
		return $this->get_url($longurl);
	}//function
}//class

Der Implementierungsaufwand ist minimal wie man sieht. An eine Konkrete Instanz kommt man so:

$iface = ShortenerInterface::factory("CTinyurl");
$iface->get_short_url("http://schmiddi.co.cc");

oder so:

$services = array('CIsgd', 'CTinyurl', 'CI2h', 'CBitly');
foreach ($services as $service){
	$iface = ShortenerInterface::factory($service,   "", "");
	$url =  $iface->get_short_url("schmiddi.co.cc");
	echo "$url
";

Seehr schön. Auch wenn man funktional (wie in meinem Plugin-Fall) schreiben muß, sollte man immer mal kurz darüber Nachdenken etwas aus der Softwaretechnik Vorlesung zu implementieren. Über Verbesserungen und Vorschläge würde ich mich wie immer sehr freuen.

Wer den Code haben will: factory

P.S.:Wer das Kraftwerk auf dem Bild erkennt hat einen wirklich guten Musikgeschmack.