<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ebene7 &#187; Qualitätssicherung</title>
	<atom:link href="http://blog.ebene7.com/kategorie/entwicklung/qualitaetssicherung/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.ebene7.com</link>
	<description></description>
	<lastBuildDate>Tue, 04 Jun 2013 18:57:27 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>TemplateMethod vs. method_exists()-Prüfung</title>
		<link>https://blog.ebene7.com/2012/01/11/templatemethod-vs-method-exists-pruefung/</link>
		<comments>https://blog.ebene7.com/2012/01/11/templatemethod-vs-method-exists-pruefung/#comments</comments>
		<pubDate>Wed, 11 Jan 2012 07:00:07 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Qualitätssicherung]]></category>
		<category><![CDATA[Benchmark]]></category>
		<category><![CDATA[Design Patterns]]></category>
		<category><![CDATA[Entwurfsmuster]]></category>
		<category><![CDATA[Template Method]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=3295</guid>
		<description><![CDATA[Das Entwurfsmuster TemplateMethod kennen und nutzen sicherlich viele von euch. Spätestens, wenn irgendein Framework im Einsatz ist, hat man in der Regel damit zu tun, um z.B. an verschiedenen Stellen im Code eigene Funktionen in einen Ablauf einzuhängen. Das Prinzip &#8230; <a href="https://blog.ebene7.com/2012/01/11/templatemethod-vs-method-exists-pruefung/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Das Entwurfsmuster <a href="http://de.wikipedia.org/wiki/Template_Method" target="_blank">TemplateMethod</a> kennen und nutzen sicherlich viele von euch. Spätestens, wenn irgendein Framework im Einsatz ist, hat man in der Regel damit zu tun, um z.B. an verschiedenen Stellen im Code eigene Funktionen in einen Ablauf einzuhängen.<span id="more-3295"></span></p>
<p>Das Prinzip ist einfach: in der (abstrakten) Basisklasse wird eine leere Methode definiert, die durch eine konkrete Klasse überschrieben werden kann.</p>
<p>Der Vorteil ist recht offensichtlich. Die Methode kann ohne vorherige Prüfung verwendet werden und das spart an vielen Stellen unnötigen Code. Aus meinem ästhetischem Empfinden der richtige Weg.</p>
<p>Aber auch den anderen Weg habe ich auch schon desöfteren gesehen und mein Bauchgefühl hat ja auch nicht immer recht. Vielleicht ist der schöne Weg ja auch der langsamere?</p>
<p>Gefühl ist gut, Zahlen sind besser! Also habe ich schnell drei Testklassen geschrieben und probiere die verschiedenen Möglichkeiten durch.</p>
<p>Variante 1: Wir verlassen uns darauf, dass die Methode aufgerufen werden kann.</p>
<pre>&lt;?php
class Test1 {
    public function machWas() {
        $this-&gt;machWasAnderes();
    }

    public function machWasAnderes() {
    }
}</pre>
<p>Variante 2: Wir prüfen, ob die Methode existiert und finden nichts.</p>
<pre>&lt;?php
class Test2 {
    public function machWas() {
        if (method_exists($this, 'machWasAnderes')) {
            $this-&gt;machWasAnderes();
        }
    }
}</pre>
<p>Variante 3: Wir prüfen, ob die Methode existiert und rufen sie auf.</p>
<pre>&lt;?php
class Test3 {
    public function machWas() {
        if (method_exists($this, 'machWasAnderes')) {
            $this-&gt;machWasAnderes();
        }
    }

    public function machWasAnderes() {
    }
}</pre>
<p>Zum Vergleich habe ich das folgende Script verwendet.</p>
<pre>&lt;?php
foreach (array('Test1', 'Test2', 'Test3') as $class) {
    $object = new $class();
    $start = microtime(true);

    for($i=0; $i&lt;100000; $i++) {
        $object-&gt;machWas();
    }
    echo $class . ' = ' . round(microtime(true) - $start, 5) . '&lt;br/&gt;';
}</pre>
<p>Ausgabe:</p>
<pre>Test1 = 0.44767
Test2 = 0.48588
Test3 = 0.70881</pre>
<p>In mehreren Durchläufen waren &#8220;Test1&#8243; und &#8220;Test2&#8243; immer fast gleich auf, nur &#8220;Test3&#8243; brauchte etwas länger, weil in der Klasse die Prüfung und die Ausführung der Methode stattfindet.</p>
<p>Fazit: Der Einsatz von Schablonenmethoden lohnt sich doppelt, da der Code übersichtlich bleibt und auch die Geschwindigkeit etwas besser ist.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2012/01/11/templatemethod-vs-method-exists-pruefung/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Ausgelagerte Ablaufkontrolle dank Retry-Proxy</title>
		<link>https://blog.ebene7.com/2011/08/11/ausgelagerte-ablaufkontrolle-dank-retry-proxy/</link>
		<comments>https://blog.ebene7.com/2011/08/11/ausgelagerte-ablaufkontrolle-dank-retry-proxy/#comments</comments>
		<pubDate>Thu, 11 Aug 2011 04:00:09 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Qualitätssicherung]]></category>
		<category><![CDATA[Exception-Handling]]></category>
		<category><![CDATA[Funktion]]></category>
		<category><![CDATA[Methode]]></category>
		<category><![CDATA[Proxy]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=2910</guid>
		<description><![CDATA[Neulich bin ich während der Arbeit auf ein kleines Problem gestoßen, welches sich eigentlich sehr einfach lösen lies. Da ich diese Lösung aber nicht wirklich toll fand und ja auch schon länger keinen Artikel mehr geschrieben habe, habe ich mir &#8230; <a href="https://blog.ebene7.com/2011/08/11/ausgelagerte-ablaufkontrolle-dank-retry-proxy/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Neulich bin ich während der Arbeit auf ein kleines Problem gestoßen, welches sich eigentlich sehr einfach lösen lies. Da ich diese Lösung aber nicht wirklich toll fand und ja auch schon länger keinen Artikel mehr geschrieben habe, habe ich mir also ein paar Gedanken dazu gemacht und schreibe heute zum Thema <a href="http://blog.ebene7.com/2009/12/29/decorator-adapter-oder-proxy-was-bist-du-eigentlich/" target="_blank">Proxy</a>.<span id="more-2910"></span></p>
<p>Was ist aber eigentlich passiert? Für eine bestimmte Aufgabe musste ich Daten in der SimpleDB (Amazon Webservices) zwischengespeichern und dann an anderer Stelle weiter verarbeitet. Nun passiert es hin und wieder, dass meine Weiterleitung schneller als die Datenbank war und ich die Daten (noch) nicht lesen konnte.</p>
<p>Was macht man in diesem Fall? Abwarten, Tee trinken und nochmal probieren. In dem Fall kamen ein paar Zeilen Code dazu und alles lief wie gewünscht. Wirklich schick ist das jedoch so noch nicht.</p>
<p>Erstmal eine einfach Beipielklasse im PHP-Pseudocode zum besseren Verständnis:</p>
<pre>&lt;?php
class SomeWebResource
{
  public function load($key)
  {
    // do something
    return $data;
  }

  public function save($key, $data)
  {
    // do something
    return $flag;
  }

  public function delete($key)
  {
    // do something
    return $flag;
  }
}</pre>
<p>In diesem Beispiel hat unsere Klasse drei Methoden, in denen die selben oder zumindest ähnliche Probleme auftreten können. Die Daten haben das falsche Format, der Webservice ist nicht erreichbar oder was auch immer.</p>
<p>Für diesen Fall bauen wir dann nun die Wiederholung ein.</p>
<pre>&lt;?php
class SomeWebResource
{
  public function load($key)
  {
    $count = 0;
    do {
      try {
        // do something
        return $data;
      } catch (Exception $e) {
        sleep(1);
      }
    } while (3 &gt; $count++);
  }

  public function save($key, $data)
  {
    $count = 0;
    do {
      try {
        // do something
        return $flag;
      } catch (Exception $e) {
        sleep(1);
      }
    } while (3 &gt; $count++);
  }

  public function delete($key)
  {
    $count = 0;
    do {
      try {
        // do something
        return $flag;
      } catch (Exception $e) {
        sleep(1);
      }
    } while (3 &gt; $count++);
  }
}</pre>
<p>Spontan sollten nun jedem mindestens drei Dinge auffallen. Der Code ist gleich um etliche Zeilen länger und wiederholt sich, man könnte fast ein Muster (Pattern) erkennen. Der Code ist nicht wirklich flexibel, wenn es darum geht die Wartezeit oder die Anzahl der Versuche zu konfigurieren. Der Code ist immer da und lässt sich so nicht mehr ohne die Wiederholung ausführen und es ist nicht die Aufgabe dieser Klasse die Wiederholungen zu kontrollieren.</p>
<p>In dem Fall schreit es doch gerade danach, diesen Code recyclebar auszulagern, findet ihr nicht?</p>
<p>Dafür brauchen wir nur eine einfache Proxy-Klasse. Ok, bevor jetzt jemand protestiert, dass sei doch garnicht das Proxy-Pattern, stimmt! Wir leiten die Proxy-Klasse nicht von der Klasse &#8220;SomeWebResource&#8221; ab und haben dadurch eine andere Schnittstelle. In diesem Fall ist das aber egal, denn wir leiten ja auch nur den Methodenaufruf weiter.</p>
<p>Nun aber erstmal die <a href="http://blog.ebene7.com/download/code/E7/Tools/RetryProxy.txt" target="_blank">RetryProxy</a>-Klasse:</p>
<pre>&lt;?php
class E7_Tools_RetryProxy
{
  // some other methods

  public function call($callback)
  {
    $exception = null;
    $count = 0;
    $args = func_get_args();
    array_shift($args);

    do {
      try {
        return call_user_func_array($callback, $args);
      } catch (Exception $e) {
        $exception = $e;
        sleep($this-&gt;getDelay());
      }
    } while ($this-&gt;getRepititions() &gt; $count++);

    if ($exception instanceof Exception) {
      throw $exception;
    }
  }
}</pre>
<p>Auch hier lässt sich natürlich das selbe Muster erkennen, aber wir haben es von jeder weitern Logik entkoppelt und die gewünschten Werte lassen sich nun einfach über die Setter einstellen.</p>
<p>Die Verwendung ist später ebenfalls einfach.</p>
<pre>&lt;?php
$proxy = new E7_Tools_RetryProxy();
$swr   = new SomeWebResource();
$data  = $proxy-&gt;call(array($swr, 'load'), 42);</pre>
<p>Wer damit etwas experimentieren will, findet die komplette Klasse <a href="http://blog.ebene7.com/download/code/E7/Tools/RetryProxy.txt" target="_self">hier</a>. Wie immer freue ich mich natürlich über möglichst zahlreiche Kommentare.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2011/08/11/ausgelagerte-ablaufkontrolle-dank-retry-proxy/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Programm to an Interface, Dude!</title>
		<link>https://blog.ebene7.com/2011/07/11/programm-to-an-interface-dude/</link>
		<comments>https://blog.ebene7.com/2011/07/11/programm-to-an-interface-dude/#comments</comments>
		<pubDate>Mon, 11 Jul 2011 04:00:12 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Qualitätssicherung]]></category>
		<category><![CDATA[Data Mapper]]></category>
		<category><![CDATA[Implementierung]]></category>
		<category><![CDATA[Interface]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[Model]]></category>
		<category><![CDATA[OOP]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=2891</guid>
		<description><![CDATA[Heute mag ich mal ein einfaches Thema aufgreifen, welches jedoch noch nicht wirklich seinen Weg in die PHP-Welt gefunden hat. Es geht um Interfaces. Seit Version 5 kann man in PHP viele der lange vermissten OOP-Features nutzen, aber leider machen &#8230; <a href="https://blog.ebene7.com/2011/07/11/programm-to-an-interface-dude/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Heute mag ich mal ein einfaches Thema aufgreifen, welches jedoch noch nicht wirklich seinen Weg in die PHP-Welt gefunden hat. Es geht um Interfaces. Seit Version 5 kann man in PHP viele der lange vermissten OOP-Features nutzen, aber leider machen viele Entwickler dennoch einen großen Bogen darum.</p>
<p><span id="more-2891"></span>Als ich mich vor ein paar Jahren auf meine Java-Zertifizierung vorbereitet habe, ist mir ein Satz immer wieder begegnet: &#8220;Programm to an interface, not to an implementation!&#8221;. Klingt einfach, ist es auch.</p>
<p>Im Prinzip sagt das nur aus, dass man sich beim Entwickeln nur darauf verlassen sollte, was die jeweilig implementierten Interfaces an Funktionalität anbieten. Wie das ganze dann im Hintergrund implementiert ist, interessiert dann nicht mehr.</p>
<p>Ein kleines Beispiel aus der Praxis: In einem Shop (in dem Fall Magento) werden Bestellungen (Orders) gespeichert. Nun soll ein <a href="http://de.wikipedia.org/wiki/Enterprise_Resource_Planning" target="_blank">ERP-System</a> angebunden werden. Für beide Systeme gibt es entsprechende Models, mit denen die Daten verarbeitet werden können.</p>
<p>Soweit, so gut. Jetzt kommt der unbequeme Teil der Aufgabe. Das Magento-Order-Model erbt einfach nur von verschiedenen anderen Klassen, aber es existiert kein Interface, das dem Entwickler bestimmte Methoden garantiert. An vielen Stellen werden zudem die Parameter mit Type-Hinting überprüft, ob sie eine Magento-Order enthalten.</p>
<p>Das Model für die Anbindung an das ERP-System hat unter Umständen andere Elternklassen und somit auch erstmal keine Gemeinsamkeiten. Das bedeutet, dass wir theoretisch die Objekte gleich behandeln könnten, aber wir sie für das Type-Hinting doch wieder in Wrapper verpacken oder auf Magento-Order-Objekte mappen müssen.</p>
<p>Diese Arbeit könnte man sich komplett sparen, wenn man sich von Anfang an auf ein Interface verlassen hätte. Leider existiert dieses meines Wissens nicht und es für eigene Projekte zu nutzen würde Änderungen in den Magento-Core-Dateien fordern.</p>
<pre>&lt;?php
interface Mage_Sales_Model_Order_Interface
{
  /**
   * Retrieve customer model
   *
   * @return Mage_Customer_Model_Customer_Interface
   */
  public function getCustomer();

  // ...
}</pre>
<p>Damit könnte man sich auf verschiedene Methoden verlassen die der Typ Mage_Sales_Model_Order_Interface (!) zusagt.</p>
<pre>&lt;?php
class Mage_Sales_Model_Order
  extends Mage_Sales_Model_Abstract
  implements Mage_Sales_Model_Order_Interface
{
  // ...
}</pre>
<p>Die Klasse Mage_Sales_Model_Order könnte sich an diesen &#8220;Vertrag&#8221; halten,</p>
<pre>&lt;?php
class Erp_Sales_Model_Order
  extends Erp_Was_Auch_Immer_Model_Abstract
  implements Mage_Sales_Model_Order_Interface
{
  // ...
}</pre>
<p>sowie auch jede andere Klasse.</p>
<pre>&lt;?php
// ...
public function getEmailFromOrder(Mage_Sales_Model_Order_Interface $order)
{
  return $order-&gt;getCustomer()-&gt;getEmail();
}
// ...</pre>
<p>So können wir jede beliebige Klasse mit bestehenden Code weiterhin verarbeiten, ohne dass uns das Type-Hinting dabei im Weg steht. Was die Methode getCustomer() nun intern macht, ist uns egal, solange ein Objekt vom Typ Mage_Customer_Model_Customer_Interface zurückgegeben wird.</p>
<p>Es ist vielleicht auf den ersten Blick etwas umständlicher, für jeden Typ ein Interface zu schreiben, aber das spart man danach wieder locker ein und bleibt dazu auch in der weiteren Entwicklung seiner Anwendung flexibel.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2011/07/11/programm-to-an-interface-dude/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Amazon S3 mit PHP-Stream Wrapper verwenden</title>
		<link>https://blog.ebene7.com/2011/01/21/amazon-s3-mit-php-stream-wrapper-verwenden/</link>
		<comments>https://blog.ebene7.com/2011/01/21/amazon-s3-mit-php-stream-wrapper-verwenden/#comments</comments>
		<pubDate>Fri, 21 Jan 2011 05:00:07 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Qualitätssicherung]]></category>
		<category><![CDATA[Amazon]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[S3]]></category>
		<category><![CDATA[Stream]]></category>
		<category><![CDATA[Wrapper]]></category>
		<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[Zend_Cloud]]></category>
		<category><![CDATA[Zend_Service]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=2645</guid>
		<description><![CDATA[In der letzten Woche habe ich ja bereits über die Komponente Zend_Cloud geschrieben und ungetestet behauptet, dass sie sicherlich leicht zu verwenden sei. Das Testen habe ich nun nachgeholt und habe erwartungsgemäß keine bösen Überraschungen erlebt. Ganz im Gegenteil, sogar! &#8230; <a href="https://blog.ebene7.com/2011/01/21/amazon-s3-mit-php-stream-wrapper-verwenden/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In der letzten Woche habe ich ja bereits über die Komponente <a href="http://blog.ebene7.com/2011/01/13/auf-wolke-sieben-mit-zend_cloud/" target="_self">Zend_Cloud</a> geschrieben und ungetestet behauptet, dass sie sicherlich leicht zu verwenden sei. Das Testen habe ich nun nachgeholt und habe erwartungsgemäß keine bösen Überraschungen erlebt.</p>
<p>Ganz im Gegenteil, sogar! Während meiner Arbeit mit Amazon S3 kam mir der Gedanke, dass es doch sehr bequem wäre, wenn es einen Stream Wrapper gäbe und man die PHP-eigenen File-Funktionen zum Lesen und Schreiben verwenden könnte.</p>
<p>Nach kurzem Suchen habe ich, wen wird es überraschen, eine noch einfachere Lösung gefunden. Zuerst aber mein Versuch mit Zend_Cloud Dateien nach Amazon S3 zu kopieren.<span id="more-2645"></span></p>
<h3>Zend_Cloud</h3>
<p>Einfach die <a href="http://framework.zend.com/manual/de/zend.cloud.storageservice.html" target="_blank">Storage-Factory</a> mit den nötigen Zugangsdaten füttern und schon kann es losgehen.</p>
<pre>&lt;?php
$adapter      = 'Zend_Cloud_StorageService_Adapter_S3';
$amazonKey    = '&lt;amazon-key&gt;';
$amazonSecret = '&lt;amazon-secret&gt;';
$bucketName   = 'mein-bucket';

$storage = Zend_Cloud_StorageService_Factory::getAdapter(array(
  Zend_Cloud_StorageService_Factory::STORAGE_ADAPTER_KEY =&gt; $adapter,
  Zend_Cloud_StorageService_Adapter_S3::AWS_ACCESS_KEY   =&gt; $amazonKey,
  Zend_Cloud_StorageService_Adapter_S3::AWS_SECRET_KEY   =&gt; $amazonSecret,
  Zend_Cloud_StorageService_Adapter_S3::BUCKET_NAME      =&gt; $bucketName,
));</pre>
<p>Die Factory liefert uns ein gebrauchsfertiges Objekt zurück, mit dem wir nun Dateien erzeugen können.</p>
<pre>&lt;?php
$filename = 'example.txt';
$data = file_get_contents($filename);
$storage-&gt;storeItem($filename, $data);</pre>
<p>Ebenso einfach wie das Erstellen ist auch das Lesen&#8230;</p>
<pre>&lt;?php
echo $storage-&gt;fetchItem($filename));</pre>
<p>&#8230;oder Löschen einer Datei.</p>
<pre>&lt;?php
$storage-&gt;deleteItem($filename);</pre>
<h3>Zend_Service</h3>
<p>Nun hatte ich ja versprochen, dass es noch einfacher geht. Die Komponente Zend_Service bietet ebenfalls eine Schnittstelle für <a href="http://framework.zend.com/manual/de/zend.service.amazon.s3.html" target="_blank">Amazon S3</a> an und auch gleich eine Methode, diese als Stream Wrapper zu registrieren.</p>
<p>Zuerst muss natürlich das Objekt mit den Zugangsdaten erzeugt werden.</p>
<pre>&lt;?php
$amazonKey    = '&lt;amazon-key&gt;';
$amazonSecret = '&lt;amazon-secret&gt;';

$s3 = new Zend_Service_Amazon_S3($amazonKey, $amazonSecret);
$s3-&gt;registerStreamWrapper('s3');</pre>
<p>Ab jetzt ist der Stream Wrapper mit dem Schema &#8216;s3://&#8217; im System bekannt und mit den gewohnten File-Funktionen verwendet werden. Dadurch bleibt der Code schlank und man muss sich nicht für jede Speicherart eine andere Schnittstelle merken.</p>
<p>Nicht zuletzt können wir unsere Dateien nun organisieren wie und wo wir wollen ohne dabei wieder den Code umschreiben zu müssen.</p>
<pre>&lt;?php
file_put_contents("s3://&lt;bucket-name&gt;/halloWelt", "Hallo Welt"); // einfach schreiben
echo file_get_contents("s3://&lt;bucket-name&gt;/halloWelt"); // und wieder lesen</pre>
<p>Nebenbei bemerkt ist es auch recht einfach, sich einen eigenen Stream Wrapper für spezielle Anwendungfälle selber zu schreiben, aber dazu vielleicht mehr in einem weiteren Artikel.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2011/01/21/amazon-s3-mit-php-stream-wrapper-verwenden/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Wir brauchen echte Typen und keine Primitiven, oder?</title>
		<link>https://blog.ebene7.com/2011/01/05/wir-brauchen-echte-typen-und-keine-primitiven-oder/</link>
		<comments>https://blog.ebene7.com/2011/01/05/wir-brauchen-echte-typen-und-keine-primitiven-oder/#comments</comments>
		<pubDate>Wed, 05 Jan 2011 05:00:52 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Qualitätssicherung]]></category>
		<category><![CDATA[Datentypen]]></category>
		<category><![CDATA[Interface]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[OOP]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=2408</guid>
		<description><![CDATA[Ich bin ein großer Fan objektorientierter Programmierung und wenn es nach mir ginge, würde ich auch nur Objekte verwenden. Aber nach mir geht es nicht, das Leben ist kein Ponyhof und ich habe mich so entschieden mein Geld mit PHP- &#8230; <a href="https://blog.ebene7.com/2011/01/05/wir-brauchen-echte-typen-und-keine-primitiven-oder/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Ich bin ein großer Fan objektorientierter Programmierung und wenn es nach mir ginge, würde ich auch nur Objekte verwenden.</p>
<p>Aber nach mir geht es nicht, das Leben ist kein Ponyhof und ich habe mich so entschieden mein Geld mit <a href="http://blog.ebene7.com/kategorie/entwicklung/php/" target="_self">PHP</a>- und nicht mit <a href="http://blog.ebene7.com/kategorie/entwicklung/java/" target="_self">Java</a>-Programmierung zu verdienen. Genug gejammert, worum geht es?<span id="more-2408"></span></p>
<p>In den letzten Tagen, Urlaub sei Dank, hatte ich etwas mehr Zeit mich durch die Blogwelt zu klicken und habe dabei einen älteren <a href="http://ajaveeb.de/string-klasse-version-1-0-1-331" target="_blank">Artikel von Benjamin</a> entdeckt, in dem er seine PHP-Stringklasse vorstellt. Etwas schmunzeln musste ich bei der Lizenz für die wenigen Zeilen Code, aber Ordnung muss sein. <img src='https://blog.ebene7.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>Die Idee gefällt mir sehr gut keine primitiven Datentypen, sondern echte Objekte zu verwenden.</p>
<p>Inspiriert von der Idee, habe ich ein paar Minuten gebastelt und habe nun meine Custom_String-Klasse. Sie ist einfach umgesetzt, handlich und hat alles was <em>ich</em> brauche.</p>
<p>An der Stelle fiel mir dann auch gleich wieder ein, warum ich das bisher nicht umgesetzt habe.</p>
<p>Wer sich etwas mit Java auskennt, der weiß, dass sämtliche Objekte in gewisser Weise nach bestimmten Mustern funktionieren. Will ich meine <a href="http://blog.ebene7.com/2010/09/06/besser-sortieren-mit-php-dank-java-interfaces/" target="_self">Objekte sortieren</a> können, dann implementiere ich einfach das Interface Comparable und gut ist.</p>
<p>An dem Beispiel mit den Strings sollte das Problem klar werden. Benjamin hat eine Klasse für Strings geschrieben, wie er sie gerne hätte, ich habe das getan und viele andere vielleicht auch.</p>
<p>Jede für sich mag gut sein, aber auch etwas anders funktionieren und eine andere Schnittstelle bieten.</p>
<p>In großen Systemen kommen nun die Arbeiten vieler Entwickler zusammen, teilweise sogar aus verschiedenen Teams oder auch Firmen.</p>
<p>Um nun einheitlich mit allen Objekten arbeiten zu können, brauchen wir zwangsläufig <a href="http://blog.ebene7.com/2009/12/29/decorator-adapter-oder-proxy-was-bist-du-eigentlich/" target="_self">Adapter</a>-Klassen und haben damit weitere potentielle Schwachstellen im System. Wir müssten jedes Objekt an den Schnittstellen richtig verpacken und bauschen dadurch den Code auf und wir haben die Adapter-Klassen, die wir ebenfalls mit jeder Änderung der Originalklassen anpassen müssen.</p>
<p>Ich denke, solange PHP nicht im Kern ähnlich wie Java die entsprechenden Schnittstellen vorgibt, macht man sich das Entwicklerleben damit nicht wirklich leichter. Wie denkt ihr darüber?</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2011/01/05/wir-brauchen-echte-typen-und-keine-primitiven-oder/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Enums in PHP (sicher ist sicher)</title>
		<link>https://blog.ebene7.com/2010/10/08/enums-in-php-sicher-ist-sicher/</link>
		<comments>https://blog.ebene7.com/2010/10/08/enums-in-php-sicher-ist-sicher/#comments</comments>
		<pubDate>Fri, 08 Oct 2010 05:00:52 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Qualitätssicherung]]></category>
		<category><![CDATA[CustomLibrary]]></category>
		<category><![CDATA[Enum]]></category>
		<category><![CDATA[Magic Methods]]></category>
		<category><![CDATA[Reflection]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=1586</guid>
		<description><![CDATA[Wer hin und wieder auch mal in anderen Sprachen wie z.B. Java programmiert, dem werden Enums sicher nicht fremd sein. Wäre es nicht schön, ähnliches auch unter PHP zur Verfügung zu haben, um nicht jeden Status als String oder Int &#8230; <a href="https://blog.ebene7.com/2010/10/08/enums-in-php-sicher-ist-sicher/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Wer hin und wieder auch mal in anderen Sprachen wie z.B. Java programmiert, dem werden Enums sicher nicht fremd sein. Wäre es nicht schön, ähnliches auch unter PHP zur Verfügung zu haben, um nicht jeden Status als String oder Int zu übergeben? Tja, das Leben ist aber kein Ponyhof und wenn PHP das nicht anbietet, dann schaffen wir uns eben eine eigene Lösung um besser und (typ-)sicherer zu programmieren.<span id="more-1586"></span></p>
<p>Wir kennen es sicher alle: Wir haben irgendein Objekt und wollen dessen Status oder einen bestimmten Wert setzen oder abfragen. Was passiert sicher in 95% aller Fälle? Es wird ein String- oder Integer-Wert gesetzt oder verglichen. Aus meiner Sicht nicht besonders elegant und erst recht nicht sicher, da der Wert unnötig oft überprüft werden muss.</p>
<p>Mit Enums haben wir den Vorteil, dass wir bestimmte Werte vorgeben können und auch nur diese zu Verfügung stehen. Da wir unter PHP nur &#8220;normale&#8221; Klassen verwenden können, haben wir dadurch immer automatisch einen bestimmten Typen.</p>
<p>Wir wollen nun den Status eines Benutzers in unserem System definieren und legen uns dazu folgende Klasse mit den erforderlichen Werten an.</p>
<pre>&lt;?php
class UserStatus extends Custom_Enum
{
  const ACTIVE    = 1;
  const NOTACTIVE = 2;
  const DELETED   = 3;
}</pre>
<p>Damit können wir unseren Benutzern einen eindeutigen Status setzen.</p>
<pre>&lt;?php
class User
{
  public function setStatus(UserStatus $status)
  {
    // ..
  }
}

$user = new User();

$status = new UserStatus();
$user-&gt;setStatus($status-&gt;active());</pre>
<p>Durch das Type-Hinting können wir schon bei der Parameterübergabe den richtigen Objekttypen sicherstellen und müssen darauf später nicht mehr extra prüfen.</p>
<p>Die Klasse Custom_Enum funktioniert mit Reflektion und etwas PHP-Magie und ist bislang erst nur ein grober Entwurf. Ein paar Überprüfungen und eine bessere Fehlerbehandlung wären dann noch notwendige Maßnahmen.</p>
<pre>&lt;?php
abstract class Custom_Enum
{
  private $_constants;  // array
  private $_index;  // string

  public function  __construct()
  {
    $rc = new ReflectionClass($this);
    $this-&gt;_constants = $rc-&gt;getConstants();
  }

  public function __call($method, $args)
  {
    if (preg_match('/^is([a-zA-Z]*?)$/', $method, $matches)) {
      return $this-&gt;is($matches[1]);
    }
    $this-&gt;set($method);
    return $this;
  }

  public function __toString()
  {
    return (string)$this-&gt;getValue();
  }

  public function set($index)
  {
    $this-&gt;_index = strtoupper($index);
    return $this;
  }

  public function is($index)
  {
    return strtoupper($index) == $this-&gt;_index;
  }

  public function getValue()
  {
    return $this-&gt;_constants[$this-&gt;_index];
  }
}</pre>
<p>Ich finde das schon wesentlich besser als lose String- oder Integerwerte auszutauschen, aber vielleicht geht es ja noch besser und sicherer? Eure Ideen, Kritik, Fragen oder was auch immer sind dann in den Kommentaren gut aufgehoben. Also keine Scheu und diskutiert mit! <img src='https://blog.ebene7.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2010/10/08/enums-in-php-sicher-ist-sicher/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
		<item>
		<title>Fluently self-contained Factory Method</title>
		<link>https://blog.ebene7.com/2010/09/29/fluently-self-contained-factory-method/</link>
		<comments>https://blog.ebene7.com/2010/09/29/fluently-self-contained-factory-method/#comments</comments>
		<pubDate>Wed, 29 Sep 2010 05:00:02 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[Grundlagen]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Qualitätssicherung]]></category>
		<category><![CDATA[Design Patterns]]></category>
		<category><![CDATA[Entwurfsmuster]]></category>
		<category><![CDATA[Factory]]></category>
		<category><![CDATA[Singleton Pattern]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=1510</guid>
		<description><![CDATA[Nein, wir spielen nicht Buzzword-Bingo. Heute geht es darum, Objekt-Instanzen durch einfache Factory Methoden zu erzeugen und sie im Weiteren als Fluent Interface direkt zu nutzen, ohne den Stolperstein &#8220;new&#8221; und ob das in der Form überhaupt sinnvoll ist. Der &#8230; <a href="https://blog.ebene7.com/2010/09/29/fluently-self-contained-factory-method/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Nein, wir spielen nicht Buzzword-Bingo. Heute geht es darum, Objekt-Instanzen durch einfache Factory Methoden zu erzeugen und sie im Weiteren als Fluent Interface direkt zu nutzen, ohne den Stolperstein &#8220;new&#8221; und ob das in der Form überhaupt sinnvoll ist.</p>
<p><span id="more-1510"></span>Der herkömmliche Weg eine Instanz einer Klasse zu erzeugen ist die Verwendung des new-Operators.</p>
<pre>&lt;?php
$meinObject = new MeineKlasse();
$meineKlasse-&gt;machWas();</pre>
<p>Leider funktioniert Methodenverkettung in PHP nicht wie in Java direkt nach &#8220;new&#8221; und wir müssen uns mit einer statischen Methode behelfen. Das Prinzip ähnelt dem Singleton-Muster, jedoch wollen wir in diesem Fall bei jedem Aufruf eine neue Instanz bekommen. Wer schonmal mit (Borland-)Delphi gearbeitet hat, der kennt das sicher schon.</p>
<pre>&lt;?php
class MeineKlasse
{
  public static function create()
  {
    return new self();
  }
}</pre>
<p>Der Vorteil ist nun ganz klar der, dass sich Instanzen in einer Zeile benutzen lassen.</p>
<pre>&lt;?php
MeineKlasse::create()-&gt;machWas();</pre>
<p>Leider fallen mir aber auch spontan zwei Nachteile ein: Bis PHP 5.3 ist die Methode nicht vererbbar, das bedeutet, dass wir die Methode mit jeder Ableitung erneut überschreiben müssten. Ab Version 5.3 kann statt &#8220;self&#8221; dann &#8220;static&#8221; instanziiert werden. Genaueres findet sich auch in den Links in meinem <a href="http://blog.ebene7.com/2010/08/30/vererbbares-singleton-pattern-dank-late-static-binding-ab-php-5-3/">Singleton-Artikel</a>.</p>
<p>Der zweite Nachteil ist genau der, warum man auch &#8220;new&#8221; nicht verwenden sollte. Beides schafft an vielen Stellen im Code Abhängigkeitet zu einer bestimmten Klasse. Wenn nun irgendwann eine abgeleitete Klasse benötigt wird müssen viele Änderungen gemacht werden.</p>
<p>Im Zweifelsfall sollte auf eine klassische, externe Factory zurückgegriffen werden, um derartigen Problemen im Voraus aus dem Weg zu gehen.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2010/09/29/fluently-self-contained-factory-method/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
