<?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; PHP</title>
	<atom:link href="http://blog.ebene7.com/schlagwort/php/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>Symfony2: Globale Variablen in Routen</title>
		<link>https://blog.ebene7.com/2012/12/13/symfony2-globale-variablen-in-routen/</link>
		<comments>https://blog.ebene7.com/2012/12/13/symfony2-globale-variablen-in-routen/#comments</comments>
		<pubDate>Thu, 13 Dec 2012 05:00:17 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Annotations]]></category>
		<category><![CDATA[Konfiguration]]></category>
		<category><![CDATA[Routing]]></category>
		<category><![CDATA[Symfony2]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=3922</guid>
		<description><![CDATA[Für ein Projekt wollte ich ein Prefix für die Routen verwenden und dieses an einer zentralen Stelle konfigurieren können. In diesem Fall sollte damit der Admin-/Backendbereich abgegrenzt werden. Nach etwas Suchen fand ich eine Möglichkeit in der Symfony Dokumentation. Ab &#8230; <a href="https://blog.ebene7.com/2012/12/13/symfony2-globale-variablen-in-routen/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Für ein Projekt wollte ich ein Prefix für die Routen verwenden und dieses an einer zentralen Stelle konfigurieren können. In diesem Fall sollte damit der Admin-/Backendbereich abgegrenzt werden.</p>
<p>Nach etwas Suchen fand ich eine Möglichkeit in der <a href="http://symfony.com/doc/current/cookbook/routing/service_container_parameters.html" target="_blank">Symfony Dokumentation</a>.</p>
<p>Ab Version 2.1 kann ein Parameter in der Konfigurations-Datei gespeichert werden.</p>
<pre># app/config/config.yml
parameters:
    backend_prefix: admin</pre>
<p>Dieser Parameter kann dann z.B. in der Route-Annotation oder der Routing Konfiguration verwendet werden.</p>
<pre>/**
 * @Route("/%backend_prefix%/user")
 */
class UserBackendController extends Controller {
    /**
     * @Route("/")
     */
    public function indexAction() {
        /* do something */
    }
}</pre>
<p>Durch das Prefix ist dieser Bereich nicht nur optisch im URL abgehoben, sondern kann durch die <a href="http://symfony.com/doc/current/book/security.html" target="_blank">Security Konfiguration</a> auch leicht nur für einzelne Nutzergruppen freigegeben werden.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2012/12/13/symfony2-globale-variablen-in-routen/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Sortieren mit PHP5 Closures und dem Java Comparator Pattern</title>
		<link>https://blog.ebene7.com/2012/08/31/sortieren-mit-php5-closures-und-dem-java-comparator-pattern/</link>
		<comments>https://blog.ebene7.com/2012/08/31/sortieren-mit-php5-closures-und-dem-java-comparator-pattern/#comments</comments>
		<pubDate>Fri, 31 Aug 2012 04:00:13 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Callback]]></category>
		<category><![CDATA[Closure]]></category>
		<category><![CDATA[Comparator]]></category>
		<category><![CDATA[Interface]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Sortierung]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=3421</guid>
		<description><![CDATA[Was mich schon oft bei PHP ein wenig störte ist, dass es zum Sortieren nicht so schöne Comparatoren wie in Java gibt. Nun habe ich in der Vergangenheit ja schon das eine oder andere über Closures in PHP und Java &#8230; <a href="https://blog.ebene7.com/2012/08/31/sortieren-mit-php5-closures-und-dem-java-comparator-pattern/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Was mich schon oft bei PHP ein wenig störte ist, dass es zum Sortieren nicht so schöne Comparatoren wie in Java gibt.</p>
<p>Nun habe ich in der Vergangenheit ja schon das eine oder andere über <a href="http://blog.ebene7.com/2012/01/30/closures-in-php/">Closures in PHP</a> und <a href="http://blog.ebene7.com/2010/09/06/besser-sortieren-mit-php-dank-java-interfaces/">Java Comparatoren für PHP</a> geschrieben und wollte das nun mal zusammenbringen.</p>
<p><span id="more-3421"></span>Einige PHP-Sortierfunktionen erlauben Callbacks, um die Reihenfolge zu bestimmen. Da ich das Ganze aber gerne in gut testbaren OOP-Einheiten hätte, müssen wir einen kleinen Umweg gehen.</p>
<p>Zunächst das obligatorische Interface.</p>
<pre>namespace E7;

interface Comparator {
  public function compare($a, $b);
}</pre>
<p>Diese Schnittstelle implementieren wir mit einer abstrakten Klasse.</p>
<pre>namespace E7;

class BaseComparator implements Comparator {
  public function compare($a, $b) {
    if ($a == $b) { return 0; }
    return $a &lt; $b ? -1 : 1;
  }

  public function __invoke() {
    return call_user_func_array(array($this, 'compare'), func_get_args());
  }
}</pre>
<p>Und schon haben wir einen einfachen, und zugegebenermaßen nicht typsicheren, Comparator.</p>
<p>Durch die magische Methode __invoke() kann ein Objekt nun wie eine Callbackfunktion verwendet werden.</p>
<p>Für die Sortierung von Objekten kann das dann einfach erweitert werden.</p>
<pre>class PersonComparator extends BaseComparator {
  public function compare($a, $b) {
    // hier Prüfung auf Typ etc.
    return parent::compare($a-&gt;getId(), $b-&gt;getId());
  }    
}</pre>
<p>Um die Sortierreihenfolge negieren zu können, können wir einen einfachen Wrapper nutzen.</p>
<pre>class ReverseOrder implements Comparator {
  private $_comparator;

  public function __construct(Comparator $comparator) {
    $this-&gt;_comparator = $comparator;
  }

  public function compare($a, $b) {
    return $this-&gt;_comparator-&gt;compare($a, $b) * -1;
  }
}</pre>
<p>Beispiel&#8230;</p>
<pre>//--
$people = array();
for ($i = 0; $i &lt; 10; $i ++) {
  $people[] = new Person();
}

echo 'BEFORE&lt;br/&gt;';
foreach($people as $person) {
  echo "$person&lt;br/&gt;";
}

$comparator = new ReverseOrder( new PersonComparator() );

uasort($people, function($a, $b) use ($comparator) {
    return $comparator-&gt;compare($a, $b);
});

// oder

uasort($people, $comparator);

echo 'AFTER&lt;br/&gt;';
foreach($people as $person) {
  echo "$person&lt;br/&gt;";
}</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2012/08/31/sortieren-mit-php5-closures-und-dem-java-comparator-pattern/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>&#8220;Walkable&#8221; Iterator</title>
		<link>https://blog.ebene7.com/2012/07/31/walkable-iterator/</link>
		<comments>https://blog.ebene7.com/2012/07/31/walkable-iterator/#comments</comments>
		<pubDate>Tue, 31 Jul 2012 04:00:00 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Array]]></category>
		<category><![CDATA[Design Patterns]]></category>
		<category><![CDATA[each]]></category>
		<category><![CDATA[Foreach]]></category>
		<category><![CDATA[Iterator]]></category>
		<category><![CDATA[Schleife]]></category>
		<category><![CDATA[Visitor Pattern]]></category>
		<category><![CDATA[walk]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=3499</guid>
		<description><![CDATA[In PHP haben Entwickler seit Version 5 die Möglichkeit, den Zugriff auf Datenstrukturen durch eigene oder bereits in der SPL vorhandene Iteratoren zu kontrollieren. Das ist einfach und hat sicherlich auch schon jeder einmal gemacht. Damit ist dann zumindest der &#8230; <a href="https://blog.ebene7.com/2012/07/31/walkable-iterator/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In PHP haben Entwickler seit Version 5 die Möglichkeit, den Zugriff auf Datenstrukturen durch eigene oder bereits in der <a href="http://www.php.net/~helly/php/ext/spl/" target="_blank">SPL</a> vorhandene <a href="http://blog.ebene7.com/schlagwort/iterator/">Iteratoren</a> zu kontrollieren. Das ist einfach und hat sicherlich auch schon jeder einmal gemacht.</p>
<p>Damit ist dann zumindest der eine Teil, die Datenstruktur, für sich gekapselt. Was ist aber mit dem Teil, den wir wahrscheinlich häufiger verwenden werden? Wir nutzen Iteratoren in Schleifen und machen irgendwas mit den Elementen.<span id="more-3499"></span></p>
<pre>&lt;?php
foreach($list as $key =&gt; $item) {
  $item-&gt;doSomething();
}

// oder
$values = array();
foreach($list as $key =&gt; $item) {
  $values[] = $item-&gt;getSomething();
}</pre>
<p>In verschiedenen anderen Sprachen, Java, JavaScript etc., sieht man häufig, dass dort auch die Scheifen gekapselt sind. Warum probieren wir das nicht auch mal in PHP?</p>
<p>Ich werde das Beipiel bewusst einfach halten und wie gewohnt auf einige Fehlerbehandlungen verzichten, um den Code übersichtlich zu halten.</p>
<p>Als erstes erstellen wir eine Klasse &#8220;WalkableIterator&#8221; und lassen diese von ArrayIterator erben. Die beiden Methoden &#8220;each&#8221; und &#8220;walk&#8221; bilden später unsere beiden Beispiele ab.</p>
<pre>&lt;?php
class WalkableIterator extends ArrayIterator {
  public function each($method) {}
  public function walk($callback) {}
}</pre>
<p>Mit each() können wir eine bestimmte Methode auf jedem Element in unserem Iterator aufrufen. Dafür müssten hier natürlich diverse Fehlerbehandlungen rein was passieren soll, wenn das Element kein Objekt ist oder die Methode nicht existiert oder diese gar eine Exception wirft.</p>
<pre>&lt;?php
class WalkableIterator extends ArrayIterator {
  public function each($method) {
    $args = func_get_args();
    $method = array_shift($args);
    foreach($this as $item) {
      call_user_func_array( array($item, $method), $args );
    }
  }
  // ...
}</pre>
<p>Das ganze ist denkbar einfach: Die Methode nimmt als ersten Pflichtparameter den Methodennamen entgegen, die auf allen Elementen aufgerufen werden soll und der Rest bleibt flexibel und wird einfach nur durchgereicht.</p>
<p>Die Implementierung von walk() wird sogar noch einfacher, da hier keine Parameter weitergegeben werden müssen. Im produktiven Einsatz müssten auch hier noch die üblichen Fehlerbehandlungen rein.</p>
<pre>&lt;?php
class WalkableIterator extends ArrayIterator {
  // ...
  public function walk($callback) {
    foreach($this as $item) {
      call_user_func( $callback, $item );
    }
  }
}</pre>
<p>Soweit, so einfach&#8230; Was können wir jetzt damit machen? Bauen wir ein kleines Beispiel.</p>
<pre>&lt;?php
// Testklasse
class Person {
  private $name;
  public function __construct($name = 'unnamed') {
    $this-&gt;setName($name);
  }
  public function getName() {
    return $this-&gt;name;
  }
  public function setName($name) {
    $this-&gt;name = $name;
  }
}

// Testarray mit Objekten befüllen
$a = array();
for($i=1; $i &lt;= 10; $i++) {
  $a[] = new Person('Person ' . $i);
}

// Iterator erstellen und Namen ausgeben
$it = new WalkableIterator($a);

foreach($it as $item) {
  echo $item-&gt;getName() . '&lt;br/&gt;';
}

// Person 1
// ...
// Person 10</pre>
<p>Wollten wir nun allen Personenobjekten einen Namen geben, so könnten wir dafür each() verwenden.</p>
<pre>&lt;?php
$it-&gt;each('setName', 'PHP-Nerd');

// PHP-Nerd
// ...
// PHP-Nerd</pre>
<p>Wollen wir unsere Personen dann vielleicht doch wieder individueller benennen, so könnten wird das mit walk() und einem <a href="http://blog.ebene7.com/schlagwort/callback/">Callback</a> machen.</p>
<pre>$callback = function(Person $person) {
  static $count = 1;
  $person-&gt;setName( $person-&gt;getName() . ' ' . $count++ );
};

$it-&gt;walk($callback);</pre>
<pre>// PHP-Nerd 1
// ...
// PHP-Nerd 10</pre>
<p>&#8220;Was bringt uns das und warum so kompliziert?&#8221;, ist in dem Zusammenhang eine oft gehörte Frage.</p>
<p>Zunächst ist die Implementierung, wie das Beispiel sicher beweist, nicht kompliziert.</p>
<p>Die Vorteile sind kürzere Aufrufe im Code, weil wir keine Schleifen mehr schreiben müssen und durch die Kapselung verbessert sich auch die Wart- und Testbarkeit. Der Code existiert nur an einer Stelle und funktioniert überall nach dem selben Muster.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2012/07/31/walkable-iterator/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Closures in PHP</title>
		<link>https://blog.ebene7.com/2012/01/30/closures-in-php/</link>
		<comments>https://blog.ebene7.com/2012/01/30/closures-in-php/#comments</comments>
		<pubDate>Mon, 30 Jan 2012 05:00:58 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Callback]]></category>
		<category><![CDATA[Closure]]></category>
		<category><![CDATA[Interface]]></category>
		<category><![CDATA[SPL]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=3364</guid>
		<description><![CDATA[Ab der Version 5.3 bietet auch PHP, wie auch schon viele andere Sprachen, die Möglichkeit mit anonymen Funktionen zu arbeiten. Dadurch können z.B. Callback-Funktionen zur Filterung o.Ä. implementiert werden, ohne dass man sich dafür tolle Namen ausdenken muss. Aber was &#8230; <a href="https://blog.ebene7.com/2012/01/30/closures-in-php/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Ab der Version 5.3 bietet auch PHP, wie auch schon viele andere Sprachen, die Möglichkeit mit <a href="http://www.php.net/manual/de/functions.anonymous.php" target="_blank">anonymen Funktionen</a> zu arbeiten. Dadurch können z.B. Callback-Funktionen zur Filterung o.Ä. implementiert werden, ohne dass man sich dafür tolle Namen ausdenken muss. Aber was kann man damit noch machen?</p>
<p><span id="more-3364"></span>Bislang musste man Callback-Funktionen gewöhnlich definieren, bevor man sie verwenden konnte.</p>
<pre>&lt;?php
function myCallback($output) {
  return '##' . $output . '##';
}

echo call_user_func('myCallback', 'Hallo Welt');

// Ausgabe:
##Hallo Welt##</pre>
<p>Als Closure geschrieben sähe das dann so aus:</p>
<pre>&lt;?php
echo call_user_func(
  function($output) { return '##' . $output . '##'; },
  'Hallo Welt');

// Ausgabe:
##Hallo Welt##</pre>
<p>Zugegeben, dieses Beispiel hätte man durch einfache Stringverkettung wesentlich einfacher schreiben können und eigentlich war das mit <a href="http://de2.php.net/manual/de/function.create-function.php" target="_blank">create_function()</a> auch schon unter PHP4 möglich.</p>
<p>Wir können die Funktion natürlich wie früher auch schon in einer Variablen speichern und dann weiter verwenden.</p>
<pre>&lt;?php
$myFunction = function($output) {
  return '##' . $output . '##';
};

echo call_user_func($myFunction, 'Hallo Welt') . '&lt;br/&gt;';
echo $myFunction('Hallo Welt') . '&lt;br/&gt;';

//Ausgabe:
##Hallo Welt##
##Hallo Welt##</pre>
<p>Und auch das ist ja noch nichts Neues. Mit Closures haben wir nun aber auch die Möglichkeit, teile unserer &#8220;Umgebung&#8221; zum Zeitpunkt der Funktionsdefinition zu konservieren.</p>
<p>Dazu müssen wir nur die Definition etwas erweitern.</p>
<pre>&lt;?php
$before = '&gt;';
$after = '&lt;';

$myFunction = function($output) use ($before, $after) {
    return $before . $output . $after;
};

echo $myFunction('Hallo Welt') . '&lt;br/&gt;';

//Ausgabe:
&gt;Hallo Welt&lt;</pre>
<p>An dieser Stelle frieren wir mit &#8220;use&#8221; sozusagen die Werte für $before und $after innerhalb unserer Funktion ein. Spätere Änderungen der beiden Variablen haben keine Auswirkungen auf die Funktion.</p>
<pre>$before = 'foo';
$after = 'bar';
echo $myFunction('Hallo Welt') . '&lt;br/&gt;';

//Ausgabe:
&gt;Hallo Welt&lt;</pre>
<p>In PHP wir mittlerweile sehr viel mit Standardinterfaces und -klassen (SPL) abgedeckt und so ist es auch in diesem Fall. In der Variablen $myFunction ist ein Objekt vom Typ &#8220;<a href="http://de2.php.net/manual/en/class.closure.php" target="_blank">Closure</a>&#8221; gespeichert.</p>
<pre>&lt;?php
echo '&lt;pre&gt;' . print_r($myFunction, true) . '&lt;/pre&gt;';

//Ausgabe:
Closure Object
(
  [static] =&gt; Array
    (
      [before] =&gt; &gt;
      [after] =&gt; &lt;
    )
  [parameter] =&gt; Array
    (
      [$output] =&gt;
    )
)</pre>
<p>Will man eigene Objekte wie Funktionen aufrufen, dann geht das mit der magischen Methode <a href="http://de2.php.net/manual/de/language.oop5.magic.php#language.oop5.magic.invoke" target="_blank">__invoke()</a>, die auch hier verwendet wird.</p>
<p>Anfangs erwähnte ich, dass Closure-Callbacks zur Filterung, aber auch zur Manipulation von Array verwendet werden können.</p>
<p>Wenn nur der Inhalt interessant ist, dann kommen wir mit array_map() und einem Parameter aus.</p>
<pre>&lt;?php
$values = array(
  array(
    'a' =&gt; array(
      'b' =&gt; 'foo'
    )
  ),
  array(
    'a' =&gt; array(
      'b' =&gt; 'bar'
    )
  ),
);

$filtered = array_map(
  function ($item) { return $item['a']['b']; },
  $values
);
echo '&lt;pre&gt;' . print_r($filtered, true) . '&lt;/pre&gt;';

// Ausgabe:
Array
(
  [0] =&gt; foo
  [1] =&gt; bar
)</pre>
<p>Wollen wir aber Werte im Array in Abhängigkeit zum Key/Index verändern, dann geht das mit array_walk und einem zweiten Parameter im Callback. Bei beiden kann natürlich auch &#8220;use&#8221; verwendet werden. Der Parameter $value wird dabei als Referenz übernommen.</p>
<pre>$values = array(
  'a' =&gt; 100,
  'b' =&gt; 200,
  'c' =&gt; 300,
);

array_walk(
  $values,
  function (&amp;$value, $key) {
    if ('b' == $key) {
      $value = 42;
    }
  }
);

echo '&lt;pre&gt;' . print_r($values, true) . '&lt;/pre&gt;';

// Ausgabe:
Array
(
  [a] =&gt; 100
  [b] =&gt; 42
  [c] =&gt; 300
)</pre>
<p>Ich hoffe, dass ich ein wenig Licht ins Dunkel bringen konnte und &#8220;Closure&#8221; nun kein geheimnisvolles Zauberwort mehr ist.</p>
<p>Wenn ihr noch gute Ergänzungen oder Anwendungbeispiele habt, dann immer her damit und bitte fleissig kommentieren. <img src='https://blog.ebene7.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2012/01/30/closures-in-php/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<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>Eigene Werte aus PHP in die Apache Logs schreiben</title>
		<link>https://blog.ebene7.com/2011/12/01/eigene-werte-aus-php-in-die-apache-logs-schreiben/</link>
		<comments>https://blog.ebene7.com/2011/12/01/eigene-werte-aus-php-in-die-apache-logs-schreiben/#comments</comments>
		<pubDate>Thu, 01 Dec 2011 05:00:50 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Server und Technik]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[Callback]]></category>
		<category><![CDATA[Logging]]></category>
		<category><![CDATA[Webserver]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=3193</guid>
		<description><![CDATA[Heute, na inzwischen eigentlich schon gestern, habe ich bei der Suche nach einer Apache-Konfiguration durch Zufall etwas interessantes gefunden. Eine PHP-Funktion namens &#8220;apache_note()&#8220;, mit der man Werte aus PHP an die Apache-Logs weitergeben kann. Der eine oder andere kennt die &#8230; <a href="https://blog.ebene7.com/2011/12/01/eigene-werte-aus-php-in-die-apache-logs-schreiben/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Heute, na inzwischen eigentlich schon gestern, habe ich bei der Suche nach einer Apache-Konfiguration durch Zufall etwas interessantes gefunden. Eine PHP-Funktion namens &#8220;<a href="http://php.net/manual/de/function.apache-note.php" target="_blank">apache_note()</a>&#8220;, mit der man Werte aus PHP an die Apache-Logs weitergeben kann.<span id="more-3193"></span></p>
<p>Der eine oder andere kennt die Funktion vielleicht schon, aber für mich ist sie neu. Daher habe ich damit einfach mal etwas rumprobiert und einen kleinen Codeschipsel dazu gebastelt. Die Apache-Logs können für vielfältige Auswertungen verwendet werden.</p>
<p>Zum Beispiel welche Seiten besucht oder nicht gefunden werden können, zum Tracken von Werbemitteln oder in dem Fall auch zum Protokollieren weiterer PHP-Werte.</p>
<p>In einem früheren Projekt haben wir mal die Zeit und den Speicherverbrauch gemessen die ein PHP-Script braucht, um die Seite auszuliefern. Dazu hatten wir eine einfache Klasse, ähnlich der folgenden (im dem Beispiel wird nur die Zeit gemessen):</p>
<pre>class PageBenchmark
{
  private $_startTime;
  private static $_instance;

  protected function __construct()
  {
    register_shutdown_function(array(self::$_instance, 'stop'));
    $this-&gt;start();
  }

  protected function __clone() {}

  public function getInstance()
  {
    if (null === self::$_instance) {
      self::$_instance = new self();
    }
    return self::$_instance;
  }

  public function start()
  {
    $this-&gt;_startTime = microtime(true);
  }

  public function stop()
  {
    $time = microtime() - $this-&gt;_startTime;
    apache_note('worktime', $time);
  }
}

PageBenchmark::getInstance();</pre>
<p>Die Klasse ist bewusst einfach gehalten und sollte möglichst ohne weitere Abhängigkeiten funktionieren. Die Verwendung ist dabei recht einfach. Das Script an einer zentralen Stelle möglichst früh einbinden. Durch den Aufruf von getInstance() wird ein Objekt instanziiert und die Methode stop() als Callback registriert.</p>
<p>Wird das Script nun abgearbeitet, wird diese Methode zum Ende aufgerufen und die verbrauchte Zeit wird errechnet und an Apache übergeben.</p>
<p>Damit das ganze dann einen Sinn bekommt, muss die Konfiguration des Webservers noch etwas angepasst werden. Für unser Beispiel schreiben wir die Zeit an das Ende jeder Zeile.</p>
<pre>LogFormat "%h %l %u %t \"%r\" %&gt;s %b \"%{Referer}i\" [%{worktime}n]" mylogformat
CustomLog /var/www/sandkasten/logs/access.log mylogformat</pre>
<p>Danach natürlich den Webserver neu starten, bzw. ein Reload machen. Ab jetzt sollte zu jedem Logeintrag die verbrauchte Zeit mitgeschrieben werden. Die verwendeten Kürzel werden in der <a href="http://httpd.apache.org/docs/current/mod/mod_log_config.html" target="_blank">Doku zu mod_log_config</a> erklärt.</p>
<p>Viel Spaß beim Probieren!</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2011/12/01/eigene-werte-aus-php-in-die-apache-logs-schreiben/feed/</wfw:commentRss>
		<slash:comments>1</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>
	</channel>
</rss>
