<?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>Yoda Condition &#187; PHP</title>
	<atom:link href="http://yoda.neun12.de/artikel-category/php/feed" rel="self" type="application/rss+xml" />
	<link>http://yoda.neun12.de</link>
	<description>Debuggen du musst</description>
	<lastBuildDate>Sun, 18 May 2014 13:49:01 +0000</lastBuildDate>
	<language>de-DE</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=3.9.40</generator>
	<item>
		<title>Empfehlung des Tages: Filter-Funktionen</title>
		<link>http://yoda.neun12.de/artikel-117</link>
		<comments>http://yoda.neun12.de/artikel-117#comments</comments>
		<pubDate>Sun, 19 May 2013 12:59:21 +0000</pubDate>
		<dc:creator><![CDATA[Ralf]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Sicherheit]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=117</guid>
		<description><![CDATA[Seit PHP5.2 sind die Filter-Funktionen fester Bestandteil von PHP geworden. Jedoch greifen immer noch sehr wenige Programmierer auf diese Filter-Funktionen zurück, was ein kleines bis großes Sicherheitsrisiko darstellt. Der Normalfall sieht immer noch so aus, dass einfach abgefragt wird ob in $_GET, $_POST oder $_REQUEST ein Schlüssel vorhanden ist und dann der entsprechende Wert verwendet [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Seit PHP5.2 sind die <a title="PHP: Filter-Funktionen - Manual" href="http://www.php.net/manual/de/ref.filter.php">Filter-Funktionen</a> fester Bestandteil von PHP geworden. Jedoch greifen immer noch sehr wenige Programmierer auf diese Filter-Funktionen zurück, was ein kleines bis großes Sicherheitsrisiko darstellt.</p>
<p>Der Normalfall sieht immer noch so aus, dass einfach abgefragt wird ob in <code>$_GET</code>, <code>$_POST</code> oder <code>$_REQUEST</code> ein Schlüssel vorhanden ist und dann der entsprechende Wert verwendet wird. Leider viel zu oft sieht man auch, dass erst gar nicht geprüft wird ob der Schlüssel vorhanden ist und einfach davon ausgegangen wird das dieser vorhanden ist und verwendet werden kann. Das ist nicht nur schlechter Stil, sondern eröffnet auch eine Sicherheitslücke. Denn die superglobalen Arrays <code>$_GET</code>, <code>$_POST</code> und <code>$_REQUEST</code> sind keine Einbahnstraße, man kann aus ihnen lesen und in sie hinein schreiben. Schauen wir uns das mal etwas näher an.</p>
<p><code>$_REQUEST</code> lassen wir in der in diesem Artikel mal außen vor da es noch nicht von den Filter-Funktionen unterstützt wird. Zudem sollte man auf <code>$_REQUEST</code> auch nur in Ausnahmefällen zugreifen. <code>$_REQUEST</code> Enthält die Daten von <code>$_GET</code> und <code>$_POST</code>. Die Verwendung von <code>$_REQUEST</code> deutet also darauf hin, dass man nicht so wirklich weiß was man tut und einfach auf gut Glück auf ein superglobales Array zugreift in der Hoffnung die gesuchten Daten seien schon irgendwie da.<br />
Es gibt einige wenige Fälle wo der Zugriff auf <code>$_REQUEST</code> sinnvoll sein kann, man sollte sich jedoch im klaren darüber sein das der Zugriff auf <code>$_REQUEST</code> eben nicht so sicher ist als wenn man <code>$_GET</code> und <code>$_POST</code> mit den Filter-Funktionen abfragt.</p>
<h3>$_GET und $_POST sind keine Einbahnstraße</h3>
<p>Das man auf die superglobalen Arrays <code>$_GET</code> und <code>$_POST</code> nicht nur lesend, sondern auch schreibend zugreifen kann, ist anscheinend nicht allen klar. Schauen wir uns dazu mal dieses Script an</p>
<pre class="brush:php">$_POST['nonce'] = 'badnonce';
echo 'Was the nonce send with a POST request?&lt;br&gt;';
echo 'With &lt;code&gt;isset()&lt;/code&gt;: ' . ( isset( $_POST['nonce'] ) ? 'yes' : 'no' ) . '&lt;br&gt;';
echo 'With &lt;code&gt;filter_has_var()&lt;/code&gt;' . ( filter_has_var( INPUT_POST, 'nonce' ) ? 'yes' : 'no' ) . '&lt;br&gt;';
echo 'Value of &lt;code&gt;nonce&lt;/code&gt; with &lt;code&gt;$_POST[\'nonce\']&lt;/code&gt;: ' . $_POST['nonce'] . '&lt;br&gt;';
echo 'Value of &lt;code&gt;nonce&lt;/code&gt; with &lt;code&gt;filter_input( INPUT_POST, \'nonce\' )&lt;/code&gt;:' . filter_input( INPUT_POST, 'nonce' ) . '&lt;br&gt;';

echo '&lt;hr&gt;';

$_GET['nonce'] = 'badnonce';
echo 'Was the nonce send with a GET request?&lt;br&gt;';
echo 'With &lt;code&gt;isset()&lt;/code&gt;: ' . ( isset( $_GET['nonce'] ) ? 'yes' : 'no' ) . '&lt;br&gt;';
echo 'With &lt;code&gt;filter_has_var()&lt;/code&gt;' . ( filter_has_var( INPUT_GET, 'nonce' ) ? 'yes' : 'no' ) . '&lt;br&gt;';
echo 'Value of &lt;code&gt;nonce&lt;/code&gt; with &lt;code&gt;$_GET[\'nonce\']&lt;/code&gt;: ' . $_GET['nonce'] . '&lt;br&gt;';
echo 'Value of &lt;code&gt;nonce&lt;/code&gt; with &lt;code&gt;filter_input( INPUT_GET, \'nonce\' )&lt;/code&gt;:' . filter_input( INPUT_GET, 'nonce' ) . '&lt;br&gt;';</pre>
<p>Die <code>nonces</code> sind in <a title="Glossary « WordPress Codex" href="http://codex.wordpress.org/Glossary#Nonce">WordPress ein Sicherheitsmechanismus</a> mit dem man prüfen kann ob eine Anfrage tatsächlich von dort kommt, von wo man sie erwartet. Verlassen wir uns darauf das der Schlüssel <code>nonce</code> vorhanden ist und verwenden diesen, gehen wir das Risiko ein das er an einer anderen Stelle einfach überschrieben wurde.</p>
<p>Das man die Werte der superglobalen Arrays einfach überschreiben kann, lässt sich recht einfach mit vielen WordPress Funktionen testen die Werte aus den superglobalen Arrays <code>$_GET</code>, <code>$_POST</code> und/oder <code>$_REQUEST</code> verwenden.</p>
<pre class="brush:php">add_action(
	'admin_init',
	function(){
		if (
			( isset( $_GET['action'] ) &amp;&amp; 'delete-comment' == $_GET['action'] )
			||
			( isset( $_GET['action'] ) &amp;&amp; 'trash' == $_GET['action'] )
		) {
			$_GET['action'] = $_POST['action'] = $_REQUEST['action'] = 'not-now';
		}
	}
);</pre>
<p>Einfach mal diesen Code-Schnipsel in die <code>functions.php</code> einfügen und dann im Backend die Kommentarübersicht aufrufen. Dort dann wahllos ein paar Kommentare löschen. Entweder über die Checkboxen und eines der Bulk-Menüs oder über den Link der erscheint wenn man mit der Maus auf einen Kommentar zeigt.<br />
Nutzt man die Checkboxen und das Bulk-Menü, passiert gar nichts. Beim Löschen über den Link verschwindet zwar der Kommentar und der Zähler hinter &#8220;Papierkorb&#8221; geht hoch, ein Klick auf &#8220;Alle Kommentare&#8221; genügt um die vermeintlich gelöschten Kommentare wieder anzuzeigen.</p>
<p>Es geht aber deutlich böser</p>
<pre class="brush:php">add_action(
	'admin_init',
	function(){
		if (
			( isset( $_GET['action'] ) &amp;&amp; 'delete-comment' == $_GET['action'] )
			||
			( isset( $_GET['action'] ) &amp;&amp; 'trash' == $_GET['action'] )
		) {
			$a = array_fill( 0, 5, 0 );
			array_walk( $a, function( &amp;$e ){ $e = rand( 1,999 ); } );
			$_GET['delete_comments'] = $_POST['delete_comments'] = $_REQUEST['delete_comments'] = $a;
			$_GET['c'] = $_POST['c'] = $_REQUEST['c'] = rand( 1, 999 );
		}
	}
);</pre>
<p>Dieser Code überschreibt nicht einfach die <code>action</code>, sondern ersetzt die ausgewählten Kommentare durch zufällige Werte. Egal was man auswählt, welche Kommentaren gelöscht werden ist reiner Zufall. Im besten Fall passiert nichts, da die zufällig ausgewählten IDs nicht existieren. Im schlimmsten Fall werden ganz andere Kommentare gelöscht als ausgewählt. Man könnte auch über eine SQL-Abfrage alle vorhandenen Kommentar-IDS abfragen und dann zufällig IDs auswählen, dass ist dann richtig böse aber ein anderes Thema.</p>
<p>Mit <code>filter_input()</code> wäre dies nicht möglich, da <code>filter_input()</code> nur die Werte berücksichtigt, die auch tatsächlich über einen Request abgeschickt wurden (siehe erstes Beispiel). Nun fragt man sich vielleicht warum WordPress etwas so dummes macht wenn es doch eine solch einfache Lösung für das Problem gibt.<br />
Nun die Antwort liegt in meinen ersten Satz dieses Artkels. Die Filter-Funktionen sind erst ab PHP5.2 verfügbar, WordPress wurde jedoch zu PHP4 Zeiten entwickelt und enthält auch noch unendlich viel PHP4-Code. Wer das ändern möchte, kann gerne mal eine Suche nach <code>$_GET</code>, <code>$_POST</code> und <code>$_REQUEST</code> über die WordPress Dateien laufen lassen und die entsprechenden Stellen anpassen. Die Suche nach <code>$_GET</code> liefert aktuell 594 Treffer in 104 Dateien. Soviel zu diesen Thema.</p>
<p>Ich hoffe es ist klar geworden warum es nicht ganz unerheblich ist seinen Code mindestens auf PHP5.2 Niveau zu bringen und warum man in seinen Themes und Plugins unbedingt auf die <a title="PHP: Filter-Funktionen - Manual" href="http://www.php.net/manual/de/ref.filter.php">Filter-Funktionen</a> setzen sollte anstatt direkt auf die superglobalen Arrays <code>$_GET</code>, <code>$_POST</code> und <code>$_REQUEST</code> zuzugreifen.</p>
<p>Zum Schluss noch etwas Mehrwert. Manchmal kann es vorkommen das Werte sowohl per GET als auch POST Request übergeben werden (meist im Zusammenhang mit Ajax Requests), in diesen Fall greift man gerne auf <code>$_REQUEST</code> zurück. Da die Filter-Funktionen von PHP <code>$_REQUEST</code> (noch) nicht unterstützen, müsste man jedes mal umständlich <code>$_GET</code> und <code>$_POST</code> abfragen ob der benötigte Schlüssel vorhanden ist. Das kann man sich mit einer kleinen Funktion vereinfachen und den Mangel von PHP gleich etwas ausbügeln.</p>
<pre class="brush:php">function read_superglobals( $vars ) {
	
	if ( is_string( $vars ) )
		$vars = (array) $vars;
	
	$return = array();
	
	foreach ( $vars as $variable_name ) {
		if ( ! filter_has_var( INPUT_POST, $variable_name ) ) {
			if ( ! filter_has_var( INPUT_GET, $variable_name ) ) {
				$return[$variable_name] = '';
			} else {
				$return[$variable_name] = filter_input( INPUT_GET, $variable_name );
			}
		} else {
			$return[$variable_name] = filter_input( INPUT_GET, $variable_name );
		}
	}

	return $return;
}</pre>
<p>Die Funktion erwartet als Parameter ein Array oder einen String mit den jeweiligen Schlüssel(n) den/die man abfragen möchte. Die Funktion prüft dann mit <code>filter_input()</code> ob in <code>$_GET</code> oder <code>$_POST</code> der Schlüssel vorhanden ist. Ist er vorhanden, kopiert sie den Wert mit den zugehörigen Schlüssel in ein Array und gibt anschließend das Array zurück. Die Funktion arbeitet in etwa so wie <code>wp_reset_var()</code>, jedoch mit den Unterschied das sie keine globalen Variablen erzeugt und ausschließlich die Schlüssel zurück gibt, die auch tatsächlich mittels eines GET oder POST Requests abgesendet wurden.<br />
Natürlich kann man die Funktion auch dann verwenden, wenn man genau weiß ob die Werte mittels GET oder POST Request gesendet wurden. Dann bekommt man ein Array zurück mit exakt den Schlüssel-Werte Paaren die man benötigt.</p>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-117/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Gimme-Gimme-Gimme</title>
		<link>http://yoda.neun12.de/artikel-102</link>
		<comments>http://yoda.neun12.de/artikel-102#comments</comments>
		<pubDate>Sat, 20 Apr 2013 19:27:53 +0000</pubDate>
		<dc:creator><![CDATA[Ralf]]></dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=102</guid>
		<description><![CDATA[ABBA suchte dereinst nach einen Mann für die Nachtschicht. PHP kann damit wenig anfangen, genauso wenig wie mit den falschen Typen, wobei mit &#8220;Typen&#8221; jetzt nicht der Mann gemeint ist. Oft schreibt man Funktionen oder Methoden und macht sich nur wenig Gedanken über den Rückgabewert im Fehlerfall, also dann, wenn die Funktion nicht die Aktion [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>ABBA suchte dereinst nach einen Mann für die Nachtschicht. PHP kann damit wenig anfangen, genauso wenig wie mit den falschen Typen, wobei mit &#8220;Typen&#8221; jetzt nicht der Mann gemeint ist.</p>
<p>Oft schreibt man Funktionen oder Methoden und macht sich nur wenig Gedanken über den Rückgabewert im Fehlerfall, also dann, wenn die Funktion nicht die Aktion durchführen konnte wofür sie geschrieben wurde. Ich selber habe es bisher auch so gehandhabt das ich im Fehlerfall einen boolschen Wert oder vergleichbares zurück gegeben habe. Das Ergebnis ist, ich muss bei jeden Funktionsaufruf prüfen ob auch der Variablen-Typ zurück kommt den ich erwarte. Erwarte ich z.B. ein Array, kommt im Fehlkerfall aber ein boolsches False zurück, muss ich das abfangen.</p>
<p>Warum? Weil es ansonsten unter Umständen Fehlermeldungen hagelt und das Script abbricht. Im Backend kann man es noch verschmerzen, ich nenne das immer den &#8220;Weisste bescheid&#8221; Zustand. Im Frontend ist es aber mehr als peinlich und sogar kontraproduktiv wenn der Seitenaufbau nach dem Blogheader mit einer Fehlermeldung abbricht.</p>
<p>Stellen wir uns mal vor wir schreiben ein Widget für die Sidebar. Im Code für das Widget sind folgende zwei Funktionen:</p>
<pre class="brush:php">/**
 * Create a ordered- or unordered list from values
 *
 * @param	string	$type	ol for ordered lists or ul for unordered list
 * @param	array	$values	Array with list items
 * @return	string			HTML list
 */
function get_list( $type = 'ol', $values = array() ) {

	$type = ( in_array( $type, array( 'ol', 'ul' ) ) ) ?
		$type : 'ol';

	foreach ( $values as &amp;$val )
		$val .= ' item';

	$format = "&lt;{$type}&gt;" . str_repeat( '&lt;li&gt;%s&lt;/li&gt;', sizeof( $values ) ) . "&lt;/{$type}&gt;";

	return vsprintf( $format, $values );

}

/**
 * Returns an array or boolean depending on parameter
 *
 * @param	boolean	$fail	Returns an array if set to true, else returns boolean false.
 * @return Ambigous &lt;boolean, multitype:string &gt;
 */
function get_list_values( $fail = false ) {

	return ( true == $fail ) ?
		false : array( 'A', 'B', 'C' );

}</pre>
<p>Die eine Funktion (<code>get_list_values()</code>) erzeugt ein Array mit Elementen, die andere Funktion (<code>get_list()</code>) erzeugt aus einem Array mit Werten eine HTML-Liste. Der Aufruf beider Funktionen könnte exemplarisch so aussehen:</p>
<pre class="brush:php">$vals = get_list_values();
$list = get_list( 'ol', $vals );

echo $list;</pre>
<p>Soweit funktioniert das ganze recht ordentlich. Nun provozieren wir jedoch mal einen Fehler und rufen die Funktion <code>get_list_values()</code> mit den Parameter <code>1</code> auf. Jetzt werden wir mit einen <code>Warning: Invalid argument supplied for foreach() in ...</code> begrüßt und das Script bricht an dieser Stelle ab.</p>
<p>Um solche Fehlermeldungen zu vermeiden, hätte ich vorher prüfen müssen ob <code>$vals</code> ein Array ist.</p>
<pre class="brush:php">$vals = get_list_values(1);

if ( is_array( $vals ) ) {
  $list = get_list( 'ol', $vals );
  echo $list;
} else {
  // do some error handling
}</pre>
<p>Das erscheint bisher alles recht logisch. Die frage ist nur, was soll man an dieser Stelle für ein Error-Handling machen? Einen Log-Eintrag? Eine eigene Fehlermeldung ausgeben? Nichts?<br />
Nichts scheint mir eigentlich die beste Lösung zu sein. Mit einer eigenen Fehlermeldung kann der Besucher nichts anfangen.Und ein Log-Eintrag hilft dem Besucher auch nicht weiter. Ein Log-Eintrag hilft dem Programmierer bzw. den Admin an dieser Stelle ebenso wenig, da es unklar ist warum die Funktion <code>get_list_values()</code> gescheitert ist. Das kann uns nur die Funktion selber sagen, daher wäre ein Log-Eintrag innerhalb der Funktion sinnvoller untergebracht.</p>
<pre class="brush:php">function get_list_values( $fail = false ) {

	if ( true == $fail ) {
		write_to_error_log( sprintf( 'Function %s was called with parameter $fail set to %s', __FUNCTION__, $fail ) );
		return false;
	}

	return array( 'A', 'B', 'C' );

}</pre>
<p>Dadurch sind wir schon mal einen kleinen Schritt weiter. Der Fehler wird da geloggt, wo er tatsächlich auftritt, nicht da wo er zu einen weiteren Fehler führt. Das eigentliche Problem besteht jedoch weiterhin. Denn die Funktion gibt ja noch einen boolschen Wert zurück. Wir müssen also weiterhin prüfen ob das Ergebnis des Funktionsaufrufes tatsächlich von den erwarteten Typs ist. Das ist hinderlich, denn dadurch ist folgendes Konstrukt nicht möglich:</p>
<pre class="brush:php">echo get_list( 'ol', get_list_values( 1 ) );</pre>
<p>Würde die Funktion nun einen Wert vom erwarteten Typ zurück geben, könnten wir obiges Konstrukt ohne weiteres verwenden. Im Fehlerfall erhalten wir dann anstatt einer Liste lediglich ein leeres Ergebnis. Also ändern wir die Funktion ein klein wenig:</p>
<pre class="brush:php">function get_list_values( $fail = false ) {

	if ( true == $fail ) {
		write_to_error_log( sprintf( 'Function %s was called with parameter $fail set to %s', __FUNCTION__, $fail ) );
		return array();
	}

	return array( 'A', 'B', 'C' );

}</pre>
<p>Das Logging des Fehlers bleibt, er geht also nicht verloren. Dafür haben wir im Frontend keine Fehlermeldung mehr und der Seitenaufbau bricht auch nicht mehr ab.</p>
<p>Dies können wir nun auf alle Funktionen übertragen. Wenn die Funktion im Erfolgsfall ein Array zurück gibt, sollte sie dies auch im Fehlerfall machen, dann halt ein leeres Array. Erwarten wir ein Objekt als Rückgabewert, so sollte im Fehlerfall ein leeres Objekt zurück kommen. Allerdings sollte man speziell bei Objekten die Eigenschaften vorbelegen und nicht einfach nur ein leeres Objekt zurück geben da oft direkt auf die Objekteigenschaften zugegriffen wird und man, anders als bei Arrays, nicht mit <code>empty()</code> prüfen kann ob das Objekt überhaupt irgendwelche Eigenschaften enthält. Eine Abfrage mit <code>empty()</code> liefert bei Objekten immer <code>false</code> zurück, da ein Objekt niemals &#8220;leer&#8221; ist.</p>
<pre class="brush:php">function get_some_object( $fail = false ) {

	$object = new stdClass();
	$object-&gt;foo = false;
	$object-&gt;bar = '';
	$object-&gt;baz = null;

	if ( true == $fail )
		return $object;

	$object-&gt;foo = true;
	$object-&gt;bar = 'FooBarBaz';
	$object-&gt;baz = $object;

	return $object;

}
$objects = array();
var_dump( $objects );

$objects[] = get_some_object();
$objects[] = get_some_object( true );
$objects[] = new stdClass();

array_walk( $objects, function( $object ) { var_dump( empty( $object ) ); } );

/*
Ausgabe:
array (size=0)
  empty

boolean false
boolean false
boolean false
*/</pre>
<p>Der Grund warum man sich damit beschäftigen sollte ist jedoch nicht nur eine saubere Ausgabe im Frontend, sondern auch das Debuggen. Im ersten Beispiel wurde der Fehler nämlich still und heimlich an einen ganz anderen Ort verlagert. Obwohl er in der Funktion <code>get_list_values()</code> aufgetreten ist, wird er erst in <code>get_list()</code> beim Aufruf der <code>foreach</code>-Schleife wirksam. In Beispielen ist es immer einfach den Fehler zu finden. Sie sind von Natur aus kurz und übersichtlich. In größeren und längeren Scripten ist es jedoch oft nicht so einfach heraus zu finden wann und wo eine Variable durch einen Funktionsaufruf einen Wert zugewiesen bekommen hat. Liegen zwischen der Wertzuweisung und der Verarbeitung des Wertes noch andere Zwischenschritte in der der fehlerhafte Wert nicht zu einen Fehler führt, wird die Suche noch umständlicher.<br />
Deshalb sollte man Fehlerfälle immer sofort dort behandeln, wo sie auftreten anstatt sie in einen Pseudozustand umzuwandeln und sie ggf. auch noch als Rückgabewert zurück zu geben.</p>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-102/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Klassen-Konstante von außerhalb der Klasse auslesen</title>
		<link>http://yoda.neun12.de/artikel-76</link>
		<comments>http://yoda.neun12.de/artikel-76#comments</comments>
		<pubDate>Sun, 08 Jul 2012 00:12:18 +0000</pubDate>
		<dc:creator><![CDATA[Ralf]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Quicktipp]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=76</guid>
		<description><![CDATA[Hin und wieder komme ich in die Verlegenheit außerhalb einer Klasse eine ihrer Konstante verwenden zu wollen oder zu müssen. Auf direkten Weg, also z.B. mit Foo:CONSTANT geht es nicht. Mit der folgenden Methode geht es jedoch wunderbar:]]></description>
				<content:encoded><![CDATA[<p>Hin und wieder komme ich in die Verlegenheit außerhalb einer Klasse eine ihrer Konstante verwenden zu wollen oder zu müssen. Auf direkten Weg, also z.B. mit <code>Foo:CONSTANT</code> geht es nicht. Mit der folgenden Methode geht es jedoch wunderbar: <div class="gistem"><div id="gist-3068674" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="cp">&lt;?php</span></div><div class='line' id='LC2'><span class="k">class</span> <span class="nc">Foo</span></div><div class='line' id='LC3'><span class="p">{</span></div><div class='line' id='LC4'>	<span class="k">const</span> <span class="no">BAR</span> <span class="o">=</span> <span class="s1">&#39;Hallo&#39;</span><span class="p">;</span></div><div class='line' id='LC5'>	<span class="k">const</span> <span class="no">BAZ</span> <span class="o">=</span> <span class="s1">&#39;Welt!&#39;</span><span class="p">;</span></div><div class='line' id='LC6'><br/></div><div class='line' id='LC7'>	<span class="sd">/**</span></div><div class='line' id='LC8'><span class="sd">	 * </span></div><div class='line' id='LC9'><span class="sd">	 * Returns the value of a class constant</span></div><div class='line' id='LC10'><span class="sd">	 * @param string $const Name of the constant</span></div><div class='line' id='LC11'><span class="sd">	 * @param string $class [optional] Name of the class (if not set, the constant will be searched in this class) </span></div><div class='line' id='LC12'><span class="sd">	 * @return mixed|false The value of the constant or false if it does not exists</span></div><div class='line' id='LC13'><span class="sd">	 */</span></div><div class='line' id='LC14'>	<span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">get_constant</span><span class="p">(</span> <span class="nv">$const</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="nv">$class_name</span> <span class="o">=</span> <span class="nx">__CLASS__</span> <span class="p">){</span></div><div class='line' id='LC15'><br/></div><div class='line' id='LC16'>		<span class="k">if</span><span class="p">(</span> <span class="k">empty</span><span class="p">(</span> <span class="nv">$const</span> <span class="p">)</span> <span class="o">||</span> <span class="o">!</span> <span class="nb">is_string</span><span class="p">(</span> <span class="nv">$const</span> <span class="p">)</span> <span class="o">||</span> <span class="o">!</span> <span class="nb">class_exists</span><span class="p">(</span> <span class="nv">$class_name</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC17'>			<span class="k">return</span> <span class="k">FALSE</span><span class="p">;</span></div><div class='line' id='LC18'><br/></div><div class='line' id='LC19'>		<span class="nv">$reflection</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">ReflectionClass</span><span class="p">(</span> <span class="nv">$class_name</span> <span class="p">);</span></div><div class='line' id='LC20'><br/></div><div class='line' id='LC21'>		<span class="k">return</span> <span class="nv">$reflection</span><span class="o">-&gt;</span><span class="na">getConstant</span><span class="p">(</span> <span class="nv">$const</span> <span class="p">);</span></div><div class='line' id='LC22'><br/></div><div class='line' id='LC23'>	<span class="p">}</span></div><div class='line' id='LC24'><br/></div><div class='line' id='LC25'><span class="p">}</span></div><div class='line' id='LC26'><br/></div><div class='line' id='LC27'><span class="k">class</span> <span class="nc">Bar</span></div><div class='line' id='LC28'><span class="p">{</span></div><div class='line' id='LC29'>	<span class="k">const</span> <span class="no">FOO</span> <span class="o">=</span> <span class="s1">&#39;Horst&#39;</span><span class="p">;</span></div><div class='line' id='LC30'><span class="p">}</span></div><div class='line' id='LC31'><br/></div><div class='line' id='LC32'><span class="nv">$consts</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span> <span class="s1">&#39;BAR&#39;</span><span class="p">,</span> <span class="s1">&#39;BAZ&#39;</span><span class="p">,</span> <span class="s1">&#39;FOO&#39;</span> <span class="p">);</span></div><div class='line' id='LC33'><span class="k">foreach</span><span class="p">(</span> <span class="nv">$consts</span> <span class="k">as</span> <span class="nv">$const</span> <span class="p">)</span></div><div class='line' id='LC34'>	<span class="nb">var_dump</span><span class="p">(</span> <span class="nx">Foo</span><span class="o">::</span><span class="na">get_constant</span><span class="p">(</span> <span class="nv">$const</span> <span class="p">)</span> <span class="p">);</span></div><div class='line' id='LC35'><br/></div><div class='line' id='LC36'><span class="nb">var_dump</span><span class="p">(</span> <span class="nx">Foo</span><span class="o">::</span><span class="na">get_constant</span><span class="p">(</span> <span class="s1">&#39;FOO&#39;</span><span class="p">,</span> <span class="s1">&#39;Bar&#39;</span> <span class="p">)</span> <span class="p">);</span></div><div class='line' id='LC37'><br/></div><div class='line' id='LC38'><span class="nb">var_dump</span><span class="p">(</span> <span class="nx">Foo</span><span class="o">::</span><span class="na">get_constant</span><span class="p">(</span> <span class="s1">&#39;TEST&#39;</span><span class="p">,</span> <span class="s1">&#39;Baz&#39;</span> <span class="p">)</span> <span class="p">);</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/3068674/117dd6890c9796b733f04a24e8c792098d63fdaa/get_constant.php" style="float:right;">view raw</a>
            <a href="https://gist.github.com/3068674#file_get_constant.php" style="float:right;margin-right:10px;color:#666">get_constant.php</a>
            <a href="https://gist.github.com/3068674">This Gist</a> is brought to you using <a href="http://en.bainternet.info/2011/simple-gist-embed"><small>Simple Gist Embed</small></a>.
          </div>
        </div>
</div>
</div><style type="text/css">@import "http://gist.github.com/stylesheets/gist/embed.css"; .gistem .highlight {background: inherit; !important;}</style></p>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-76/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Gummi-Thickbox</title>
		<link>http://yoda.neun12.de/artikel-73</link>
		<comments>http://yoda.neun12.de/artikel-73#comments</comments>
		<pubDate>Wed, 30 May 2012 14:32:40 +0000</pubDate>
		<dc:creator><![CDATA[Ralf]]></dc:creator>
				<category><![CDATA[Code-Snippets]]></category>
		<category><![CDATA[Quicktipp]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=73</guid>
		<description><![CDATA[Will man im Backend von WordPress die Thickbox verwenden, bekommt man ein Problem. Zumindest dann, wenn man mit der vorgegebenen Größe nicht einverstanden ist. Die wird nämlich von WordPress mittels eines Scriptes vorgegeben. Bindet man zusätzlich den Editor ein, wird es richtig haarig. Denn im media-upload.js steht dummerweise die Zeile $('a.thickbox').each( function() {...} Also alle [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Will man im Backend von WordPress die Thickbox verwenden, bekommt man ein Problem. Zumindest dann, wenn man mit der vorgegebenen Größe nicht einverstanden ist. Die wird nämlich von WordPress mittels eines Scriptes vorgegeben. Bindet man zusätzlich den Editor ein, wird es richtig haarig. Denn im media-upload.js steht dummerweise die Zeile <code>$('a.thickbox').each( function() {...}</code><br />
Also alle Links mit der Klasse <code>thickbox</code> werden manipuliert. Würde man die Klasse <code>thickbox</code> weg lassen, würde der Link keine Thickbox öffnen. Blöde Situation das ganze.</p>
<p>Ich suchte eine Möglichkeit wie ich die Thickbox in ihrer Größe ändern kann, darüber hinaus mir aber keine Gedanken mehr machen muss wie groß ich sie dimensionieren soll. Die Thickbox sollte sich in ihrer Größe immer schön am dargestellten Inhalt ausrichten. Nach etlichen rumprobieren und etwas suchen, kam ich dann auf folgende Lösung:<div class="gistem"><div id="gist-2837799" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="nx">jQuery</span><span class="p">(</span><span class="nb">document</span><span class="p">).</span><span class="nx">ready</span><span class="p">(</span></div><div class='line' id='LC2'>	<span class="kd">function</span><span class="p">(</span><span class="nx">$</span><span class="p">){</span></div><div class='line' id='LC3'><br/></div><div class='line' id='LC4'>		<span class="nx">resize_thickbox_iframe</span><span class="p">();</span></div><div class='line' id='LC5'><span class="cm">/*</span></div><div class='line' id='LC6'><span class="cm"> *</span></div><div class='line' id='LC7'><span class="cm"> * some other jQuery code</span></div><div class='line' id='LC8'><span class="cm"> *</span></div><div class='line' id='LC9'><span class="cm"> */</span></div><div class='line' id='LC10'><br/></div><div class='line' id='LC11'>		<span class="kd">function</span> <span class="nx">resize_thickbox_iframe</span><span class="p">(){</span></div><div class='line' id='LC12'><br/></div><div class='line' id='LC13'>			<span class="c1">//padding</span></div><div class='line' id='LC14'>			<span class="kd">var</span> <span class="nx">pad</span> <span class="o">=</span> <span class="mi">50</span><span class="p">;</span></div><div class='line' id='LC15'><br/></div><div class='line' id='LC16'>			<span class="c1">// give the body a height</span></div><div class='line' id='LC17'>			<span class="nx">$</span><span class="p">(</span> <span class="s1">&#39;body&#39;</span> <span class="p">).</span><span class="nx">css</span><span class="p">(</span> <span class="s1">&#39;height&#39;</span><span class="p">,</span> <span class="s1">&#39;auto&#39;</span> <span class="p">);</span></div><div class='line' id='LC18'><br/></div><div class='line' id='LC19'>			<span class="c1">// read the bodys height and add some padding</span></div><div class='line' id='LC20'>			<span class="kd">var</span> <span class="nx">mh</span> <span class="o">=</span> <span class="nb">parseInt</span><span class="p">(</span> <span class="nx">$</span><span class="p">(</span> <span class="s1">&#39;body&#39;</span> <span class="p">).</span><span class="nx">height</span><span class="p">()</span> <span class="p">)</span> <span class="o">+</span> <span class="nx">pad</span><span class="p">;</span></div><div class='line' id='LC21'><br/></div><div class='line' id='LC22'>			<span class="kd">var</span> <span class="nx">max_height</span> <span class="o">=</span> <span class="nx">mh</span> <span class="o">+</span> <span class="s1">&#39;px&#39;</span><span class="p">;</span></div><div class='line' id='LC23'><br/></div><div class='line' id='LC24'>			<span class="c1">// get the parent window dimensions</span></div><div class='line' id='LC25'>			<span class="kd">var</span> <span class="nx">parent</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span> <span class="nb">window</span><span class="p">.</span><span class="nx">parent</span><span class="p">.</span><span class="nb">document</span> <span class="p">);</span></div><div class='line' id='LC26'>			<span class="kd">var</span> <span class="nx">ph</span> <span class="o">=</span> <span class="nx">parent</span><span class="p">.</span><span class="nx">height</span><span class="p">();</span></div><div class='line' id='LC27'><br/></div><div class='line' id='LC28'>			<span class="c1">// get the ID of this iframe and the iframe itself</span></div><div class='line' id='LC29'>			<span class="nx">frame_id</span> <span class="o">=</span> <span class="nx">frameElement</span><span class="p">.</span><span class="nx">id</span><span class="p">;</span></div><div class='line' id='LC30'>			<span class="nx">frame</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span> <span class="s1">&#39;#&#39;</span><span class="o">+</span><span class="nx">frame_id</span><span class="p">,</span> <span class="nb">window</span><span class="p">.</span><span class="nx">parent</span><span class="p">.</span><span class="nb">document</span> <span class="p">);</span></div><div class='line' id='LC31'><br/></div><div class='line' id='LC32'>			<span class="c1">// get the id of the overlay-div and the overlay-div itself</span></div><div class='line' id='LC33'>			<span class="nx">div_id</span> <span class="o">=</span> <span class="nx">frame</span><span class="p">.</span><span class="nx">parent</span><span class="p">().</span><span class="nx">attr</span><span class="p">(</span> <span class="s1">&#39;id&#39;</span> <span class="p">);</span></div><div class='line' id='LC34'>			<span class="nx">div</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span> <span class="s1">&#39;#&#39;</span><span class="o">+</span><span class="nx">div_id</span><span class="p">,</span> <span class="nb">window</span><span class="p">.</span><span class="nx">parent</span><span class="p">.</span><span class="nb">document</span> <span class="p">);</span></div><div class='line' id='LC35'><br/></div><div class='line' id='LC36'>			<span class="c1">// first set the hight for the frame, than set the hight for the overlay-div</span></div><div class='line' id='LC37'>			<span class="nx">frame</span><span class="p">.</span><span class="nx">css</span><span class="p">(</span> <span class="s1">&#39;height&#39;</span><span class="p">,</span> <span class="nx">max_height</span> <span class="p">);</span></div><div class='line' id='LC38'>			<span class="nx">div</span><span class="p">.</span><span class="nx">css</span><span class="p">(</span> <span class="s1">&#39;height&#39;</span><span class="p">,</span> <span class="nx">max_height</span> <span class="p">);</span></div><div class='line' id='LC39'><br/></div><div class='line' id='LC40'>			<span class="c1">// calculate the new top position</span></div><div class='line' id='LC41'>			<span class="kd">var</span> <span class="nx">tb</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">round</span><span class="p">(</span> <span class="p">(</span> <span class="p">(</span> <span class="nx">ph</span> <span class="o">-</span> <span class="nx">mh</span> <span class="p">)</span> <span class="o">/</span> <span class="mi">2</span> <span class="p">)</span> <span class="o">-</span> <span class="nx">pad</span> <span class="p">)</span> <span class="o">+</span> <span class="s1">&#39;px&#39;</span><span class="p">;</span></div><div class='line' id='LC42'><br/></div><div class='line' id='LC43'>			<span class="c1">// set the new top position</span></div><div class='line' id='LC44'>			<span class="nx">frame</span><span class="p">.</span><span class="nx">css</span><span class="p">(</span> <span class="s1">&#39;top&#39;</span><span class="p">,</span> <span class="nx">tb</span> <span class="p">);</span></div><div class='line' id='LC45'>			<span class="nx">div</span><span class="p">.</span><span class="nx">css</span><span class="p">(</span> <span class="s1">&#39;top&#39;</span><span class="p">,</span> <span class="nx">tb</span> <span class="p">);</span></div><div class='line' id='LC46'><br/></div><div class='line' id='LC47'>		<span class="p">}</span></div><div class='line' id='LC48'><br/></div><div class='line' id='LC49'>	<span class="p">}</span></div><div class='line' id='LC50'><span class="p">);</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2837799/230e1f0bcb365096666c10b746e6b11188b00299/resize_thickbox.js" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2837799#file_resize_thickbox.js" style="float:right;margin-right:10px;color:#666">resize_thickbox.js</a>
            <a href="https://gist.github.com/2837799">This Gist</a> is brought to you using <a href="http://en.bainternet.info/2011/simple-gist-embed"><small>Simple Gist Embed</small></a>.
          </div>
        </div>
</div>
</div></p>
<p>Das Script setzt die Höhe des body-Tags im iFrame zuerst auf &#8216;auto&#8217; damit dieser eine Höhe bekommt (für den Fall das der body-Tag noch keine Höhe besitzt). Danach wird das iFrame aus dem Eltern-Dokument gefischt und seine Höhe angepasst. Da sich das iFrame allerdings innerhalb eines Overlay-Divs befindet, muss dieser ebenfalls aus dem DOM gefischt und angepasst werden. Zum Schluss werden Overlay-Div und iFrame neu ausgerichtet.</p>
<p>Das Script gehört <strong>in das</strong> iFrame hinein! Dementsprechend muss im iFrame auch noch jQuery geladen werden. Wer im iFrame auf jQuery verzichten kann, muss sihc die Funktion auf pures JavaScript umschreiben (ist auch nicht sooo schwer).</p>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-73/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Templating mit WordPress</title>
		<link>http://yoda.neun12.de/artikel-72</link>
		<comments>http://yoda.neun12.de/artikel-72#comments</comments>
		<pubDate>Sat, 26 May 2012 23:37:18 +0000</pubDate>
		<dc:creator><![CDATA[Ralf]]></dc:creator>
				<category><![CDATA[HowTo]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=72</guid>
		<description><![CDATA[Mit diesen Artikel möchte ich zum Teil ein über 6 Monate altes Versprechen einlösen. Zum anderen ist es der dritte Teil einer Reihe von Beiträgen die Schritt für Schritt zu einer einfachen Template-Engine führen. Im ersten Teil hatte ich einen Formatter vorgestellt mit dem ich auf vergleichsweise einfache und flexible Art aus Daten eine Ausgabe [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Mit diesen Artikel möchte ich zum Teil ein <a title="Bültge - Trenne Ausgabe und Logik" href="http://bueltge.de/trenne-logik-von-der-ausgabe-mittels-hooks-in-wordpress/1335/#comment-440817">über 6 Monate altes Versprechen</a> einlösen. Zum anderen ist es der dritte Teil einer Reihe von Beiträgen die Schritt für Schritt zu einer einfachen Template-Engine führen.</p>
<p>Im <a title="Strings bequem formatieren" href="http://yoda.neun12.de/artikel-63">ersten Teil hatte ich einen Formatter vorgestellt</a> mit dem ich auf vergleichsweise einfache und flexible Art aus Daten eine Ausgabe machen kann. Im <a title="Trenne Ausgabe und Logik" href="http://yoda.neun12.de/artikel-65">zweiten Teil</a> habe ich mittels der Formatter-Klasse und einer Templates-Klasse eine Mini-Template-Engine gebastelt. Die hat aber noch etliche Nachteile und diente lediglich der Darstellung des Prinzips das dahinter steckt.<br />
Diesmal möchte ich auf eine konkrete Implementierung in WordPress eingehen die in dieser Form immer wieder verwendet werden kann.<span id="more-72"></span></p>
<h3>Das Pferd von hinten aufgezäumt</h3>
<p>Es ist vielleicht etwas ungewöhnlich, ich will jedoch von hinten anfangen und beginne mit den eigentlichen Templates. Das ist in sofern sinnvoll, als das wir konkrete Templates haben und uns dann einen Weg überlegen können wie wir an diese heran kommen. Hier also erst einmal die Template-Klassen:<br />
<div class="gistem"><div id="gist-2794775" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="cp">&lt;?php</span></div><div class='line' id='LC2'><span class="sd">/**</span></div><div class='line' id='LC3'><span class="sd"> * </span></div><div class='line' id='LC4'><span class="sd"> * Abstract class Wp Simple Templates define one method to retrive the defined templates</span></div><div class='line' id='LC5'><span class="sd"> * @author Ralf Albert</span></div><div class='line' id='LC6'><span class="sd"> *</span></div><div class='line' id='LC7'><span class="sd"> */</span></div><div class='line' id='LC8'><span class="k">abstract</span> <span class="k">class</span> <span class="nc">WP_Simple_Templates</span></div><div class='line' id='LC9'><span class="p">{</span></div><div class='line' id='LC10'><br/></div><div class='line' id='LC11'>	<span class="sd">/**</span></div><div class='line' id='LC12'><span class="sd">	 * </span></div><div class='line' id='LC13'><span class="sd">	 * Returns the template if it was defined in the template class. If the requested template was not</span></div><div class='line' id='LC14'><span class="sd">	 * defined in the template-class, return a wp-error.</span></div><div class='line' id='LC15'><span class="sd">	 * @param string $type</span></div><div class='line' id='LC16'><span class="sd">	 * @return array|string|object Array with template-strings or a single template-string or wp-error on failure</span></div><div class='line' id='LC17'><span class="sd">	 */</span></div><div class='line' id='LC18'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">get_templates</span><span class="p">(</span> <span class="nv">$type</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span> <span class="p">){</span></div><div class='line' id='LC19'><br/></div><div class='line' id='LC20'>		<span class="k">if</span><span class="p">(</span> <span class="s1">&#39;&#39;</span> <span class="o">==</span> <span class="nv">$type</span> <span class="p">)</span></div><div class='line' id='LC21'>			<span class="k">return</span> <span class="k">NULL</span><span class="p">;</span></div><div class='line' id='LC22'><br/></div><div class='line' id='LC23'>		<span class="c1">// if the template-class have a method $type, return the template(s). else return a wp-error</span></div><div class='line' id='LC24'>		<span class="k">if</span><span class="p">(</span> <span class="nb">method_exists</span><span class="p">(</span> <span class="nv">$this</span><span class="p">,</span> <span class="nv">$type</span> <span class="o">.</span> <span class="s1">&#39;_template&#39;</span> <span class="p">)</span> <span class="p">){</span></div><div class='line' id='LC25'><br/></div><div class='line' id='LC26'>			<span class="nv">$method</span> <span class="o">=</span> <span class="nv">$type</span> <span class="o">.</span> <span class="s1">&#39;_template&#39;</span><span class="p">;</span></div><div class='line' id='LC27'>			<span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="nv">$method</span><span class="p">();</span></div><div class='line' id='LC28'><br/></div><div class='line' id='LC29'>		<span class="p">}</span> <span class="k">else</span> <span class="p">{</span></div><div class='line' id='LC30'><br/></div><div class='line' id='LC31'>			<span class="k">return</span> <span class="k">new</span> <span class="nx">WP_error</span><span class="p">(</span></div><div class='line' id='LC32'>				<span class="s1">&#39;template_error&#39;</span><span class="p">,</span></div><div class='line' id='LC33'>				<span class="nb">printf</span><span class="p">(</span></div><div class='line' id='LC34'>					<span class="s1">&#39;&lt;h4&gt;Template Error&lt;/h4&gt;Template &lt;strong&gt;%s&lt;/strong&gt; does not exists in &lt;strong&gt;%s&lt;/strong&gt;&#39;</span><span class="p">,</span></div><div class='line' id='LC35'>					<span class="nv">$type</span><span class="p">,</span></div><div class='line' id='LC36'>					<span class="nb">get_class</span><span class="p">(</span> <span class="nv">$this</span> <span class="p">)</span></div><div class='line' id='LC37'>				<span class="p">)</span></div><div class='line' id='LC38'>			<span class="p">);</span></div><div class='line' id='LC39'><br/></div><div class='line' id='LC40'>		<span class="p">}</span></div><div class='line' id='LC41'><br/></div><div class='line' id='LC42'>	<span class="p">}</span></div><div class='line' id='LC43'><br/></div><div class='line' id='LC44'>	<span class="sd">/**</span></div><div class='line' id='LC45'><span class="sd">	 * </span></div><div class='line' id='LC46'><span class="sd">	 * Return an array with all available templates from the template-class</span></div><div class='line' id='LC47'><span class="sd">	 */</span></div><div class='line' id='LC48'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">get_available_templates</span><span class="p">(){</span></div><div class='line' id='LC49'><br/></div><div class='line' id='LC50'>		<span class="c1">// get all methods from the abstract class (__CLASS__) and the extended class ($this)</span></div><div class='line' id='LC51'>		<span class="nv">$self_methods</span>		<span class="o">=</span> <span class="nb">get_class_methods</span><span class="p">(</span> <span class="nx">__CLASS__</span> <span class="p">);</span></div><div class='line' id='LC52'>		<span class="nv">$extended_methods</span>	<span class="o">=</span> <span class="nb">get_class_methods</span><span class="p">(</span> <span class="nv">$this</span> <span class="p">);</span></div><div class='line' id='LC53'><br/></div><div class='line' id='LC54'>		<span class="c1">// remove the &#39;_template&#39; extension and return the array with template-names</span></div><div class='line' id='LC55'>		<span class="nv">$templates</span> <span class="o">=</span> <span class="k">array</span><span class="p">();</span></div><div class='line' id='LC56'><br/></div><div class='line' id='LC57'>		<span class="k">foreach</span><span class="p">(</span> <span class="nb">array_diff</span><span class="p">(</span> <span class="nv">$extended_methods</span><span class="p">,</span> <span class="nv">$self_methods</span> <span class="p">)</span> <span class="k">as</span> <span class="nv">$template</span> <span class="p">)</span></div><div class='line' id='LC58'>			<span class="nb">array_push</span><span class="p">(</span> <span class="nv">$templates</span><span class="p">,</span> <span class="nb">str_replace</span><span class="p">(</span> <span class="s1">&#39;_template&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="nv">$template</span> <span class="p">)</span> <span class="p">);</span></div><div class='line' id='LC59'><br/></div><div class='line' id='LC60'>		<span class="k">return</span> <span class="nv">$templates</span><span class="p">;</span></div><div class='line' id='LC61'><br/></div><div class='line' id='LC62'>	<span class="p">}</span></div><div class='line' id='LC63'><br/></div><div class='line' id='LC64'><span class="p">}</span></div><div class='line' id='LC65'><br/></div><div class='line' id='LC66'><span class="sd">/**</span></div><div class='line' id='LC67'><span class="sd"> * </span></div><div class='line' id='LC68'><span class="sd"> * Concrete class WP Simple HTML Templates defines the templates</span></div><div class='line' id='LC69'><span class="sd"> * @author Ralf Albert</span></div><div class='line' id='LC70'><span class="sd"> *</span></div><div class='line' id='LC71'><span class="sd"> */</span></div><div class='line' id='LC72'><br/></div><div class='line' id='LC73'><span class="k">class</span> <span class="nc">WP_Simple_HTML_Templates</span> <span class="k">extends</span> <span class="nx">WP_Simple_Templates</span></div><div class='line' id='LC74'><span class="p">{</span></div><div class='line' id='LC75'>	<span class="sd">/**</span></div><div class='line' id='LC76'><span class="sd">	 * Returns an array with list templates</span></div><div class='line' id='LC77'><span class="sd">	 */</span></div><div class='line' id='LC78'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">list_template</span><span class="p">(){</span></div><div class='line' id='LC79'><br/></div><div class='line' id='LC80'>		<span class="k">return</span> <span class="k">array</span><span class="p">(</span></div><div class='line' id='LC81'>			<span class="s1">&#39;ol&#39;</span>	<span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span></div><div class='line' id='LC82'>						<span class="s1">&#39;outer&#39;</span>	<span class="o">=&gt;</span> <span class="s2">&quot;&lt;ol&gt;</span><span class="se">n</span><span class="s2">%inner%&lt;/ol&gt;</span><span class="se">n</span><span class="s2">&quot;</span><span class="p">,</span></div><div class='line' id='LC83'>						<span class="s1">&#39;inner&#39;</span>	<span class="o">=&gt;</span> <span class="s2">&quot;&lt;li&gt;%item%&lt;/li&gt;</span><span class="se">n</span><span class="s2">&quot;</span></div><div class='line' id='LC84'>			<span class="p">),</span></div><div class='line' id='LC85'><br/></div><div class='line' id='LC86'>			<span class="s1">&#39;ul&#39;</span>	<span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span></div><div class='line' id='LC87'>						<span class="s1">&#39;outer&#39;</span>	<span class="o">=&gt;</span> <span class="s2">&quot;&lt;ul&gt;</span><span class="se">n</span><span class="s2">%inner%&lt;/ul&gt;</span><span class="se">n</span><span class="s2">&quot;</span><span class="p">,</span></div><div class='line' id='LC88'>						<span class="s1">&#39;inner&#39;</span>	<span class="o">=&gt;</span> <span class="s2">&quot;&lt;li&gt;%item%&lt;/li&gt;</span><span class="se">n</span><span class="s2">&quot;</span></div><div class='line' id='LC89'>			<span class="p">),</span></div><div class='line' id='LC90'><br/></div><div class='line' id='LC91'>			<span class="s1">&#39;div&#39;</span>	<span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span></div><div class='line' id='LC92'>						<span class="s1">&#39;outer&#39;</span>	<span class="o">=&gt;</span> <span class="s2">&quot;&lt;div&gt;</span><span class="se">n</span><span class="s2">%inner%&lt;/div&gt;</span><span class="se">n</span><span class="s2">&quot;</span><span class="p">,</span></div><div class='line' id='LC93'>						<span class="s1">&#39;inner&#39;</span>	<span class="o">=&gt;</span> <span class="s2">&quot;&lt;p&gt;%item%&lt;/p&gt;</span><span class="se">n</span><span class="s2">&quot;</span></div><div class='line' id='LC94'>			<span class="p">),</span></div><div class='line' id='LC95'>		<span class="p">);</span></div><div class='line' id='LC96'><br/></div><div class='line' id='LC97'>	<span class="p">}</span></div><div class='line' id='LC98'><br/></div><div class='line' id='LC99'>	<span class="sd">/**</span></div><div class='line' id='LC100'><span class="sd">	 * Returns a headline template with h1-tags</span></div><div class='line' id='LC101'><span class="sd">	 */</span></div><div class='line' id='LC102'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">hone_template</span><span class="p">(){</span></div><div class='line' id='LC103'><br/></div><div class='line' id='LC104'>		<span class="k">return</span> <span class="s1">&#39;&lt;h1&gt;%headline%&lt;/h1&gt;&#39;</span><span class="p">;</span></div><div class='line' id='LC105'><br/></div><div class='line' id='LC106'>	<span class="p">}</span></div><div class='line' id='LC107'><br/></div><div class='line' id='LC108'>	<span class="sd">/**</span></div><div class='line' id='LC109'><span class="sd">	 * Returns a paragraph-template with p-tags</span></div><div class='line' id='LC110'><span class="sd">	 */</span></div><div class='line' id='LC111'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">paragraph_template</span><span class="p">(){</span></div><div class='line' id='LC112'><br/></div><div class='line' id='LC113'>		<span class="k">return</span> <span class="s1">&#39;&lt;p&gt;%text%&lt;/p&gt;&#39;</span><span class="p">;</span></div><div class='line' id='LC114'><br/></div><div class='line' id='LC115'>	<span class="p">}</span></div><div class='line' id='LC116'><br/></div><div class='line' id='LC117'><span class="p">}</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2794775/e52df76e6d825281e1cd79d4bbc4adb4a25d9469/file1.php" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2794775#file_file1.php" style="float:right;margin-right:10px;color:#666">file1.php</a>
            <a href="https://gist.github.com/2794775">This Gist</a> is brought to you using <a href="http://en.bainternet.info/2011/simple-gist-embed"><small>Simple Gist Embed</small></a>.
          </div>
        </div>
</div>
</div></p>
<p>Am Anfang sehen wir eine abstrakte Klasse <code>WP_Simple_Templates</code>. Diese Klasse hat lediglich zwei Methoden (<code>get_templates()</code> und <code>get_available_templates()</code>) und da sie als abstrakt definiert wurde, kann man von ihr keine Instanz (kein Objekt) erzeugen. Die zweite Klasse enthält lediglich Methoden die nichts anderes machen als Strings und Arrays zurück zu geben.<br />
Wir könnten uns jetzt die abstrakte Klasse sparen und direkt auf die Methoden der Template-Klasse zugreifen. Dazu muss man aber immer genau wissen welche Methoden in der Template-Klasse definiert wurden. Das ist irgendwie doof, besser wäre es doch wenn man die Klasse fragen kann und sie antwortet mit einer Liste der verfügbaren Templates. Genau diese Aufgabe übernimmt die Methode <code>get_available_templates()</code> in der abstrakten Klasse.<br />
Um an die einzelnen Templates heran zu kommen gibt es die Methode <code>get_templates()</code>. Sie liefert immer ein Array mit den angeforderten Template(s) zurück. Es muss uns also gar nicht mehr interessieren wie die Templates in der Template-Klasse benannt wurden oder wie die Template-Klasse diese erzeugt, mit <code>get_template( 'list' )</code> bekommen wir immer das Template für HTML-Listen geliefert.<br />
Da wir später noch verschiedene Template-Klassen verwenden wollen, habe ich die Logik der Template-Klasse (<code>get_template()</code> und <code>get_available_templates()</code>) in eine abstrakte Klasse ohne Template-Strings ausgelagert und erweitere die Template-Klassen um diese abstrakte Klasse. Einfaches Code-Recyling halt.</p>
<h3>Die Templates verarbeiten</h3>
<p>Nun nützt es uns recht wenig wenn wir an die Templates heran kommen. Im Grunde genommen wollen wir das auch gar nicht. Das einzige was wir machen wollen ist, Daten angeben und eine Ausgabe zurück bekommen. Wir benötigen also noch eine Klasse die unsere Daten in die Templates einfügt:<div class="gistem"><div id="gist-2795515" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="cp">&lt;?php</span></div><div class='line' id='LC2'><span class="sd">/**</span></div><div class='line' id='LC3'><span class="sd"> * </span></div><div class='line' id='LC4'><span class="sd"> * Abstract class WP Simple Templater creates a copy of the template-class and</span></div><div class='line' id='LC5'><span class="sd"> * provide the templates to the template-engine</span></div><div class='line' id='LC6'><span class="sd"> * @author Ralf Albert</span></div><div class='line' id='LC7'><span class="sd"> *</span></div><div class='line' id='LC8'><span class="sd"> */</span></div><div class='line' id='LC9'><span class="k">abstract</span> <span class="k">class</span> <span class="nc">WP_Simple_Templater</span> <span class="k">extends</span> <span class="nx">Formatter</span></div><div class='line' id='LC10'><span class="p">{</span></div><div class='line' id='LC11'>	<span class="sd">/**</span></div><div class='line' id='LC12'><span class="sd">	 * </span></div><div class='line' id='LC13'><span class="sd">	 * Instance of template-class</span></div><div class='line' id='LC14'><span class="sd">	 * @var object $templates_object</span></div><div class='line' id='LC15'><span class="sd">	 */</span></div><div class='line' id='LC16'>	<span class="k">protected</span> <span class="nv">$templates_object</span> <span class="o">=</span> <span class="k">NULL</span><span class="p">;</span></div><div class='line' id='LC17'><br/></div><div class='line' id='LC18'>	<span class="sd">/**</span></div><div class='line' id='LC19'><span class="sd">	 * </span></div><div class='line' id='LC20'><span class="sd">	 * Constructor</span></div><div class='line' id='LC21'><span class="sd">	 * Creates an instance of the template-class and setup the delimiters for Formatter</span></div><div class='line' id='LC22'><span class="sd">	 * @param WP_Simple_Templates $templates</span></div><div class='line' id='LC23'><span class="sd">	 */</span></div><div class='line' id='LC24'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">__construct</span><span class="p">(</span> <span class="nx">WP_Simple_Templates</span> <span class="nv">$templates</span> <span class="p">){</span></div><div class='line' id='LC25'><br/></div><div class='line' id='LC26'>		<span class="nv">$this</span><span class="o">-&gt;</span><span class="na">templates_object</span> <span class="o">=</span> <span class="o">&amp;</span><span class="nv">$templates</span><span class="p">;</span></div><div class='line' id='LC27'><br/></div><div class='line' id='LC28'>		<span class="nv">$this</span><span class="o">-&gt;</span><span class="na">set_delimiter</span><span class="p">(</span> <span class="s1">&#39;%&#39;</span><span class="p">,</span> <span class="s1">&#39;%&#39;</span> <span class="p">);</span></div><div class='line' id='LC29'><br/></div><div class='line' id='LC30'>	<span class="p">}</span></div><div class='line' id='LC31'><br/></div><div class='line' id='LC32'>	<span class="sd">/**</span></div><div class='line' id='LC33'><span class="sd">	 * </span></div><div class='line' id='LC34'><span class="sd">	 * Return a template by given type. Returns an wp-error on failure</span></div><div class='line' id='LC35'><span class="sd">	 * @param string $type</span></div><div class='line' id='LC36'><span class="sd">	 * @return string|bool Return a template-string if it was defined by the template-class. Or false if no such template was defined</span></div><div class='line' id='LC37'><span class="sd">	 */</span></div><div class='line' id='LC38'>	<span class="k">protected</span> <span class="k">function</span> <span class="nf">get_templates</span><span class="p">(</span> <span class="nv">$templatetype</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="nv">$type</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span> <span class="p">){</span></div><div class='line' id='LC39'><br/></div><div class='line' id='LC40'>		<span class="c1">// error message</span></div><div class='line' id='LC41'>		<span class="nv">$err_msg</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="p">;</span></div><div class='line' id='LC42'><br/></div><div class='line' id='LC43'>		<span class="c1">// if the sub-type is empty (e.g the template is a string not an array), use the template-type as sub-type</span></div><div class='line' id='LC44'>		<span class="k">if</span><span class="p">(</span> <span class="s1">&#39;&#39;</span> <span class="o">==</span> <span class="nv">$type</span> <span class="p">)</span></div><div class='line' id='LC45'>			<span class="nv">$type</span> <span class="o">=</span> <span class="nv">$templatetype</span><span class="p">;</span></div><div class='line' id='LC46'><br/></div><div class='line' id='LC47'>		<span class="c1">// first check if a template-type was set</span></div><div class='line' id='LC48'>		<span class="k">if</span><span class="p">(</span> <span class="s1">&#39;&#39;</span> <span class="o">==</span> <span class="nv">$templatetype</span> <span class="p">)</span></div><div class='line' id='LC49'>			<span class="nv">$err_msg</span> <span class="o">=</span> <span class="s1">&#39;Empty template-type&#39;</span><span class="p">;</span></div><div class='line' id='LC50'><br/></div><div class='line' id='LC51'>		<span class="c1">// check if a template-class was loaded</span></div><div class='line' id='LC52'>		<span class="k">elseif</span><span class="p">(</span> <span class="k">NULL</span> <span class="o">===</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">templates_object</span> <span class="p">)</span></div><div class='line' id='LC53'>			<span class="nv">$err_msg</span> <span class="o">=</span> <span class="s1">&#39;No templates defined in &lt;strong&gt;&#39;</span> <span class="o">.</span> <span class="nb">get_class</span><span class="p">(</span> <span class="nv">$this</span> <span class="p">)</span> <span class="o">.</span> <span class="s1">&#39;&lt;/strong&gt;&#39;</span><span class="p">;</span>					</div><div class='line' id='LC54'><br/></div><div class='line' id='LC55'>		<span class="c1">// we have a template-type and a template-class. get the template(s)</span></div><div class='line' id='LC56'>		<span class="k">else</span> <span class="p">{</span></div><div class='line' id='LC57'><br/></div><div class='line' id='LC58'>			 <span class="nv">$template</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">templates_object</span><span class="o">-&gt;</span><span class="na">get_templates</span><span class="p">(</span> <span class="nv">$templatetype</span> <span class="p">);</span></div><div class='line' id='LC59'><br/></div><div class='line' id='LC60'>			 <span class="c1">// get error-message thrown by template-class</span></div><div class='line' id='LC61'>			 <span class="k">if</span><span class="p">(</span> <span class="nx">is_wp_error</span><span class="p">(</span> <span class="nv">$template</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC62'>			 	<span class="nv">$err_msg</span> <span class="o">=</span> <span class="nv">$template</span><span class="o">-&gt;</span><span class="na">get_error_message</span><span class="p">();</span></div><div class='line' id='LC63'><br/></div><div class='line' id='LC64'>			 <span class="c1">// check the template.</span></div><div class='line' id='LC65'>			 <span class="c1">// convert a string into an array. else check if the requested type is in the template-array</span></div><div class='line' id='LC66'>			 <span class="k">else</span> <span class="p">{</span></div><div class='line' id='LC67'><br/></div><div class='line' id='LC68'>				 <span class="k">if</span><span class="p">(</span> <span class="o">!</span> <span class="nb">is_array</span><span class="p">(</span> <span class="nv">$template</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC69'>				 	<span class="nv">$template</span><span class="p">[</span><span class="nv">$type</span><span class="p">]</span> <span class="o">=</span> <span class="nv">$template</span><span class="p">;</span></div><div class='line' id='LC70'><br/></div><div class='line' id='LC71'>				 <span class="k">elseif</span><span class="p">(</span> <span class="o">!</span> <span class="nb">in_array</span><span class="p">(</span> <span class="nv">$type</span><span class="p">,</span> <span class="nb">array_keys</span><span class="p">(</span> <span class="nv">$template</span> <span class="p">)</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC72'>				 	<span class="nv">$err_msg</span> <span class="o">=</span> <span class="nv">$type</span> <span class="o">.</span> <span class="s1">&#39; is not defined.&#39;</span><span class="p">;</span></div><div class='line' id='LC73'><br/></div><div class='line' id='LC74'>			 <span class="p">}</span></div><div class='line' id='LC75'><br/></div><div class='line' id='LC76'>		<span class="p">}</span></div><div class='line' id='LC77'><br/></div><div class='line' id='LC78'>		<span class="c1">// if a error occurs, return an error-object</span></div><div class='line' id='LC79'>		<span class="k">if</span><span class="p">(</span> <span class="s1">&#39;&#39;</span> <span class="o">!=</span> <span class="nv">$err_msg</span> <span class="p">){</span></div><div class='line' id='LC80'><br/></div><div class='line' id='LC81'>			<span class="k">return</span> <span class="k">new</span> <span class="nx">WP_Error</span><span class="p">(</span></div><div class='line' id='LC82'>					<span class="s1">&#39;template_error&#39;</span><span class="p">,</span></div><div class='line' id='LC83'>					<span class="nb">sprintf</span><span class="p">(</span></div><div class='line' id='LC84'>						<span class="s1">&#39;&lt;div class=&quot;error&quot;&gt;&lt;h4&gt;Template Error&lt;/h4&gt;%s&lt;/div&gt;&#39;</span><span class="p">,</span></div><div class='line' id='LC85'>						<span class="nv">$err_msg</span></div><div class='line' id='LC86'>					<span class="p">)</span></div><div class='line' id='LC87'>				<span class="p">);</span></div><div class='line' id='LC88'><br/></div><div class='line' id='LC89'>		<span class="p">}</span></div><div class='line' id='LC90'><br/></div><div class='line' id='LC91'>		<span class="c1">// finally all checks are ok, return the template-array</span></div><div class='line' id='LC92'>		<span class="k">return</span> <span class="nv">$template</span><span class="p">;</span></div><div class='line' id='LC93'><br/></div><div class='line' id='LC94'>	<span class="p">}</span></div><div class='line' id='LC95'><br/></div><div class='line' id='LC96'><span class="p">}</span></div><div class='line' id='LC97'><br/></div><div class='line' id='LC98'><span class="sd">/**</span></div><div class='line' id='LC99'><span class="sd"> * </span></div><div class='line' id='LC100'><span class="sd"> * The concrete class WP Simple HTML insert the data in the templates</span></div><div class='line' id='LC101'><span class="sd"> * @author Ralf Albert</span></div><div class='line' id='LC102'><span class="sd"> *</span></div><div class='line' id='LC103'><span class="sd"> */</span></div><div class='line' id='LC104'><span class="k">class</span> <span class="nc">WP_Simple_HTML</span> <span class="k">extends</span> <span class="nx">WP_Simple_Templater</span></div><div class='line' id='LC105'><span class="p">{</span></div><div class='line' id='LC106'><br/></div><div class='line' id='LC107'>	<span class="sd">/**</span></div><div class='line' id='LC108'><span class="sd">	 * </span></div><div class='line' id='LC109'><span class="sd">	 * Constructor overrides the delimiters in parent class</span></div><div class='line' id='LC110'><span class="sd">	 * @param WP_Simple_Templates $templates</span></div><div class='line' id='LC111'><span class="sd">	 */</span></div><div class='line' id='LC112'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">__construct</span><span class="p">(</span> <span class="nx">WP_Simple_Templates</span> <span class="nv">$templates</span> <span class="p">){</span></div><div class='line' id='LC113'><br/></div><div class='line' id='LC114'>		<span class="k">parent</span><span class="o">::</span><span class="na">__construct</span><span class="p">(</span> <span class="nv">$templates</span> <span class="p">);</span></div><div class='line' id='LC115'><br/></div><div class='line' id='LC116'>		<span class="nv">$this</span><span class="o">-&gt;</span><span class="na">set_delimiter</span><span class="p">(</span> <span class="s1">&#39;{&#39;</span><span class="p">,</span> <span class="s1">&#39;}&#39;</span> <span class="p">);</span></div><div class='line' id='LC117'><br/></div><div class='line' id='LC118'>	<span class="p">}</span></div><div class='line' id='LC119'><br/></div><div class='line' id='LC120'>	<span class="sd">/**</span></div><div class='line' id='LC121'><span class="sd">	 * </span></div><div class='line' id='LC122'><span class="sd">	 * Create a html list (ul, ol or with div-tag)</span></div><div class='line' id='LC123'><span class="sd">	 * @param string $type The type of the list. ul, ol or div</span></div><div class='line' id='LC124'><span class="sd">	 * @param array $data Data to display inside the list</span></div><div class='line' id='LC125'><span class="sd">	 */</span></div><div class='line' id='LC126'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">get_list</span><span class="p">(</span> <span class="nv">$type</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="nv">$data</span> <span class="o">=</span> <span class="k">array</span><span class="p">()</span> <span class="p">){</span></div><div class='line' id='LC127'><br/></div><div class='line' id='LC128'>		<span class="c1">// get list templates</span></div><div class='line' id='LC129'>		<span class="nv">$templates</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">get_templates</span><span class="p">(</span> <span class="s1">&#39;list&#39;</span><span class="p">,</span> <span class="nv">$type</span> <span class="p">);</span></div><div class='line' id='LC130'><br/></div><div class='line' id='LC131'>		<span class="k">if</span><span class="p">(</span> <span class="nx">is_wp_error</span><span class="p">(</span> <span class="nv">$templates</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC132'>			<span class="k">return</span> <span class="nv">$templates</span><span class="o">-&gt;</span><span class="na">get_error_message</span><span class="p">();</span></div><div class='line' id='LC133'><br/></div><div class='line' id='LC134'>		<span class="c1">// create list</span></div><div class='line' id='LC135'>		<span class="nv">$inner</span>	<span class="o">=</span> <span class="k">new</span> <span class="k">stdClass</span><span class="p">();</span></div><div class='line' id='LC136'>		<span class="nv">$values</span>	<span class="o">=</span> <span class="k">new</span> <span class="k">stdClass</span><span class="p">();</span></div><div class='line' id='LC137'><br/></div><div class='line' id='LC138'>		<span class="k">foreach</span><span class="p">(</span> <span class="nv">$data</span> <span class="k">as</span> <span class="nv">$key</span> <span class="o">=&gt;</span> <span class="nv">$value</span> <span class="p">){</span></div><div class='line' id='LC139'><br/></div><div class='line' id='LC140'>			<span class="nv">$values</span><span class="o">-&gt;</span><span class="na">key</span>	<span class="o">=</span> <span class="nv">$key</span><span class="p">;</span></div><div class='line' id='LC141'>			<span class="nv">$values</span><span class="o">-&gt;</span><span class="na">item</span>	<span class="o">=</span> <span class="nv">$value</span><span class="p">;</span></div><div class='line' id='LC142'><br/></div><div class='line' id='LC143'>			<span class="nv">$inner</span><span class="o">-&gt;</span><span class="na">inner</span>	<span class="o">.=</span> <span class="nx">self</span><span class="o">::</span><span class="na">sprintf</span><span class="p">(</span> <span class="nv">$templates</span><span class="p">[</span><span class="nv">$type</span><span class="p">][</span><span class="s1">&#39;inner&#39;</span><span class="p">],</span> <span class="nv">$values</span> <span class="p">);</span></div><div class='line' id='LC144'><br/></div><div class='line' id='LC145'>		<span class="p">}</span></div><div class='line' id='LC146'><br/></div><div class='line' id='LC147'>		<span class="k">return</span> <span class="nx">self</span><span class="o">::</span><span class="na">sprintf</span><span class="p">(</span> <span class="nv">$templates</span><span class="p">[</span><span class="nv">$type</span><span class="p">][</span><span class="s1">&#39;outer&#39;</span><span class="p">],</span> <span class="nv">$inner</span> <span class="p">);</span></div><div class='line' id='LC148'><br/></div><div class='line' id='LC149'>	<span class="p">}</span></div><div class='line' id='LC150'><br/></div><div class='line' id='LC151'>	<span class="sd">/**</span></div><div class='line' id='LC152'><span class="sd">	 * </span></div><div class='line' id='LC153'><span class="sd">	 * Prints a html-list (ul, ol or with div-tag)</span></div><div class='line' id='LC154'><span class="sd">	 * @param string $type The type of the list. ul, ol or div</span></div><div class='line' id='LC155'><span class="sd">	 * @param array $data Data to display inside the list</span></div><div class='line' id='LC156'><span class="sd">	 */</span></div><div class='line' id='LC157'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">print_list</span><span class="p">(</span> <span class="nv">$type</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="nv">$data</span> <span class="o">=</span> <span class="k">array</span><span class="p">()</span> <span class="p">){</span></div><div class='line' id='LC158'><br/></div><div class='line' id='LC159'>		<span class="k">if</span><span class="p">(</span> <span class="o">!</span> <span class="nb">is_array</span><span class="p">(</span> <span class="nv">$data</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC160'>			<span class="nv">$data</span> <span class="o">=</span> <span class="p">(</span><span class="k">array</span><span class="p">)</span> <span class="nv">$data</span><span class="p">;</span></div><div class='line' id='LC161'><br/></div><div class='line' id='LC162'>		<span class="k">echo</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">get_list</span><span class="p">(</span> <span class="nv">$type</span><span class="p">,</span> <span class="nv">$data</span> <span class="p">);</span></div><div class='line' id='LC163'><br/></div><div class='line' id='LC164'>	<span class="p">}</span></div><div class='line' id='LC165'><br/></div><div class='line' id='LC166'>	<span class="sd">/**</span></div><div class='line' id='LC167'><span class="sd">	 * </span></div><div class='line' id='LC168'><span class="sd">	 * Create a H1-headline</span></div><div class='line' id='LC169'><span class="sd">	 * @param string $text</span></div><div class='line' id='LC170'><span class="sd">	 */</span></div><div class='line' id='LC171'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">get_headline</span><span class="p">(</span> <span class="nv">$text</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span> <span class="p">){</span></div><div class='line' id='LC172'><br/></div><div class='line' id='LC173'>		<span class="c1">// get headline template</span></div><div class='line' id='LC174'>		<span class="nv">$template</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">get_templates</span><span class="p">(</span> <span class="s1">&#39;hone&#39;</span> <span class="p">);</span></div><div class='line' id='LC175'><br/></div><div class='line' id='LC176'>		<span class="k">if</span><span class="p">(</span> <span class="nx">is_wp_error</span><span class="p">(</span> <span class="nv">$template</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC177'>			<span class="k">return</span> <span class="nv">$template</span><span class="o">-&gt;</span><span class="na">get_error_message</span><span class="p">();</span></div><div class='line' id='LC178'><br/></div><div class='line' id='LC179'>		<span class="nv">$data</span> <span class="o">=</span> <span class="k">new</span> <span class="k">stdClass</span><span class="p">();</span></div><div class='line' id='LC180'>		<span class="nv">$data</span><span class="o">-&gt;</span><span class="na">headline</span> <span class="o">=</span> <span class="nv">$text</span><span class="p">;</span></div><div class='line' id='LC181'><br/></div><div class='line' id='LC182'>		<span class="k">return</span> <span class="nx">self</span><span class="o">::</span><span class="na">sprintf</span><span class="p">(</span> <span class="nv">$template</span><span class="p">,</span> <span class="nv">$data</span> <span class="p">);</span></div><div class='line' id='LC183'><br/></div><div class='line' id='LC184'>	<span class="p">}</span></div><div class='line' id='LC185'><br/></div><div class='line' id='LC186'>	<span class="sd">/**</span></div><div class='line' id='LC187'><span class="sd">	 * </span></div><div class='line' id='LC188'><span class="sd">	 * Print a H1-headline</span></div><div class='line' id='LC189'><span class="sd">	 * @param string $text</span></div><div class='line' id='LC190'><span class="sd">	 */</span></div><div class='line' id='LC191'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">print_headline</span><span class="p">(</span> <span class="nv">$text</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span> <span class="p">){</span></div><div class='line' id='LC192'><br/></div><div class='line' id='LC193'>		<span class="k">echo</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">get_headline</span><span class="p">(</span> <span class="nv">$text</span> <span class="p">);</span></div><div class='line' id='LC194'><br/></div><div class='line' id='LC195'>	<span class="p">}</span></div><div class='line' id='LC196'><br/></div><div class='line' id='LC197'><span class="p">}</span></div><div class='line' id='LC198'><br/></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2795515/0738580053b964b267b3bc830921eb1782ef2445/file1.php" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2795515#file_file1.php" style="float:right;margin-right:10px;color:#666">file1.php</a>
            <a href="https://gist.github.com/2795515">This Gist</a> is brought to you using <a href="http://en.bainternet.info/2011/simple-gist-embed"><small>Simple Gist Embed</small></a>.
          </div>
        </div>
</div>
</div><br />
Dies wird die Klasse <code>WP_Simple_HTML</code> übernehmen. Auch hier könnte man es sich einfach machen und sich den Template-String direkt aus der Template-Klasse holen und dann mit den entsprechenden Daten versehen an die Formatter-Klasse übergeben. Allerdings müssten wir dann zuerst die Daten jedes mal für das entsprechende Template aufbereiten. Diese Logik lagern wir lieber in die Klasse <code>WP_Simple_HTML</code> aus um sie nicht ständig im Plugin- oder Theme-Code drin zu haben.<br />
Das Heranholen der Templates aus der Template-Klasse ist immer der gleiche Vorgang, deswegen können wir diesen ebenfalls in eine abstrakte Klasse (<code>WP_Simple_Templater</code>) auslagern die wir ebenfalls immer wieder verwenden können.<br />
Diese Klasse hat eine kleine Besonderheit. Im Konstruktor wird explizit ein Objekt angefordert das von der Klasse <code>WP_Simple_Templates</code> abstammt. Da wir <code>WP_Simple_Templates</code> abstrakt definiert haben, und somit davon nicht direkt eine Instanz erzeugen können, muss es also eine Instanz einer Klasse sein die <code>WP_Simple_Templates</code> erweitert. Damit gehen wir sicher das wir <code>WP_Simple_HTML</code> nicht z.B. eine Instanz von <code>wpdb</code> (der Datenbank-Klasse) oder ein Error-Object (<code>WP_Error()</code>) übergeben. Die abstrakte Klasse erfüllt somit neben dem Code-Recycling zusätzlich noch die Aufgabe sicherzustellen das wir eine Template-Klasse und nichts anderes übergeben.</p>
<p>Damit haben wir jetzt die Logik von der Ausgabe getrennt. Sowohl in unserer Template-Klasse (<code>WP_Simple_Templates</code> und <code>WP_Simple_HTML_Templates</code>), als auch in der Template-Engine (<code>WP_Simple_Templater</code> und <code>WP_Simple_HTML</code>). Wiederkehrende Logik haben wir in abstrakte Klassen ausgelagert die wir problemlos recyclen können.<br />
Die einzige Arbeit die uns zukünftig bleibt, ist eine Template-Klasse zu schreiben die die entsprechenden Templates enthält und für jedes Template die nötige Logik schreiben die die Daten aufbereitet und anschließend Daten und Template verbindet. Da wir die Logik für die Datenaufbereitung von den Templates getrennt haben, können wir munter die Templates umstellen ohne in unseren eigentlichen Plugin- oder Theme-Code eingreifen zu müssen.<br />
Die Logik für die Datenaufbereitung müssen wir auch nur dann anfassen, wenn wir die Templates um weitere Variablen ergänzen oder ändern. Logik und Ausgabe sind in allen Bereichen komplett voneinander getrennt.</p>
<h3>Lose koppeln anstatt fest verdrahten</h3>
<p>Wie würde man nun diese Template-Engine in seinem Plugin oder Theme verwenden? Wahrscheinlich würde man sie an entsprechender Stelle so im Code einfügen:</p>
<pre class="brush:php">$template = new WP_Simple_HTML_Templates();
$html = new WP_Simple_HTML( $template );
//some other code

$html-&gt;print_headline( 'Success!' );

$list = $html-&gt;get_list( 'ol', array( 'one' =&gt; 'eins', 'two' =&gt; 'zwei', 'three' =&gt; 'drei' ) );

// more code
echo $list;</pre>
<p>Das sieht im Grunde genommen schon mal schön aus. Relativ schön, um genau zu sein. Denn sowohl die Template-Klasse (<code>$template</code>) als auch die Template-Engine (<code>$html</code>) sind mehr oder minder fest verdrahtet. Würden wir für unsere Template-Engine eine andere Template-Klasse verwenden wollen, müssten wir dies im Code ändern. Gleiches gilt für den Fall das wir unsere Template-Klasse behalten aber auf eine andere Template-Engine zurückgreifen wollen.</p>
<p>Besser wäre es, wenn wir später noch andere Template-Engines und Template-Klassen angeben könnten. WordPress bietet uns hierzu die Möglichkeit mit <code>apply_filters()</code> und <code>add_filter()</code>. Schauen wir uns dazu folgende Demo an:<div class="gistem"><div id="gist-2795518" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="cp">&lt;?php</span></div><div class='line' id='LC2'><span class="k">class</span> <span class="nc">Template_Engine_Test</span></div><div class='line' id='LC3'><span class="p">{</span></div><div class='line' id='LC4'>	<span class="sd">/**</span></div><div class='line' id='LC5'><span class="sd">	 * </span></div><div class='line' id='LC6'><span class="sd">	 * Container for the different template-engines</span></div><div class='line' id='LC7'><span class="sd">	 * @var object $template_engine</span></div><div class='line' id='LC8'><span class="sd">	 */</span></div><div class='line' id='LC9'>	<span class="k">public</span> <span class="k">static</span> <span class="nv">$template_engine</span><span class="p">;</span></div><div class='line' id='LC10'><br/></div><div class='line' id='LC11'>	<span class="sd">/**</span></div><div class='line' id='LC12'><span class="sd">	 * </span></div><div class='line' id='LC13'><span class="sd">	 * Initial some vars</span></div><div class='line' id='LC14'><span class="sd">	 */</span></div><div class='line' id='LC15'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">__construct</span><span class="p">(){</span></div><div class='line' id='LC16'><br/></div><div class='line' id='LC17'>		<span class="c1">// initialize the template-engine to avoid strict errors</span></div><div class='line' id='LC18'>		<span class="nx">self</span><span class="o">::</span><span class="nv">$template_engine</span> <span class="o">=</span> <span class="k">new</span> <span class="k">stdClass</span><span class="p">();</span></div><div class='line' id='LC19'><br/></div><div class='line' id='LC20'>	<span class="p">}</span></div><div class='line' id='LC21'><br/></div><div class='line' id='LC22'>	<span class="sd">/**</span></div><div class='line' id='LC23'><span class="sd">	 * </span></div><div class='line' id='LC24'><span class="sd">	 * Caching for the template-classes</span></div><div class='line' id='LC25'><span class="sd">	 * Create a WP-Error if the template-engine could not be initialize</span></div><div class='line' id='LC26'><span class="sd">	 * @param string $template_engine The requested template-engine</span></div><div class='line' id='LC27'><span class="sd">	 * @return object The requested template-engine if available</span></div><div class='line' id='LC28'><span class="sd">	 */</span></div><div class='line' id='LC29'>	<span class="k">protected</span> <span class="k">function</span> <span class="nf">get_template_engine</span><span class="p">(</span> <span class="nv">$template_engine</span> <span class="p">){</span></div><div class='line' id='LC30'><br/></div><div class='line' id='LC31'>		<span class="nv">$template_engine</span> <span class="o">=</span> <span class="nx">strtolower</span><span class="p">(</span> <span class="nv">$template_engine</span> <span class="p">);</span></div><div class='line' id='LC32'><br/></div><div class='line' id='LC33'>		<span class="c1">// available template-engines and the template-classes</span></div><div class='line' id='LC34'>		<span class="nv">$available_template_engines</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span></div><div class='line' id='LC35'><br/></div><div class='line' id='LC36'>			<span class="s1">&#39;html&#39;</span>	<span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span> <span class="s1">&#39;WP_Simple_HTML&#39;</span><span class="p">,</span> <span class="s1">&#39;WP_Simple_HTML_Templates&#39;</span> <span class="p">)</span></div><div class='line' id='LC37'><br/></div><div class='line' id='LC38'>		<span class="p">);</span></div><div class='line' id='LC39'><br/></div><div class='line' id='LC40'>		<span class="nv">$available_template_engines</span> <span class="o">=</span> <span class="nx">apply_filters</span><span class="p">(</span> <span class="s1">&#39;available_template_engines&#39;</span><span class="p">,</span> <span class="nv">$available_template_engines</span> <span class="p">);</span></div><div class='line' id='LC41'><br/></div><div class='line' id='LC42'>		<span class="c1">// check if the requested template-engine is available. if not, try to create it</span></div><div class='line' id='LC43'>		<span class="k">if</span><span class="p">(</span> <span class="o">!</span> <span class="nb">isset</span><span class="p">(</span> <span class="nx">self</span><span class="o">::</span><span class="nv">$template_engine</span><span class="o">-&gt;</span><span class="nv">$template_engine</span> <span class="p">)</span> <span class="p">){</span></div><div class='line' id='LC44'><br/></div><div class='line' id='LC45'>			<span class="k">if</span><span class="p">(</span> <span class="o">!</span> <span class="nb">isset</span><span class="p">(</span> <span class="nv">$available_template_engines</span><span class="p">[</span><span class="nv">$template_engine</span><span class="p">]</span> <span class="p">)</span> <span class="p">){</span></div><div class='line' id='LC46'><br/></div><div class='line' id='LC47'>				<span class="k">return</span> <span class="k">new</span> <span class="nx">WP_Error</span><span class="p">(</span> <span class="s1">&#39;template_engine&#39;</span><span class="p">,</span> <span class="s1">&#39;Unknown template-engine &lt;strong&gt;&#39;</span> <span class="o">.</span> <span class="nv">$template_engine</span> <span class="o">.</span> <span class="s1">&#39;&lt;/strong&gt;&#39;</span> <span class="p">);</span></div><div class='line' id='LC48'><br/></div><div class='line' id='LC49'>			<span class="p">}</span> <span class="k">else</span> <span class="p">{</span></div><div class='line' id='LC50'><br/></div><div class='line' id='LC51'>				<span class="nv">$tmpl_ng</span>	<span class="o">=</span> <span class="o">&amp;</span><span class="nv">$available_template_engines</span><span class="p">[</span><span class="nv">$template_engine</span><span class="p">];</span></div><div class='line' id='LC52'>				<span class="nv">$class</span>		<span class="o">=</span> <span class="o">&amp;</span><span class="nv">$tmpl_ng</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span></div><div class='line' id='LC53'>				<span class="nv">$template</span>	<span class="o">=</span> <span class="o">&amp;</span><span class="nv">$tmpl_ng</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span></div><div class='line' id='LC54'><br/></div><div class='line' id='LC55'>				<span class="nx">self</span><span class="o">::</span><span class="nv">$template_engine</span><span class="o">-&gt;</span><span class="nv">$template_engine</span> <span class="o">=</span> <span class="k">new</span> <span class="nv">$class</span><span class="p">(</span> <span class="k">new</span> <span class="nv">$template</span> <span class="p">);</span></div><div class='line' id='LC56'><br/></div><div class='line' id='LC57'>			<span class="p">}</span></div><div class='line' id='LC58'><br/></div><div class='line' id='LC59'>		<span class="p">}</span></div><div class='line' id='LC60'><br/></div><div class='line' id='LC61'>		<span class="k">return</span> <span class="nx">self</span><span class="o">::</span><span class="nv">$template_engine</span><span class="o">-&gt;</span><span class="nv">$template_engine</span><span class="p">;</span></div><div class='line' id='LC62'><br/></div><div class='line' id='LC63'>	<span class="p">}</span> </div><div class='line' id='LC64'><br/></div><div class='line' id='LC65'>	<span class="sd">/**</span></div><div class='line' id='LC66'><span class="sd">	 * </span></div><div class='line' id='LC67'><span class="sd">	 * The output</span></div><div class='line' id='LC68'><span class="sd">	 */</span></div><div class='line' id='LC69'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">output</span><span class="p">(</span> <span class="nv">$stream</span> <span class="p">){</span></div><div class='line' id='LC70'><br/></div><div class='line' id='LC71'>		<span class="nv">$output</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">get_template_engine</span><span class="p">(</span> <span class="nv">$stream</span> <span class="p">);</span></div><div class='line' id='LC72'><br/></div><div class='line' id='LC73'>		<span class="k">if</span><span class="p">(</span> <span class="nx">is_wp_error</span><span class="p">(</span> <span class="nv">$output</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC74'>			<span class="k">die</span><span class="p">(</span> <span class="nv">$output</span><span class="o">-&gt;</span><span class="na">get_error_message</span><span class="p">()</span> <span class="p">);</span></div><div class='line' id='LC75'><br/></div><div class='line' id='LC76'>		<span class="nv">$output</span><span class="o">-&gt;</span><span class="na">print_headline</span><span class="p">(</span> <span class="nx">strtoupper</span><span class="p">(</span> <span class="nv">$stream</span> <span class="p">)</span> <span class="p">);</span></div><div class='line' id='LC77'><br/></div><div class='line' id='LC78'>		<span class="nv">$list</span> <span class="o">=</span> <span class="nv">$output</span><span class="o">-&gt;</span><span class="na">get_list</span><span class="p">(</span> <span class="s1">&#39;ol&#39;</span><span class="p">,</span> <span class="k">array</span><span class="p">(</span> <span class="s1">&#39;eins&#39;</span><span class="p">,</span> <span class="s1">&#39;zwei&#39;</span><span class="p">,</span> <span class="s1">&#39;drei&#39;</span> <span class="p">)</span> <span class="p">);</span></div><div class='line' id='LC79'>		<span class="k">echo</span> <span class="nv">$list</span><span class="p">;</span></div><div class='line' id='LC80'><br/></div><div class='line' id='LC81'>	<span class="p">}</span></div><div class='line' id='LC82'><br/></div><div class='line' id='LC83'>	<span class="sd">/**</span></div><div class='line' id='LC84'><span class="sd">	 * </span></div><div class='line' id='LC85'><span class="sd">	 * Setup html-mode</span></div><div class='line' id='LC86'><span class="sd">	 */</span></div><div class='line' id='LC87'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">set_html</span><span class="p">(){</span></div><div class='line' id='LC88'><br/></div><div class='line' id='LC89'>		<span class="c1">// html is build in</span></div><div class='line' id='LC90'><br/></div><div class='line' id='LC91'>	<span class="p">}</span></div><div class='line' id='LC92'><br/></div><div class='line' id='LC93'>	<span class="sd">/**</span></div><div class='line' id='LC94'><span class="sd">	 * </span></div><div class='line' id='LC95'><span class="sd">	 * Setup xml-mode</span></div><div class='line' id='LC96'><span class="sd">	 */</span></div><div class='line' id='LC97'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">set_xml</span><span class="p">(){</span></div><div class='line' id='LC98'><br/></div><div class='line' id='LC99'>		<span class="nx">add_filter</span><span class="p">(</span> <span class="s1">&#39;available_template_engines&#39;</span><span class="p">,</span> <span class="k">array</span><span class="p">(</span> <span class="o">&amp;</span><span class="nv">$this</span><span class="p">,</span> <span class="s1">&#39;add_xml&#39;</span> <span class="p">),</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span> <span class="p">);</span></div><div class='line' id='LC100'><br/></div><div class='line' id='LC101'>	<span class="p">}</span></div><div class='line' id='LC102'><br/></div><div class='line' id='LC103'>	<span class="sd">/**</span></div><div class='line' id='LC104'><span class="sd">	 * </span></div><div class='line' id='LC105'><span class="sd">	 * Add the XML-Template-Engine</span></div><div class='line' id='LC106'><span class="sd">	 */</span></div><div class='line' id='LC107'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">add_xml</span><span class="p">(){</span></div><div class='line' id='LC108'><br/></div><div class='line' id='LC109'>		<span class="k">return</span> <span class="k">array</span><span class="p">(</span></div><div class='line' id='LC110'><br/></div><div class='line' id='LC111'>			<span class="s1">&#39;xml&#39;</span>	<span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span> <span class="s1">&#39;WP_Simple_HTML&#39;</span><span class="p">,</span> <span class="s1">&#39;WP_Simple_HTML_Templates&#39;</span> <span class="p">),</span></div><div class='line' id='LC112'><br/></div><div class='line' id='LC113'>		<span class="p">);</span></div><div class='line' id='LC114'><br/></div><div class='line' id='LC115'>	<span class="p">}</span></div><div class='line' id='LC116'><br/></div><div class='line' id='LC117'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">set_feed</span><span class="p">(){</span></div><div class='line' id='LC118'><br/></div><div class='line' id='LC119'>		<span class="nx">add_filter</span><span class="p">(</span> <span class="s1">&#39;available_template_engines&#39;</span><span class="p">,</span> <span class="k">array</span><span class="p">(</span> <span class="o">&amp;</span><span class="nv">$this</span><span class="p">,</span> <span class="s1">&#39;add_feed&#39;</span> <span class="p">),</span> <span class="mi">1</span><span class="p">,</span><span class="mi">1</span> <span class="p">);</span></div><div class='line' id='LC120'><br/></div><div class='line' id='LC121'>	<span class="p">}</span></div><div class='line' id='LC122'><br/></div><div class='line' id='LC123'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">add_feed</span><span class="p">(</span> <span class="nv">$template_engines</span> <span class="p">){</span></div><div class='line' id='LC124'><br/></div><div class='line' id='LC125'>		<span class="nv">$feed_engines</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span></div><div class='line' id='LC126'><br/></div><div class='line' id='LC127'>			<span class="s1">&#39;rss&#39;</span>	<span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span> <span class="s1">&#39;WP_Simple_HTML&#39;</span><span class="p">,</span> <span class="s1">&#39;WP_Simple_HTML_Templates&#39;</span> <span class="p">),</span></div><div class='line' id='LC128'>			<span class="s1">&#39;atom&#39;</span>	<span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span> <span class="s1">&#39;WP_Simple_HTML&#39;</span><span class="p">,</span> <span class="s1">&#39;WP_Simple_HTML_Templates&#39;</span> <span class="p">),</span></div><div class='line' id='LC129'><br/></div><div class='line' id='LC130'>		<span class="p">);</span></div><div class='line' id='LC131'><br/></div><div class='line' id='LC132'>		<span class="k">return</span> <span class="nb">array_merge</span><span class="p">(</span> <span class="nv">$template_engines</span><span class="p">,</span> <span class="nv">$feed_engines</span> <span class="p">);</span></div><div class='line' id='LC133'><br/></div><div class='line' id='LC134'>	<span class="p">}</span></div><div class='line' id='LC135'><br/></div><div class='line' id='LC136'><span class="p">}</span></div><div class='line' id='LC137'><br/></div><div class='line' id='LC138'><span class="nv">$html</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Template_Engine_Test</span><span class="p">();</span></div><div class='line' id='LC139'><span class="nv">$html</span><span class="o">-&gt;</span><span class="na">set_html</span><span class="p">();</span></div><div class='line' id='LC140'><span class="nv">$html</span><span class="o">-&gt;</span><span class="na">output</span><span class="p">(</span> <span class="s1">&#39;html&#39;</span> <span class="p">);</span></div><div class='line' id='LC141'><br/></div><div class='line' id='LC142'><span class="nv">$xml</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Template_Engine_Test</span><span class="p">();</span></div><div class='line' id='LC143'><span class="nv">$xml</span><span class="o">-&gt;</span><span class="na">set_xml</span><span class="p">();</span></div><div class='line' id='LC144'><span class="nv">$xml</span><span class="o">-&gt;</span><span class="na">output</span><span class="p">(</span> <span class="s1">&#39;xml&#39;</span> <span class="p">);</span></div><div class='line' id='LC145'><br/></div><div class='line' id='LC146'><span class="nv">$feed</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Template_Engine_Test</span><span class="p">();</span></div><div class='line' id='LC147'><span class="nv">$feed</span><span class="o">-&gt;</span><span class="na">set_feed</span><span class="p">();</span></div><div class='line' id='LC148'><span class="nv">$feed</span><span class="o">-&gt;</span><span class="na">output</span><span class="p">(</span> <span class="s1">&#39;rss&#39;</span> <span class="p">);</span></div><div class='line' id='LC149'><span class="nv">$feed</span><span class="o">-&gt;</span><span class="na">output</span><span class="p">(</span> <span class="s1">&#39;atom&#39;</span> <span class="p">);</span></div><div class='line' id='LC150'><br/></div><div class='line' id='LC151'><span class="nv">$bar</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Template_Engine_Test</span><span class="p">();</span></div><div class='line' id='LC152'><span class="nv">$bar</span><span class="o">-&gt;</span><span class="na">output</span><span class="p">(</span> <span class="s1">&#39;wallawalla&#39;</span> <span class="p">);</span></div><div class='line' id='LC153'><br/></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2795518/1c6995596a1dbb7903d0f093a462a516d94f4b71/file1.php" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2795518#file_file1.php" style="float:right;margin-right:10px;color:#666">file1.php</a>
            <a href="https://gist.github.com/2795518">This Gist</a> is brought to you using <a href="http://en.bainternet.info/2011/simple-gist-embed"><small>Simple Gist Embed</small></a>.
          </div>
        </div>
</div>
</div></p>
<p>Die Methode <code>get_template_engine()</code> erfüllt zwei Aufgaben. Zum einen gibt sie die angeforderte Template-Engine inkl. der dazugehörigen Template-Klasse zurück (sofern beides vorhanden). Und zum anderen speichert sie die Template-Engine und Template-Klasse in einer statischen Variablen. Welche Kombination aus Template-Engine und Template-Klasse zurück gegeben wird, wird anhand eines Tags entschieden. So ist dem Tag &#8216;html&#8217; schon einmal die Kombination <code>WP_Simple_HTML</code>/<code>WP_Simple_HTML_Templates</code> zugeordnet.<br />
Weitere Kombinationen aus Template-Engine und Template-Klasse lassen sich über einen Filter hinzufügen. Bevor geprüft wird ob es den angeforderten Tag mit der entsprechenden Kombination gibt, wird ein Filter ausgeführt der es uns erlaubt weitere Kombinationen hinzuzufügen.<br />
Dies nutzen die Methoden <code>set_xml()</code> und <code>set_feed()</code> aus. Sie fügen einfach dem Array der verfügbaren Template-Engines/Klassen ihre eigenen hinzu und machen diese dadurch zugänglich. Danach kann in der Methode <code>output()</code> auf die neu hinzugefügten Template-Engines und Klassen zugegriffen werden. Hiermit sind wir quasi am Ziel unserer Wünsche angelangt. Denn die Methode <code>output()</code> muss sich gar nicht mehr darum kümmern wie die Daten ausgegeben werden, sie stellt diese einfach bereit und erwartet das die entsprechende Template-Engine entsprechende Methoden zur Ausgabe zur Verfügung stellt.</p>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-72/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Trenne Ausgabe und Logik</title>
		<link>http://yoda.neun12.de/artikel-65</link>
		<comments>http://yoda.neun12.de/artikel-65#comments</comments>
		<pubDate>Sun, 01 Apr 2012 02:23:02 +0000</pubDate>
		<dc:creator><![CDATA[Ralf]]></dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=65</guid>
		<description><![CDATA[Die Trennung von Ausgabe und Logik ist ein Grundsatz den man beherzigen sollte. Viele CMS bieten Template-Engines an um dies zu erreichen. WordPress bildet in diesen Punkt eine Ausnahme. Es bringt keine eigene Template-Engine mit, sondern setzt auf PHP als Template-Engine. Grundsätzlich keine schlechte Idee, denn PHP ist ursprünglich eine Template-Sprache. Aber die Möglichkeiten die [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Die Trennung von Ausgabe und Logik ist ein Grundsatz den man beherzigen sollte. Viele CMS bieten Template-Engines an um dies zu erreichen. WordPress bildet in diesen Punkt eine Ausnahme. Es bringt keine eigene Template-Engine mit, sondern setzt auf PHP als Template-Engine. Grundsätzlich keine schlechte Idee, denn PHP ist ursprünglich eine Template-Sprache. Aber die Möglichkeiten die PHP bietet führen grundsätzlich dazu das Logik und Ausgabe munter miteinander vermischt werden, was wiederum zu arg unleserlichen und vor allem unflexiblen Code führt.<br />
In diesen Artikel geht es nicht ausschließlich um WordPress. Das hier gezeigte lässt sich aber sehr leicht auf WordPress anpassen und viele WordPress-Themes haben es bitter nötig sich hinter der Fassade auch mal etwas aufzuhübschen.</p>
<p>Ich hatte in meinem letzten Artikel bereits kurz angesprochen das es eine gute Idee ist Logik und Ausgabe voneinander zu trennen. Eins der besten Argumente für die Trennung von Logik und Ausgabe ist wohl das, dass man einmal geschriebenen Code erneut verwenden kann, man spart sich so viel Arbeit. Aber auch die Übersichtlichkeit steigt, was z.B. die Fehlersuche vereinfacht. Und nicht zu Letzt ist es leichter im Team zu arbeiten. So kann sich einer um die Logik kümmern während der andere sich ausschließlich um das Design (Ausgabe) kümmert.</p>
<p>Das hier im Artikel beschriebene dürfte für PHP-Profis nichts neues sein. Für den einen oder anderen meiner Leser (sofern vorhanden <img src="http://yoda.neun12.de/wp-includes/images/smilies/icon_wink.gif" alt=";)" class="wp-smiley" />  ) kann es aber durchaus interessant sein. Fangen wir also mal ganz locker an.</p>
<h3>Ran an den Speck</h3>
<p>Ziel soll es sein das in der einen Datei ein Template (Vorlage) steht, während in einer anderen Datei dieses Template mit Daten gefüllt wird. Will man die Trennung noch weiter voran treiben, so legt man weitere Dateien an die sich z.B. um die Beschaffung der Daten kümmern oder um die Ausgabe der Daten (HTML, RSS, Druck, usw.).<br />
Wir wollen uns aber mal darauf beschränken ein einfaches  Template mit einem ebenso einfachem Array zu füllen. Bei dem Template soll es sich um eine Liste handeln. In WordPress zum Beispiel ist fast alles eine Liste. Ob nun die Artikel auf der Startseite, die Blogroll, eine Aufzählung der letzten Kommentare, Menüs, usw. Eigentlich besteht WordPress zu gefühlten 90% aus Listen. Listen dürften als Beispiel also ganz brauchbar sein.<br />
Schauen wir uns mal kurz die Anatomie einer Liste in HTML an. Sie besteht im Prinzip aus zwei Teilen. Den äußeren Teil der die Liste definiert und den inneren Teil der die eigentliche Liste darstellt. In <a title="W3Schools" href="http://www.w3schools.com/html/html_lists.asp">HTML gibt es drei native Listentypen</a>: &lt;ol&gt; (Ordered List), &lt;ul&gt; (Unordered List) und &lt;dl&gt; (Defenition List). Da die &lt;dl&gt;-Liste etwas komplexer ist nehmen wir uns mal die &lt;ol&gt;- und &lt;ul&gt;-Listen vor. Als &#8220;Ersatz&#8221; für die &lt;dl&gt;-Liste möchte ich eine einfache &lt;div&gt;-Liste dazu nehmen. Die &lt;div&gt;-Liste besteht aus einem äußeren Div-Container und &lt;p&gt;-Tags für die Listenelemente.</p>
<p>Nachdem nun klar ist um welche Listen es geht, brauchen wir noch ein paar Daten für die Liste. Die meisten Daten werden uns als Array oder Objekt zur Verfügung gestellt. Wir können ja mal annehmen wir hätten gerade eine Datenbankabfrage gemacht und wollten nun das Ergebnis als Liste darstellen. Der Einfachheit halber begnügen wir uns mit einem eindimensionalen Array das lediglich die Zahlwörter von Eins bis Drei enthält.</p>
<h3>Aus Daten wird eine Liste</h3>
<p>Das Problem ein Array als Liste darzustellen ist recht einfach zu lösen. Äußeren Teil ausgeben, das Array durchlaufen und den inneren Teil erstellen, inneren Teil in den Äußern Teil einbetten und fertig ist die Liste.<br />
<div class="gistem"><div id="gist-2138338" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="cp">&lt;?php</span></div><div class='line' id='LC2'><span class="k">require_once</span> <span class="s1">&#39;class-formatter.php&#39;</span><span class="p">;</span></div><div class='line' id='LC3'><br/></div><div class='line' id='LC4'><span class="k">class</span> <span class="nc">Lister</span> <span class="k">extends</span> <span class="nx">Formatter</span></div><div class='line' id='LC5'><span class="p">{</span>	</div><div class='line' id='LC6'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">get_list</span><span class="p">(</span> <span class="nv">$data</span> <span class="o">=</span> <span class="k">array</span><span class="p">()</span> <span class="p">){</span></div><div class='line' id='LC7'><br/></div><div class='line' id='LC8'>		<span class="nv">$inner</span>	<span class="o">=</span> <span class="k">new</span> <span class="k">stdClass</span><span class="p">();</span></div><div class='line' id='LC9'>		<span class="nv">$values</span>	<span class="o">=</span> <span class="k">new</span> <span class="k">stdClass</span><span class="p">();</span></div><div class='line' id='LC10'><br/></div><div class='line' id='LC11'>		<span class="k">foreach</span><span class="p">(</span> <span class="nv">$data</span> <span class="k">as</span> <span class="nv">$key</span> <span class="o">=&gt;</span> <span class="nv">$value</span> <span class="p">){</span></div><div class='line' id='LC12'><br/></div><div class='line' id='LC13'>			<span class="nv">$values</span><span class="o">-&gt;</span><span class="na">key</span>	<span class="o">=</span> <span class="nv">$key</span><span class="p">;</span></div><div class='line' id='LC14'>			<span class="nv">$values</span><span class="o">-&gt;</span><span class="na">item</span> 	<span class="o">=</span> <span class="nv">$value</span><span class="p">;</span></div><div class='line' id='LC15'><br/></div><div class='line' id='LC16'>			<span class="nv">$inner</span><span class="o">-&gt;</span><span class="na">inner</span> <span class="o">.=</span> <span class="nx">self</span><span class="o">::</span><span class="na">sprintf</span><span class="p">(</span> <span class="s1">&#39;&lt;li&gt;%item%&#39;</span><span class="p">,</span> <span class="nv">$values</span> <span class="p">);</span></div><div class='line' id='LC17'>		<span class="p">}</span></div><div class='line' id='LC18'><br/></div><div class='line' id='LC19'>		<span class="k">return</span> <span class="nx">self</span><span class="o">::</span><span class="na">sprintf</span><span class="p">(</span> <span class="s1">&#39;&lt;ol&gt;%inner%&lt;/ol&gt;&#39;</span><span class="p">,</span> <span class="nv">$inner</span> <span class="p">);</span></div><div class='line' id='LC20'><br/></div><div class='line' id='LC21'>	<span class="p">}</span></div><div class='line' id='LC22'><br/></div><div class='line' id='LC23'><span class="p">}</span></div><div class='line' id='LC24'><br/></div><div class='line' id='LC25'><span class="nv">$data</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span> <span class="s1">&#39;Eins&#39;</span><span class="p">,</span> <span class="s1">&#39;Zwei&#39;</span><span class="p">,</span> <span class="s1">&#39;Drei&#39;</span> <span class="p">);</span></div><div class='line' id='LC26'><br/></div><div class='line' id='LC27'><span class="nv">$list</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Lister</span><span class="p">();</span></div><div class='line' id='LC28'><span class="k">echo</span> <span class="nv">$list</span><span class="o">-&gt;</span><span class="na">get_list</span><span class="p">(</span> <span class="nv">$data</span> <span class="p">);</span></div><div class='line' id='LC29'><br/></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2138338/9fea73567c4999306d4ea4cc949fec8a2d223e8a/file1.php" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2138338#file_file1.php" style="float:right;margin-right:10px;color:#666">file1.php</a>
            <a href="https://gist.github.com/2138338">This Gist</a> is brought to you using <a href="http://en.bainternet.info/2011/simple-gist-embed"><small>Simple Gist Embed</small></a>.
          </div>
        </div>
</div>
</div><br />
Um es gleich ordentlich zu machen verwende ich eine Klasse. Diese Klasse erweitert den <a title="Strings bequem formatieren" href="http://yoda.neun12.de/artikel-63">Formatter den ich bereits vorgestellt habe</a> und erbt dadurch die Methoden <code>printf()</code> und <code>sprintf()</code>. Zu der Verarbeitung der Key-Value-Paare in der Foreach-Schleife komme ich später noch.</p>
<p>Wenn wir jetzt aber anstatt der Ordered List eine Unordered List erstellen wollen, schreiben wir uns eine neue Klasse!? Das wäre ja nicht Sinn der Aktion, wir wollen ja eine flexible Lösung haben.<br />
Es fehlt die Möglichkeit einen Listen-Typ auszuwählen. Was dafür geändert werden muss, sind die Template-Strings mit dem HTML-Code. Die einfachste Methode um die Templates für verschiedene Listen-Typen zu speichern ist ein Array. Wir benötigen also ein Array das zu jeden Listen-Typ (ol, ul und div) zwei Template-Strings speichert (den inneren Teil und den äußeren Teil).<br />
<div class="gistem"><div id="gist-2138508" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="cp">&lt;?php</span></div><div class='line' id='LC2'><span class="k">require_once</span> <span class="s1">&#39;class-formatter.php&#39;</span><span class="p">;</span></div><div class='line' id='LC3'><br/></div><div class='line' id='LC4'><span class="k">class</span> <span class="nc">Lister</span> <span class="k">extends</span> <span class="nx">Formatter</span></div><div class='line' id='LC5'><span class="p">{</span>	</div><div class='line' id='LC6'>	<span class="k">public</span> <span class="nv">$templates</span> <span class="o">=</span> <span class="k">array</span><span class="p">();</span></div><div class='line' id='LC7'><br/></div><div class='line' id='LC8'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">__construct</span><span class="p">(){</span></div><div class='line' id='LC9'><br/></div><div class='line' id='LC10'>		<span class="nv">$this</span><span class="o">-&gt;</span><span class="na">templates</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">get_templates</span><span class="p">();</span></div><div class='line' id='LC11'><br/></div><div class='line' id='LC12'>	<span class="p">}</span></div><div class='line' id='LC13'><br/></div><div class='line' id='LC14'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">get_templates</span><span class="p">(){</span></div><div class='line' id='LC15'><br/></div><div class='line' id='LC16'>		<span class="nv">$this</span><span class="o">-&gt;</span><span class="na">templates</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span></div><div class='line' id='LC17'>			<span class="s1">&#39;ol&#39;</span>	<span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span></div><div class='line' id='LC18'>						<span class="s1">&#39;outer&#39;</span>	<span class="o">=&gt;</span> <span class="s2">&quot;&lt;ol&gt;</span><span class="se">n</span><span class="s2">%inner%&lt;/ol&gt;</span><span class="se">n</span><span class="s2">&quot;</span><span class="p">,</span></div><div class='line' id='LC19'>						<span class="s1">&#39;inner&#39;</span>	<span class="o">=&gt;</span> <span class="s2">&quot;&lt;li&gt;%item%&lt;/li&gt;</span><span class="se">n</span><span class="s2">&quot;</span></div><div class='line' id='LC20'>			<span class="p">),</span></div><div class='line' id='LC21'><br/></div><div class='line' id='LC22'>			<span class="s1">&#39;ul&#39;</span>	<span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span></div><div class='line' id='LC23'>						<span class="s1">&#39;outer&#39;</span>	<span class="o">=&gt;</span> <span class="s2">&quot;&lt;ul&gt;</span><span class="se">n</span><span class="s2">%inner%&lt;/ul&gt;</span><span class="se">n</span><span class="s2">&quot;</span><span class="p">,</span></div><div class='line' id='LC24'>						<span class="s1">&#39;inner&#39;</span>	<span class="o">=&gt;</span> <span class="s2">&quot;&lt;li&gt;%item%&lt;/li&gt;</span><span class="se">n</span><span class="s2">&quot;</span></div><div class='line' id='LC25'>			<span class="p">),</span></div><div class='line' id='LC26'><br/></div><div class='line' id='LC27'>			<span class="s1">&#39;div&#39;</span>	<span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span></div><div class='line' id='LC28'>						<span class="s1">&#39;outer&#39;</span>	<span class="o">=&gt;</span> <span class="s2">&quot;&lt;div&gt;</span><span class="se">n</span><span class="s2">%inner%&lt;/div&gt;</span><span class="se">n</span><span class="s2">&quot;</span><span class="p">,</span></div><div class='line' id='LC29'>						<span class="s1">&#39;inner&#39;</span>	<span class="o">=&gt;</span> <span class="s2">&quot;&lt;p&gt;%item%&lt;/p&gt;</span><span class="se">n</span><span class="s2">&quot;</span></div><div class='line' id='LC30'>			<span class="p">),</span></div><div class='line' id='LC31'>		<span class="p">);</span></div><div class='line' id='LC32'><br/></div><div class='line' id='LC33'>	<span class="p">}</span></div><div class='line' id='LC34'><br/></div><div class='line' id='LC35'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">get_list</span><span class="p">(</span> <span class="nv">$type</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="nv">$data</span> <span class="o">=</span> <span class="k">array</span><span class="p">()</span> <span class="p">){</span></div><div class='line' id='LC36'><br/></div><div class='line' id='LC37'>		<span class="c1">// get templates if not already set</span></div><div class='line' id='LC38'>		<span class="k">if</span><span class="p">(</span> <span class="k">empty</span><span class="p">(</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">templates</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC39'>			<span class="nv">$this</span><span class="o">-&gt;</span><span class="na">get_templates</span><span class="p">();</span></div><div class='line' id='LC40'><br/></div><div class='line' id='LC41'>		<span class="c1">// check if the requested list-typ is defined</span></div><div class='line' id='LC42'>		<span class="k">if</span><span class="p">(</span> <span class="o">!</span> <span class="nb">in_array</span><span class="p">(</span> <span class="nv">$type</span><span class="p">,</span> <span class="nb">array_keys</span><span class="p">(</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">templates</span> <span class="p">)</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC43'>			<span class="k">return</span> <span class="k">FALSE</span><span class="p">;</span></div><div class='line' id='LC44'><br/></div><div class='line' id='LC45'>		<span class="c1">// create list</span></div><div class='line' id='LC46'>		<span class="nv">$inner</span>	<span class="o">=</span> <span class="k">new</span> <span class="k">stdClass</span><span class="p">();</span></div><div class='line' id='LC47'>		<span class="nv">$values</span>	<span class="o">=</span> <span class="k">new</span> <span class="k">stdClass</span><span class="p">();</span></div><div class='line' id='LC48'><br/></div><div class='line' id='LC49'>		<span class="k">foreach</span><span class="p">(</span> <span class="nv">$data</span> <span class="k">as</span> <span class="nv">$key</span> <span class="o">=&gt;</span> <span class="nv">$value</span> <span class="p">){</span></div><div class='line' id='LC50'><br/></div><div class='line' id='LC51'>			<span class="nv">$values</span><span class="o">-&gt;</span><span class="na">key</span>	<span class="o">=</span> <span class="nv">$key</span><span class="p">;</span></div><div class='line' id='LC52'>			<span class="nv">$values</span><span class="o">-&gt;</span><span class="na">item</span> 	<span class="o">=</span> <span class="nv">$value</span><span class="p">;</span></div><div class='line' id='LC53'><br/></div><div class='line' id='LC54'>			<span class="nv">$inner</span><span class="o">-&gt;</span><span class="na">inner</span> <span class="o">.=</span> <span class="nx">self</span><span class="o">::</span><span class="na">sprintf</span><span class="p">(</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">templates</span><span class="p">[</span><span class="nv">$type</span><span class="p">][</span><span class="s1">&#39;inner&#39;</span><span class="p">],</span> <span class="nv">$values</span> <span class="p">);</span></div><div class='line' id='LC55'>		<span class="p">}</span></div><div class='line' id='LC56'><br/></div><div class='line' id='LC57'>		<span class="k">return</span> <span class="nx">self</span><span class="o">::</span><span class="na">sprintf</span><span class="p">(</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">templates</span><span class="p">[</span><span class="nv">$type</span><span class="p">][</span><span class="s1">&#39;outer&#39;</span><span class="p">],</span> <span class="nv">$inner</span> <span class="p">);</span></div><div class='line' id='LC58'><br/></div><div class='line' id='LC59'>	<span class="p">}</span></div><div class='line' id='LC60'><br/></div><div class='line' id='LC61'><span class="p">}</span></div><div class='line' id='LC62'><br/></div><div class='line' id='LC63'><span class="nv">$data</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span> <span class="s1">&#39;Eins&#39;</span><span class="p">,</span> <span class="s1">&#39;Zwei&#39;</span><span class="p">,</span> <span class="s1">&#39;Drei&#39;</span> <span class="p">);</span></div><div class='line' id='LC64'><br/></div><div class='line' id='LC65'><span class="nv">$list</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Lister</span><span class="p">();</span></div><div class='line' id='LC66'><span class="k">echo</span> <span class="nv">$list</span><span class="o">-&gt;</span><span class="na">get_list</span><span class="p">(</span> <span class="s1">&#39;ol&#39;</span><span class="p">,</span> <span class="nv">$data</span> <span class="p">);</span></div><div class='line' id='LC67'><span class="k">echo</span> <span class="nv">$list</span><span class="o">-&gt;</span><span class="na">get_list</span><span class="p">(</span> <span class="s1">&#39;ul&#39;</span><span class="p">,</span> <span class="nv">$data</span> <span class="p">);</span></div><div class='line' id='LC68'><span class="k">echo</span> <span class="nv">$list</span><span class="o">-&gt;</span><span class="na">get_list</span><span class="p">(</span> <span class="s1">&#39;div&#39;</span><span class="p">,</span> <span class="nv">$data</span> <span class="p">);</span></div><div class='line' id='LC69'><br/></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2138508/5ae8550b2206eb6d8880e8b31d88e6be8a712351/file1.php" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2138508#file_file1.php" style="float:right;margin-right:10px;color:#666">file1.php</a>
            <a href="https://gist.github.com/2138508">This Gist</a> is brought to you using <a href="http://en.bainternet.info/2011/simple-gist-embed"><small>Simple Gist Embed</small></a>.
          </div>
        </div>
</div>
</div></p>
<p>Wunderbar. Jetzt können wir ganz einfach durch Angabe eines Listen-Types und eines Arrays eine Liste erzeugen. Das spart uns schon mal viel Arbeit, denn anstatt für jede Liste eine eigene Foreach-Schleife zu schreiben, benutzen wir einfach die Instanz unserer Klasse.<br />
Und wenn wir jetzt der Liste noch eine CSS-Klasse mitgeben wollen, dann schreiben wir uns eine andere Klasse die das kann!? Vielleicht erweitern wir einfach unsere Klasse dahingehend das sie nicht so starr ist.</p>
<h3>Noch mehr Flexibilität</h3>
<p>Die fest eingebauten Templates sind zu starr für unsere Zwecke, irgendwie müssen die raus aus der Klasse. Zu Anfang habe ich ja schon geschrieben das die Templates in die eine Datei, die Klasse die aus den Templates fertiges HTML macht in eine andere Datei soll. Das die Klasse oben einen Konstruktor hat, hat seinen Sinn. Denn das ist unser nächster Ansatzpunkt.<br />
Wir schieben einfach die Methode get_templates() in eine Template-Klasse und übergeben der Lister-Klasse ein Objekt das aus der Template-Klasse erzeugt wurde. Damit können wir innerhalb der Lister-Klasse auf die Templates zugreifen. Alles klar soweit? Nicht? Einfach das Beispiel anschauen.<div class="gistem"><div id="gist-2145820" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="cp">&lt;?php</span></div><div class='line' id='LC2'><span class="k">require_once</span> <span class="s1">&#39;class-formatter.php&#39;</span><span class="p">;</span></div><div class='line' id='LC3'><span class="k">require_once</span> <span class="s1">&#39;class-templates.php&#39;</span><span class="p">;</span></div><div class='line' id='LC4'><br/></div><div class='line' id='LC5'><span class="k">interface</span> <span class="nx">Templates</span></div><div class='line' id='LC6'><span class="p">{</span></div><div class='line' id='LC7'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">get_templates</span><span class="p">();</span></div><div class='line' id='LC8'><span class="p">}</span></div><div class='line' id='LC9'><br/></div><div class='line' id='LC10'><span class="k">class</span> <span class="nc">Lister</span> <span class="k">extends</span> <span class="nx">Formatter</span></div><div class='line' id='LC11'><span class="p">{</span>	</div><div class='line' id='LC12'>	<span class="k">public</span> <span class="nv">$templates_object</span> <span class="o">=</span> <span class="k">NULL</span><span class="p">;</span></div><div class='line' id='LC13'><br/></div><div class='line' id='LC14'>	<span class="k">public</span> <span class="nv">$templates</span> <span class="o">=</span> <span class="k">array</span><span class="p">();</span></div><div class='line' id='LC15'><br/></div><div class='line' id='LC16'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">__construct</span><span class="p">(</span> <span class="nx">Templates</span> <span class="nv">$templates</span> <span class="p">){</span></div><div class='line' id='LC17'><br/></div><div class='line' id='LC18'>		<span class="nv">$this</span><span class="o">-&gt;</span><span class="na">templates_object</span> <span class="o">=</span> <span class="o">&amp;</span><span class="nv">$templates</span><span class="p">;</span></div><div class='line' id='LC19'><br/></div><div class='line' id='LC20'>		<span class="nv">$this</span><span class="o">-&gt;</span><span class="na">get_templates</span><span class="p">();</span></div><div class='line' id='LC21'><br/></div><div class='line' id='LC22'>	<span class="p">}</span></div><div class='line' id='LC23'>	<span class="k">protected</span> <span class="k">function</span> <span class="nf">get_templates</span><span class="p">(){</span></div><div class='line' id='LC24'><br/></div><div class='line' id='LC25'>		<span class="k">if</span><span class="p">(</span> <span class="k">NULL</span> <span class="o">===</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">templates_object</span> <span class="p">)</span></div><div class='line' id='LC26'>			<span class="k">throw</span> <span class="k">new</span> <span class="nx">Exception</span><span class="p">(</span> <span class="s1">&#39;No templates defined&#39;</span> <span class="p">);</span></div><div class='line' id='LC27'><br/></div><div class='line' id='LC28'>		<span class="nv">$this</span><span class="o">-&gt;</span><span class="na">templates</span> <span class="o">=</span> <span class="o">&amp;</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">templates_object</span><span class="o">-&gt;</span><span class="na">get_templates</span><span class="p">();</span></div><div class='line' id='LC29'><br/></div><div class='line' id='LC30'>	<span class="p">}</span></div><div class='line' id='LC31'><br/></div><div class='line' id='LC32'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">get_list</span><span class="p">(</span> <span class="nv">$type</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="nv">$data</span> <span class="o">=</span> <span class="k">array</span><span class="p">()</span> <span class="p">){</span></div><div class='line' id='LC33'><br/></div><div class='line' id='LC34'>		<span class="c1">// get templates if not already set</span></div><div class='line' id='LC35'>		<span class="k">if</span><span class="p">(</span> <span class="k">empty</span><span class="p">(</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">templates</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC36'>			<span class="nv">$this</span><span class="o">-&gt;</span><span class="na">get_templates</span><span class="p">();</span></div><div class='line' id='LC37'><br/></div><div class='line' id='LC38'>		<span class="c1">// check if the requested list-typ is defined</span></div><div class='line' id='LC39'>		<span class="k">if</span><span class="p">(</span> <span class="o">!</span> <span class="nb">in_array</span><span class="p">(</span> <span class="nv">$type</span><span class="p">,</span> <span class="nb">array_keys</span><span class="p">(</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">templates</span> <span class="p">)</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC40'>			<span class="k">return</span> <span class="k">FALSE</span><span class="p">;</span></div><div class='line' id='LC41'><br/></div><div class='line' id='LC42'>		<span class="c1">// create list</span></div><div class='line' id='LC43'>		<span class="nv">$inner</span>	<span class="o">=</span> <span class="k">new</span> <span class="k">stdClass</span><span class="p">();</span></div><div class='line' id='LC44'>		<span class="nv">$values</span>	<span class="o">=</span> <span class="k">new</span> <span class="k">stdClass</span><span class="p">();</span></div><div class='line' id='LC45'><br/></div><div class='line' id='LC46'>		<span class="k">foreach</span><span class="p">(</span> <span class="nv">$data</span> <span class="k">as</span> <span class="nv">$key</span> <span class="o">=&gt;</span> <span class="nv">$value</span> <span class="p">){</span></div><div class='line' id='LC47'><br/></div><div class='line' id='LC48'>			<span class="nv">$values</span><span class="o">-&gt;</span><span class="na">key</span>	<span class="o">=</span> <span class="nv">$key</span><span class="p">;</span></div><div class='line' id='LC49'>			<span class="nv">$values</span><span class="o">-&gt;</span><span class="na">item</span> 	<span class="o">=</span> <span class="nv">$value</span><span class="p">;</span></div><div class='line' id='LC50'><br/></div><div class='line' id='LC51'>			<span class="nv">$inner</span><span class="o">-&gt;</span><span class="na">inner</span> <span class="o">.=</span> <span class="nx">self</span><span class="o">::</span><span class="na">sprintf</span><span class="p">(</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">templates</span><span class="p">[</span><span class="nv">$type</span><span class="p">][</span><span class="s1">&#39;inner&#39;</span><span class="p">],</span> <span class="nv">$values</span> <span class="p">);</span></div><div class='line' id='LC52'>		<span class="p">}</span></div><div class='line' id='LC53'><br/></div><div class='line' id='LC54'>		<span class="k">return</span> <span class="nx">self</span><span class="o">::</span><span class="na">sprintf</span><span class="p">(</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">templates</span><span class="p">[</span><span class="nv">$type</span><span class="p">][</span><span class="s1">&#39;outer&#39;</span><span class="p">],</span> <span class="nv">$inner</span> <span class="p">);</span></div><div class='line' id='LC55'><br/></div><div class='line' id='LC56'>	<span class="p">}</span></div><div class='line' id='LC57'><br/></div><div class='line' id='LC58'><span class="p">}</span></div><div class='line' id='LC59'><br/></div><div class='line' id='LC60'><span class="nv">$data</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span> <span class="s1">&#39;Eins&#39;</span><span class="p">,</span> <span class="s1">&#39;Zwei&#39;</span><span class="p">,</span> <span class="s1">&#39;Drei&#39;</span> <span class="p">);</span></div><div class='line' id='LC61'><br/></div><div class='line' id='LC62'><span class="nv">$list</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Lister</span><span class="p">(</span> <span class="k">new</span> <span class="nx">Simple_List_Templates</span> <span class="p">);</span></div><div class='line' id='LC63'><br/></div><div class='line' id='LC64'><span class="k">echo</span> <span class="nv">$list</span><span class="o">-&gt;</span><span class="na">get_list</span><span class="p">(</span> <span class="s1">&#39;ol&#39;</span><span class="p">,</span> <span class="nv">$data</span> <span class="p">);</span></div><div class='line' id='LC65'><span class="k">echo</span> <span class="nv">$list</span><span class="o">-&gt;</span><span class="na">get_list</span><span class="p">(</span> <span class="s1">&#39;ul&#39;</span><span class="p">,</span> <span class="nv">$data</span> <span class="p">);</span></div><div class='line' id='LC66'><span class="k">echo</span> <span class="nv">$list</span><span class="o">-&gt;</span><span class="na">get_list</span><span class="p">(</span> <span class="s1">&#39;div&#39;</span><span class="p">,</span> <span class="nv">$data</span> <span class="p">);</span></div><div class='line' id='LC67'><br/></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2145820/f588978c79e07218ae48d3ac244f42c56ace671f/class-lister.php" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2145820#file_class_lister.php" style="float:right;margin-right:10px;color:#666">class-lister.php</a>
            <a href="https://gist.github.com/2145820">This Gist</a> is brought to you using <a href="http://en.bainternet.info/2011/simple-gist-embed"><small>Simple Gist Embed</small></a>.
          </div>
        </div>

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="cp">&lt;?php</span></div><div class='line' id='LC2'><span class="k">class</span> <span class="nc">Simple_List_Templates</span> <span class="k">implements</span> <span class="nx">Templates</span></div><div class='line' id='LC3'><span class="p">{</span></div><div class='line' id='LC4'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">get_templates</span><span class="p">(){</span></div><div class='line' id='LC5'><br/></div><div class='line' id='LC6'>		<span class="k">return</span> <span class="k">array</span><span class="p">(</span></div><div class='line' id='LC7'>			<span class="s1">&#39;ol&#39;</span>	<span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span></div><div class='line' id='LC8'>						<span class="s1">&#39;outer&#39;</span>	<span class="o">=&gt;</span> <span class="s2">&quot;&lt;ol&gt;</span><span class="se">n</span><span class="s2">%inner%&lt;/ol&gt;</span><span class="se">n</span><span class="s2">&quot;</span><span class="p">,</span></div><div class='line' id='LC9'>						<span class="s1">&#39;inner&#39;</span>	<span class="o">=&gt;</span> <span class="s2">&quot;&lt;li&gt;%item%&lt;/li&gt;</span><span class="se">n</span><span class="s2">&quot;</span></div><div class='line' id='LC10'>			<span class="p">),</span></div><div class='line' id='LC11'><br/></div><div class='line' id='LC12'>			<span class="s1">&#39;ul&#39;</span>	<span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span></div><div class='line' id='LC13'>						<span class="s1">&#39;outer&#39;</span>	<span class="o">=&gt;</span> <span class="s2">&quot;&lt;ul&gt;</span><span class="se">n</span><span class="s2">%inner%&lt;/ul&gt;</span><span class="se">n</span><span class="s2">&quot;</span><span class="p">,</span></div><div class='line' id='LC14'>						<span class="s1">&#39;inner&#39;</span>	<span class="o">=&gt;</span> <span class="s2">&quot;&lt;li&gt;%item%&lt;/li&gt;</span><span class="se">n</span><span class="s2">&quot;</span></div><div class='line' id='LC15'>			<span class="p">),</span></div><div class='line' id='LC16'><br/></div><div class='line' id='LC17'>			<span class="s1">&#39;div&#39;</span>	<span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span></div><div class='line' id='LC18'>						<span class="s1">&#39;outer&#39;</span>	<span class="o">=&gt;</span> <span class="s2">&quot;&lt;div&gt;</span><span class="se">n</span><span class="s2">%inner%&lt;/div&gt;</span><span class="se">n</span><span class="s2">&quot;</span><span class="p">,</span></div><div class='line' id='LC19'>						<span class="s1">&#39;inner&#39;</span>	<span class="o">=&gt;</span> <span class="s2">&quot;&lt;p&gt;%item%&lt;/p&gt;</span><span class="se">n</span><span class="s2">&quot;</span></div><div class='line' id='LC20'>			<span class="p">),</span></div><div class='line' id='LC21'>		<span class="p">);</span></div><div class='line' id='LC22'><br/></div><div class='line' id='LC23'>	<span class="p">}</span></div><div class='line' id='LC24'><span class="p">}</span></div><div class='line' id='LC25'><br/></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2145820/971a998cc54775c4ebf62ab7954b58098af2690b/class-templates.php" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2145820#file_class_templates.php" style="float:right;margin-right:10px;color:#666">class-templates.php</a>
            <a href="https://gist.github.com/2145820">This Gist</a> is brought to you using <a href="http://en.bainternet.info/2011/simple-gist-embed"><small>Simple Gist Embed</small></a>.
          </div>
        </div>
</div>
</div></p>
<p>Ich möchte zur Erklärung schnell mal über die Klasse Lister fliegen. Am Anfang sehen wir ein Interface, das hat in sofern seinen Sinn, als dass man damit bestimmte Bedingungen festlegen kann. So wird im Konstruktor der Lister-Klasse festgelegt das ein Objekt übergeben werden muss das aus einer Klasse erstellt wurde die das Interface <code>Template</code> imlementiert. Damit gehen wir sicher, das dass übergebene Objekt über die Methode <code>get_templates()</code> verfügt. Würden wir versuchen ein Objekt zu übergeben das nicht über diese Methode verfügt, sprich nicht das Interface Template implementiert, würden wir beim Aufruf der Methode <code>get_templates()</code> eine Fehlermeldung bekommen. Damit gehen wir zwar nicht sicher das die Template-Klasse uns beim Aufruf der Methode <code>get_templates()</code> auch ein Array mit Templates zurück gibt, es hilft aber unter Umständen sehr bei der Fehlersuche wenn mal wieder etwas nicht funktioniert.<br />
Im  Konstruktor sehen wir das bei der Parameterübergabe darauf gepocht wird das dass übergeben Objekt das Interface Templates implementieren muss. Das übergebene Objekt speichern wir uns in einer Klassen-Variablen damit wir in anderen Methoden ggf. darauf zugreifen können. Zum Schluss holen wir uns noch die heiß begehrten Templates von der Template-Klasse.<br />
Als nächstes sehen wir dann eine get_templates() Methode. Die Methode sollte ja eigentlich ausgelagert werden. Hier steht sie quasi als Wrapper damit man z.B. noch weitere Kontrollen oder ähnliches einbauen kann. Natürlich hätte man auch z.B. in der Methode get_list() direkt auf die gespeicherte Instanz der Template-Klasse zugreifen können. Aber wir wollen uns ja mal angewöhnen gleich von Anfang an vernünftigen Code zu schreiben. Auch in Beispielen.<br />
Über get_list() muss ich hoffentlich keine Worte mehr verlieren. Templates abholen, Variablen ggf. verifizieren und desinfizieren, Liste basteln und ausgeben.</p>
<h3>Ein konkretes Beispiel</h3>
<p>Im Prinzip sind wir schon fertig und haben alle unsere gesteckten Ziele erreicht. Die Templates (Ausgabe) stehen in der einen Datei, die Verarbeitung der Daten (Logik) in einer anderen. Beides ist sauber voneinander getrennt. Kommen wir noch mal kurz darauf zurück warum das so sinnvoll sein kann.<br />
Nehmen wir einfach mal den Fall das wir relativ viele Templates haben in denen eine Footer definiert ist . Der könnte nach traditionellem HTML in etwa so aussehen:</p>
<pre class="brush:xml">&lt;div class="footer"&gt;
	&lt;p&gt;Copyright © 2001-2012&lt;/p&gt;
&lt;/div&gt;</pre>
<p>Nun kommt unser Kunde der gelesen hat das HTML5 der letzte Schrei ist und er möchte nun seine Webseite auf HTML5 umgestellt haben weil er befürchtet das sie ansonsten morgen nicht mehr erreichbar ist. Dazu müssten auch alle Footer-Bereiche nach <a title="W3Schools HTML5 Footer" href="http://www.w3schools.com/html5/tag_footer.asp">HTML5-Footer</a> konvertiert werden. Aus den Code oben müsste also in etwa folgendes werden:</p>
<pre class="brush:xml">&lt;footer&gt;
	&lt;p&gt;Copyright © 2001-2012&lt;/p&gt;
&lt;/footer&gt;</pre>
<p>Und das dann nicht nur auf einer Seite, sondern auf allen. Und nicht nur die Footer, sondern auch die Bereiche die eine <a title="W3Schools section" href="http://www.w3schools.com/html5/tag_section.asp">Section</a>, <a title="W3Schools nav" href="http://www.w3schools.com/html5/tag_nav.asp">Navigation</a>, <a title="W3Schools Article" href="http://www.w3schools.com/html5/tag_article.asp">Artikel</a>, usw. darstellen. Der richtige Zeitpunkt um eine Reihe böser Flüche los zu werden, denn das bedeutet tagelanges Wühlen in unübersichtlichen Codezeilen.<br />
Nun werfen wir einen Blick auf unsere Template-Klasse. Dort habe ich eine &#8220;Div-Liste&#8221; definiert mit der man z.B. solche Footer-Bereiche erzeugen kann. Anstatt nun den kompletten Code neu zu schreiben, tauscht man einfach seine Template-Klasse aus. Aus <code>Simple_List_Templates</code> wird dann z.B. <code>HTML5_List_Templates</code>. Das macht die Sache doch erheblich einfacher als in jeder HTML-Datei Änderungen manuell durchzuführen.<br />
Mit etwas Überlegung kommt man dann auch recht schnell darauf das es eine relativ blöde Idee ist die Template-Klasse beim erzeugen der Lister-Klasse fest zu verdrahten. Zu den Problem komme ich in einen anderen Artikel, dort will ich noch mal auf ein paar Feinheiten eingehen. Dann gehe ich auch noch mal auf die Key-Value-Paare in der Foreach-Schleife ein.</p>
<p>Aber wir sehen schon so, dass man mit der Trennung von Ausgabe und Logik für die Zukunft programmiert. Man kann sowohl die Logik als auch die Templates in verschiedenen Projekten erneut verwenden. Zudem sind Änderungen nicht mehr der Weltuntergang weil man unzählige Dateien durchsuchen und kontrollieren muss. Ich hoffe dem einen oder anderen einen kleinen Denkanstoß gegeben zu haben und wünsche viel Spaß beim selber Ausprobieren.</p>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-65/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Strings bequem formatieren</title>
		<link>http://yoda.neun12.de/artikel-63</link>
		<comments>http://yoda.neun12.de/artikel-63#comments</comments>
		<pubDate>Sun, 18 Mar 2012 01:17:01 +0000</pubDate>
		<dc:creator><![CDATA[Ralf]]></dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=63</guid>
		<description><![CDATA[Ursprünglich war PHP eine Template-Sprache die HTML etwas Dynamik verleihen sollte. Das PHP über dieses Stadium schon sehr (sehr, sehr) lange hinausgewachsen ist, dürfte bekannt sein. Dennoch wird PHP häufig noch genauso verwendet wie in seinen Anfangstagen. Zu meinem persönlichen Leidwesen unterstützt PHP dies aus Gründen der Rückwärtskompatibilität auch weiterhin. Bei der Arbeit an so [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Ursprünglich war PHP eine Template-Sprache die HTML etwas Dynamik verleihen sollte. Das PHP über dieses Stadium schon sehr (sehr, sehr) lange hinausgewachsen ist, dürfte bekannt sein. Dennoch wird PHP häufig noch genauso verwendet wie in seinen Anfangstagen. Zu meinem persönlichen Leidwesen unterstützt PHP dies aus Gründen der Rückwärtskompatibilität auch weiterhin. Bei der Arbeit an so manchem Script sollte sich keine funktionsbereite Kettensäge in Reichweite befinden, da ansonsten Gefahr besteht das am Autor des Scriptes ein Funktionstest der Kettensäge vorgenommen wird.</p>
<p>Vor allem bei WordPress sieht man folgende Konstrukte sehr häufig. Das hängt zum einen damit zusammen das WordPress keine Template-Engine hat und man gewissermaßen dazu gezwungen wird PHP und HTML zu vermischen. Zum anderen hängt es wohl auch damit zusammen, dass irgend ein Sepp bei WordPress mal damit angefangen hat solch grausige Konstrukte zu erstellen und jetzt einfach nicht mehr damit aufhören kann.</p>
<pre class="brush:php">&lt;?php
	$href	= 'http://example.com';
	$title	= 'Link zu Example.com';
	$class	= 'example_link';
	$id		= 'first_anchor';
	$text	= 'Dies ist ein Link zu Example.com';
?&gt;
&lt;a href="&lt;?php echo $href; ?&gt;" title="&lt;?php echo $title; ?&gt;" id="&lt;?php echo $id; ?&gt;" class="&lt;?php echo $class; ?&gt;"&gt;&lt;?php echo $text; ?&gt;&lt;/a&gt;</pre>
<p>Übersichtlich und lesbar ist was anderes. Wirklich schlimm wird es dann, wenn anstatt der Variablen auch noch Funktionsaufrufe direkt in die Ausgabe gemischt werden. Fehler sind so quasi vorprogrammiert und diese dann zu finden, ist eine Qual.</p>
<p>Deutlich übersichtlicher wird es, wenn man <em>Curly Braces</em> verwendet. Anstatt jede Variable mit einem<code>&lt;?php echo ...; ?&gt;</code> auszugeben, verwendet man geschweifte Klammern ( { und } ) um die Variable in einem String unterzubringen.</p>
<pre class="brush:php">&lt;?php
echo "&lt;a href=\"{$href}\" title='{$title}' id='{$id}' class='{$class}'&gt;{$text}&lt;/a&gt;";
?&gt;</pre>
<p>Das sieht doch schon mal deutlich übersichtlicher aus, hat aber auch seine Nachteile. Der String muss z.B. in doppelten Anführungszeichen (&#8220;) eingeschlossen sein, was zur Folge hat das man innerhalb des Strings nur einfache Anführungszeichen(&#8216;) verwenden kann oder doppelte Anführungszeichen mit einem Backslash maskieren muss (\&#8221;).<br />
Zudem funktionieren Funktionsaufrufe nicht mehr so einfach. Man müsste das Ergebnis des Funktionsaufrufes erst in einer Variablen zwischenspeichern bevor man den Wert im String verwenden kann. Dies kann etwas kniffelig werden wenn die Funktion keinen Wert zurück gibt, sondern ihn stattdessen direkt ausgibt.</p>
<p>Arbeitet man mit Klassen, ist es etwas leichter den Rückgabewert einer Funktion im String mit geschweiften Klammern zu integrieren.</p>
<pre class="brush:php">&lt;?php
	class Link
	{
		public $href	= 'http://example.com';
		public $class	= 'example_link';
		public $id		= 'first_anchor';
		public $text	= 'Dies ist ein Link zu Example.com';

		public function get_title(){
			return 'Link zu Example.com';
		}
	}

	$obj = new Link();

	echo  "&lt;a href='{$obj-&gt;href}' title='{$obj-&gt;get_title()}' id='{$obj-&gt;id}' class='{$obj-&gt;class}'&gt;{$obj-&gt;text}&lt;/a&gt;";
?&gt;</pre>
<p>Genau genommen handelt es sich hierbei um einen Methodenaufruf und nicht um einen Funktionsaufruf. Der &#8220;Trick&#8221; an der ganzen Sache ist einfach der, dass PHP <code>$obj</code> wie eine Variable behandelt (was es ja auch ist) und deswegen der Methodenaufruf relativ problemlos möglich ist.</p>
<p>Der größte Nachteil an allen Varianten ist meiner Meinung nach aber der, dass man Logik und Ausgabe miteinander vermischt. Gerade wenn man komplexe Ausgaben hat, wird es schwer die Stelle wiederzufinden an der die gesuchte Ausgabe formatiert wird.<br />
Besser wäre es, wenn man alle Strings zentral an einer Stelle sammelt und in der Logik dann nur noch eine Variable zur Ausgabe verwendet.</p>
<pre class="brush:php">&lt;?php
$format = "&lt;a href='{$href}' title='{$title}' id='{$id}' class='{$class}'&gt;{$text}&lt;/a&gt;";

// some other code...

echo $format;
?&gt;</pre>
<p>Dies wäre ein netter Ansatz, hat jedoch auch so seine Haken. Denn <code>$format</code> kann erst gebildet werden, nachdem alle anderen Variablen bereits definiert sind.</p>
<pre class="brush:php">&lt;?php
$format = "&lt;a href='{$href}' title='{$title}' id='{$id}' class='{$class}'&gt;{$text}&lt;/a&gt;";

// some other code...

$text = 'Ein anderer Linktext';
echo $format;
?&gt;</pre>
<p>Würde zum Beispiel nicht funktionieren. Denn zu dem Zeitpunkt an dem <code>$format</code> erstellt wird ist <code>$text</code> noch gar nicht oder mit einen anderen Wert definiert.</p>
<p>Wir bräuchten also eine Funktion die quasi einen abstrakten Formatierungs-String entgegen nimmt und an den entsprechenden Stellen die Werte der Variablen einsetzt. Grundsätzlich hat PHP eine solche Funktion: <code><a title="printf php.net" href="http://php.net/manual/de/function.printf.php">printf()</a></code> bzw. <code><a title="sprintf php.net" href="http://php.net/manual/de/function.sprintf.php">sprintf()</a></code>.<br />
<code>printf()</code>nimmt einen Formatierungs-String und eine Reihe an Variablen entgegen. Die Platzhalter im Formatierungs-String erlauben zudem eine gewisse Formatierung der Ausgabe.</p>
<pre class="brush:php">&lt;?php
$format = "&lt;a href='%s' title='%s' id='%s' class='%s'&gt;%s&lt;/a&gt;";

// some other code...

printf( $format, $href, $title, $id, $class, $text );
?&gt;</pre>
<p>Das sieht schon ganz brauchbar aus. Der Formatierungs-String kann z.B. ganz am Anfang des Scriptes definiert werden bevor auch nur eine der verwendeten Variablen definiert wurde. Und man kann anstatt einer Variablen auch einen Funktionsaufruf verwenden.<br />
Einige kleine Nachteile hat <code>printf()</code> jedoch auch. In der gezeigten Variante muss z.B. die Reihenfolge strikt eingehalten werden. <code>printf()</code> bietet einige Möglichkeiten wie man die Reihenfolge flexibler gestalten kann und Variablen mehrfach verwenden kann. Zur genauen Verwendung der Formatierung schaut man am besten im <a title="sprintf php.net" href="http://php.net/manual/de/function.sprintf.php">PHP-Manual</a> nach.</p>
<p>Aber auch <code>printf()</code> wird bei komplexen Ausgaben recht schnell unübersichtlich. Vertauscht man zwei Variablen im Funktionsaufruf, kommt es zur fehlerhaften Ausgabe. Auch wenn man die mehrfache Verwendung von Variablen nutzt, muss man die Übersicht behalten an welcher Stelle welche Variable steht.<br />
Im Großen und Ganzen eine etwas unbefriedigende Situation die zu unleserlichen Code und versteckten Fehlern führt. Aus diesen Grund habe ich mir eine Klasse geschrieben mit der ich den Code etwas übersichtlicher gestalten kann.<br />
Die Anforderung lag darin, zum einen die Übersichtlichkeit der Variante mit geschweiften Klammern zu erhalten. Zum anderen die Flexibilität, Abstraktion und Formatierungsmöglichkeiten von <code>printf()</code> zu haben. Heraus gekommen ist die <a title="Formatter on Github" href="https://github.com/RalfAlbert/Formatter">Klasse Formatter</a>.</p>
<p>Formatter nimmt einen Formatierungs-String ähnlich wie <code>printf()</code> entgegen, jedoch kann man den Platzhaltern Namen geben, was für mehr Übersichtlichkeit sorgt. Als zweiten Parameter nimmt Formatter ein Array mit Schlüssel-Werte-Paaren oder ein Objekt entgegen. Daher spielt die Reihenfolge in der die Werte definiert werden keine Rolle mehr. Zusätzlich lässt sich die Ausgabe wie bei <code>printf()</code>formatieren.</p>
<pre class="brush:php">&lt;?php
$format_time = 'Es ist jetzt %stunden[02d]%:%minuten[02d]%:%sekunden[02d]% Uhr %tageszeit%';
// some other code...

$time_values = array(
		'tageszeit'	=&gt; 'mitten in der Nacht',
		'stunden'	=&gt; 1,
		'minuten'	=&gt; 23,
		'sekunden'	=&gt; 8,
	);
// more code...

Formatter::printf( $format_time, $time_values );
// Es ist jetzt 01:23:08 Uhr mitten in der Nacht.
?&gt;</pre>
<p>So ist es sehr leicht Formatierung, Logik und Ausgabe voneinander zu trennen und das dann auch noch lesbar zu gestalten. Das es durchaus Vorteile hat das alles voneinander zu trennen, zeige ich dann im nächsten Artikel.</p>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-63/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Quicktipp: Checkboxen auswerten</title>
		<link>http://yoda.neun12.de/artikel-61</link>
		<comments>http://yoda.neun12.de/artikel-61#comments</comments>
		<pubDate>Sat, 11 Feb 2012 14:19:19 +0000</pubDate>
		<dc:creator><![CDATA[Ralf]]></dc:creator>
				<category><![CDATA[Code-Snippets]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Quicktipp]]></category>
		<category><![CDATA[auswertung]]></category>
		<category><![CDATA[checkboxen]]></category>
		<category><![CDATA[formular]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=61</guid>
		<description><![CDATA[Vor kurzem hatte ich das Problem das ich mehrere Checkboxen bzw. deren Kombination auswerten musste. Normalerweise eine Arbeit für Leute die Mutter &#38; Vadder erschlagen haben. Dazu gleich mal die Bedingungen: Wir haben drei Checkboxen (a, b und c) in einem Formular und müssen auswerten welche Checkbox ausgewählt wurde bzw. nicht ausgewählt wurde. Wenn das [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Vor kurzem hatte ich das Problem das ich mehrere Checkboxen bzw. deren Kombination auswerten musste. Normalerweise eine Arbeit für Leute die Mutter &amp; Vadder erschlagen haben. Dazu gleich mal die Bedingungen:<br />
Wir haben drei Checkboxen (a, b und c) in einem Formular und müssen auswerten welche Checkbox ausgewählt wurde bzw. <em>nicht</em> ausgewählt wurde. Wenn das Formular abgeschickt wird, bekommen wir ein POST- bzw. GET-Array mit den Werten (ich gehe im weiteren mal von einem POST-Array aus).<br />
Das Böse an Checkboxen ist, wenn eine Checkbox nicht ausgewählt wurde, wird auch kein Wert im POST- bzw. GET-Array gesetzt.<br />
Nach dem Absenden des Formulars bekommen wir also in etwa so etwas:</p>
<pre class="brush:php">$mPost = array(
		'action'	=&gt; 'send',
		'user'		=&gt; 'Horst',
		'a'		=&gt; 'On',
		'c'		=&gt; 'On',
		'foo'		=&gt; 'bar',
		'baz'		=&gt; '',
	);</pre>
<p>Dies ist nun eine Simulation des POST-Arrays und man kann sehen das für &#8216;b&#8217; kein Wert gesetzt wurde sofern die Checkbox &#8216;b&#8217; nicht ausgewählt wurde.<br />
Wie wertet man nun üblicherweise die drei Checkboxen aus? Wahrscheinlich mit vielen <code>If-ElseIf-Else</code> Konstrukten und <code>isset()</code>:</p>
<pre class="brush:php">if( isset( $_POST['a'] ) )
...
elseif( isset( $_POST['a'] ) &amp;&amp; isset( $_POST['b'] ) )
...
elseif( isset( $_POST['a' ) &amp;&amp; ! isset( $_POST['b' ) )
...

if( isset( $_POST['b'] ) &amp;&amp; isset( $_POST['c'] ) )
...</pre>
<p>So wühlt man sich Zeile für Zeile durch alle möglichen Kombinationen und versucht keine zu vergessen. <strong>Das. Ist. Blöd!</strong> Und nicht nur blöd, sondern auch verdammt unübersichtlich. Bei drei Checkboxen mag es noch machbar sein, aber wenn man fünf, acht oder mehr Checkboxen hat, dann wird es fast schon unmöglich alle Kombinationen von ausgewählten und nicht ausgewählten Checkboxen zu berücksichtigen.</p>
<p>Da eine Checkbox nur ein Ja-Nein-Wert (Wahr oder Falsch) darstellt, habe ich mich recht schnell an die Zeit erinnert als ich mit der Computerei angefangen habe. Damals hatte ich einen C16 mit 16kB RAM. Dort war jedes Bit kostbarer als Gold und durfte nicht verschwendet werden. Deswegen hatte man oft mit Bitmasken gearbeitet. In einer Bitmaske steht jedes Bit für einen Ja oder einen Nein-Wert. Das war und ist recht effizient, denn in einem Byte kann ich so 8 Werte speichern. Und natürlich auch wieder abfragen.</p>
<p>Nun stehen wir vor dem Problem unsere drei Checkboxen in eine Bitmaske zu bekommen. Dazu benötigen wir erst einmal eine entsprechende Maske. Mit <code>printf()</code> bzw. <code>sprintf()</code> können wir eine solche Maske leicht erstellen:</p>
<pre class="brush:php">$bin = sprintf( '%b%b%b', $mPost['a'], $mPost['b'], $mPost['c'] );</pre>
<p>Das PHP-Manual sagt zum Platzhalter <code>%b</code> folgendes:</p>
<blockquote><p>das Argument wird als Integer angesehen und als Binär-Wert ausgegeben</p></blockquote>
<p><code>%b</code> wird also immer zu 1 oder 0 umgewandelt. Wandeln wir nun unsere Variablen (a, b und c) in Boolsche Werte um, so würde PHP <code>%b</code> durch 1 bzw. 0 ersetzen, je nachdem ob die Variable <code>TRUE</code> oder <code>FALSE</code> ist. Denn zuerst würde der boolsche Wert in einen Integer (1 bzw. 0) umgewandelt und dann in einen einstelligen Binärwert. Dies erreichen wir dadurch, dass wir mit <code>isset()</code> abfragen ob die Variable überhaupt existiert. Somit umschiffen wir gleichzeitig das Problem das nicht ausgewählte Checkboxen keinen Wert übertragen.</p>
<pre class="brush:php">$bin = printf( '%b%b%b', isset( $mPost['a'] ), isset( $mPost['b'] ), isset( $mPost['c'] ) );</pre>
<p>Das klappt soweit schon wunderbar und bei drei Checkboxen ist es auch noch recht übersichtlich.<br />
Als Ergebnis erhalten wir einen String der z.B. &#8220;101&#8243; enthält. Je nachdem welche Variable gesetzt ist und welche nicht. Diesen String können wir nun ganz einfach mit einem <code>switch-case </code>abfragen und darauf reagieren:</p>
<pre class="brush:php">switch( $bin ){
	case '000':
		//nichts ausgewaehlt
	break;

	case '100':
		// nur checkbox 'a' wurde ausgewählt
	break;

	case '101':
		// checkbox 'a' wurde ausgewaehlt, checkbox 'b' jedoch NICHT, checkbox 'c' ist uns egal
	break;

	default:
		// alle anderen Faelle
	break;
}</pre>
<p>Bei drei Checkboxen ist das schon eine ganz brauchbare Lösung. Aber was ist wenn wir jetzt, sagen wir mal, 20 Checkboxen haben. Zum Beispiel eine Umfrage oder ähnliches?<br />
Hier stehen wir vor zwei Problemen. Zum einen wäre der <code>sprintf()</code> nicht mehr übersichtlich und recht unbrauchbar. Zum anderen müssen wir ja gewähren das jede Variable an ihren Platz ist und nicht z.B. &#8216;a&#8217; und &#8216;g&#8217; vertauscht sind.</p>
<p>Als erstes legen wir uns mal ein Muster fest welche Variablen uns in welcher Reihenfolge interessieren. Das machen wir einfach mit einem Array:</p>
<pre class="brush:php">$defaults = array(
		'a'	=&gt; '',
		'b'	=&gt; '',
		'c'	=&gt; '',
	);</pre>
<p>Damit wir nicht mit uninitialisierten Variablen arbeiten müssen, mischen wir das POST-Array mit unserer Vorgabe. Dadurch gehen wir sicher das alle benötigten Variablen auch mit einem (leeren) Wert initialisiert sind.</p>
<pre class="brush:php">$data = array_merge( $defaults, $mPost );</pre>
<p>Nun müssen wir nur noch über unser Vorgabe-Array (<code>$defaults</code>) laufen und abfragen ob die entsprechenden Schlüssel im Daten-Array (<code>$data</code>) gesetzt sind.</p>
<pre class="brush:php">$bin = '';
foreach( $defaults as $key =&gt; $val )
	$bin .= sprintf( '%b', !!$data[$key] );</pre>
<p>Dies kann man auch anders lösen, z.B. mit einem Trinären Operator. Je nach Geschmack des Programmierers halt:</p>
<pre class="brush:php">$bin .= ! empty( $data[$key] ) ? '1' : '0';</pre>
<p>Wenn der entsprechende Wert im Daten-Array <em>nicht</em> leer ist, wird eine 1 ausgegeben, ansonsten eine 0.<br />
Als Ergebnis erhalten wir wieder einen String mit vielen Einsen und Nullen den wir im Switch-Case abfragen können. Wandelt man den String mit <code>bindec()</code> in eine Dezimalzahl um, kann man die Auswahl schön platzsparend speichern. Wenn man mit Cookies arbeitet, wird man nämlich schnell wieder daran erinnert das Speicherplatz Mangelware ist. Odre man nutzt den Dezimalwert um eine statistische Auswertung durchzuführen. Oder verwendet ihn im Switch-Case. Oder mit If-Abfragen. Oder, oder, oder&#8230;</p>
<p>Und hier das ganze dann  noch mal als komplettes Script: <div class="gistem"><div id="gist-1799597" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="x">$mPost = array(</span></div><div class='line' id='LC2'><span class="x">		&#39;action&#39;	=&gt; &#39;send&#39;,</span></div><div class='line' id='LC3'><span class="x">		&#39;user&#39;		=&gt; &#39;Horst&#39;,</span></div><div class='line' id='LC4'><span class="x">		&#39;a&#39;			=&gt; &#39;On&#39;,</span></div><div class='line' id='LC5'><span class="x">		&#39;c&#39;			=&gt; &#39;On&#39;,</span></div><div class='line' id='LC6'><span class="x">		&#39;foo&#39;		=&gt; &#39;bar&#39;,</span></div><div class='line' id='LC7'><span class="x">		&#39;baz&#39;		=&gt; &#39;&#39;,</span></div><div class='line' id='LC8'><span class="x">	);</span></div><div class='line' id='LC9'><br/></div><div class='line' id='LC10'><span class="x">$defaults = array(</span></div><div class='line' id='LC11'><span class="x">		&#39;a&#39;	=&gt; &#39;&#39;,</span></div><div class='line' id='LC12'><span class="x">		&#39;b&#39;	=&gt; &#39;&#39;,</span></div><div class='line' id='LC13'><span class="x">		&#39;c&#39;	=&gt; &#39;&#39;,</span></div><div class='line' id='LC14'><span class="x">	);</span></div><div class='line' id='LC15'><br/></div><div class='line' id='LC16'><span class="x">$data = array_merge( $defaults, $mPost );</span></div><div class='line' id='LC17'><br/></div><div class='line' id='LC18'><span class="x">$bin = &#39;&#39;;</span></div><div class='line' id='LC19'><br/></div><div class='line' id='LC20'><span class="x">foreach( $defaults as $key =&gt; $val ){</span></div><div class='line' id='LC21'><span class="x">	$bin .= sprintf( &#39;%b&#39;, !!$data[$key] );</span></div><div class='line' id='LC22'><span class="x">	//$bin .= ! empty( $data[$key] ) ? &#39;1&#39; : &#39;0&#39;;</span></div><div class='line' id='LC23'><span class="x">}	</span></div><div class='line' id='LC24'><br/></div><div class='line' id='LC25'><span class="x">$dec = bindec( $bin );</span></div><div class='line' id='LC26'><br/></div><div class='line' id='LC27'><span class="x">var_dump( $bin );</span></div><div class='line' id='LC28'><span class="x">var_dump( $dec );</span></div><div class='line' id='LC29'><br/></div><div class='line' id='LC30'><span class="x">switch( $bin ){</span></div><div class='line' id='LC31'><span class="x">	case &#39;000&#39;:</span></div><div class='line' id='LC32'><span class="x">		//nichts ausgewaehlt</span></div><div class='line' id='LC33'><span class="x">	break;</span></div><div class='line' id='LC34'><span class="x">	</span></div><div class='line' id='LC35'><span class="x">	case &#39;100&#39;:</span></div><div class='line' id='LC36'><span class="x">		// nur checkbox &#39;a&#39; wurde ausgewählt</span></div><div class='line' id='LC37'><span class="x">	break;</span></div><div class='line' id='LC38'><span class="x">	</span></div><div class='line' id='LC39'><span class="x">	case &#39;101&#39;:</span></div><div class='line' id='LC40'><span class="x">		// checkbox &#39;a&#39; wurde ausgewaehlt, checkbox &#39;b&#39; jedoch NICHT</span></div><div class='line' id='LC41'><span class="x">	break;</span></div><div class='line' id='LC42'><span class="x">	</span></div><div class='line' id='LC43'><span class="x">	default:</span></div><div class='line' id='LC44'><span class="x">		// alle anderen Faelle</span></div><div class='line' id='LC45'><span class="x">	break;</span></div><div class='line' id='LC46'><span class="x">}</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1799597/a2eab75bf40e1ed29ddde59a7172caa57af58568/file1.php" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1799597#file_file1.php" style="float:right;margin-right:10px;color:#666">file1.php</a>
            <a href="https://gist.github.com/1799597">This Gist</a> is brought to you using <a href="http://en.bainternet.info/2011/simple-gist-embed"><small>Simple Gist Embed</small></a>.
          </div>
        </div>
</div>
</div></p>
<p>Zum Schluss noch etwas &#8220;dreckiges&#8221; PHP. Hier möchte ich mal schnell den NOTNOT-Operator einwerfen auf den ich bei der Suche nach der Lösung gestoßen bin. <code>!$data[$key]</code> wird Wahr (TRUE) wenn $data[$key] <em>leer</em> ist. Ich möchte aber wissen ob eine Variable <em>nicht</em> leer ist, denn <code>printf()</code> soll ja aus &#8216;%b&#8217; eine &#8217;1&#8242; machen wenn die Variable gesetzt ist. Also muss ich die Bedingung <code>!$data[$key]</code> noch einmal negieren. Aus <code>!$data[$key]</code> wird also <code>!!$data[$key]</code>.<br />
Dies ist also im Grunde genommen nur eine fürchterliche Kurzschreibweise für <code> ! empty( $data[$key] )</code>. Für das schnelle Programmieren sind solche Kurzschreibweisen ganz nützlich. Sie sparen eine Menge Tipperei wenn man viel Code schreiben muss. Für die Lesbarkeit des Codes sind sie jedoch sehr kontraproduktiv. Man muss schon genau überlegen was da gerade passiert und sicher gehen das die Variable auch initialisiert ist, ansonsten hagelt es Notices.</p>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-61/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>define( RACE_CONDITION, TRUE ) &#8211; Das Rennen um die Konstanten</title>
		<link>http://yoda.neun12.de/artikel-57</link>
		<comments>http://yoda.neun12.de/artikel-57#comments</comments>
		<pubDate>Sun, 08 Jan 2012 17:11:37 +0000</pubDate>
		<dc:creator><![CDATA[Ralf]]></dc:creator>
				<category><![CDATA[HowTo]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=57</guid>
		<description><![CDATA[Leider noch viel zu oft sieht man in Plugins den teilweise massenhaften Gebrauch von define(). Selbst wenn mit Klassen gearbeitet wird, wird reichlich Gebrauch von define() gemacht. Daran lässt sich gut erkennen ob der Programmierer die Klasse lediglich zur Kapselung seines Codes oder tatsächlich wegen OOP erstellt hat. Aber was ist nun so doof an [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Leider noch viel zu oft sieht man in Plugins den teilweise massenhaften Gebrauch von <code>define()</code>. Selbst wenn mit Klassen gearbeitet wird, wird reichlich Gebrauch von <code>define()</code> gemacht. Daran lässt sich gut erkennen ob der Programmierer die Klasse lediglich zur Kapselung seines Codes oder tatsächlich wegen OOP erstellt hat.<br />
Aber was ist nun so doof an <code>define()</code> das man es möglichst sparsam, am besten gar nicht, benutzen sollte? Die Überschrift sagt es ja schon: Race Conditions.</p>
<p>Zunächst einmal ein Stück PHP-Code wie er lange Zeit für WordPress-Plugins benutzt wurde. Unter anderem, weil der <a title="WordPress Codex" href="http://codex.wordpress.org/Determining_Plugin_and_Content_Directories#Backwards_Compatibility_Code">Codex</a> es so vorgeschlagen hatte (mittlerweile wird von der Verwendung dieses Codes dringendst abgeraten):</p>
<pre class="brush:php">	// Pre-2.6 compatibility
	if ( ! defined( 'WP_CONTENT_URL' ) )
		define( 'WP_CONTENT_URL', get_option( 'siteurl' ) . '/wp-content' );
	if ( ! defined( 'WP_CONTENT_DIR' ) )
		define( 'WP_CONTENT_DIR', ABSPATH . 'wp-content' );
	if ( ! defined( 'WP_PLUGIN_URL' ) )
		define( 'WP_PLUGIN_URL', WP_CONTENT_URL. '/plugins' );
	if ( ! defined( 'WP_PLUGIN_DIR' ) )
		define( 'WP_PLUGIN_DIR', WP_CONTENT_DIR . '/plugins' );</pre>
<p>Der Code ist relativ logisch. Sollten bestimmte Konstanten nicht definiert sein, so werden sie definiert. So weit, so unschlimm. Aber der Teufel steckt, wie so oft, im Detail.<br />
Bedenkt man das alle Plugins nacheinander geladen werden, wird schnell klar dass das erste Plugin welches diese Konstanten definiert gewinnt. Typische Race Condition: Wer zuerst kommt, mahlt zuerst.<br />
Was passierte nun wenn das erste Plugin das geladen wurde <code>WP_CONTENT_URL</code> nicht dem Codex entsprechend mit <code>get_option( 'siteurl' ) . '/wp-content' )</code> definierte, sondern z.B. mit <code>define( 'WP_CONTENT_URL', '/my_bad_content/wp-content/' );</code> ? Ganz klar, alle anderen Plugins die auf <code>WP_CONTENT_URL</code> zurückgriffen versuchten aus dem falschen Verzeichnis zu lesen. Da <code>define()</code> nicht &#8220;überschreibbare globale Variablen&#8221;, auch bekannt als Konstanten, definiert, konnte auch kein anderes Plugin den Pfad zum wp-content-Verzeichnis wieder grade biegen.<br />
Im einfachen Fall führt das zu nicht mehr funktionierenden Plugins. Im schlimmeren Fall deutet <code>WP_CONTENT_URL</code> auf einen entfernten Server und könnte Schadcode nachladen. Zugegeben, ein sehr konstruierter Fall da WordPress in der Regel diese Konstanten selber definiert hatte. Aber es ist nun einmal ein mögliches Szenario was man im Hinterkopf haben sollte.</p>
<p>Nun haben wir die 2.6er Zeit in WordPress ja hoffentlich lange hinter uns gelassen und niemand verbreitet mehr Plugins die solche Code-Zeilen enthalten. Oder? Ich schau mal böse zu den Kollegen rüber und schweige mich aus wo ich den Code her habe. Ich müsste auch einige böse anschauen, dazu fehlt mir die Zeit.</p>
<p>Aber was für WordPress-Konstanten gilt, gilt leider auch für unsere eigenen Konstanten. Schnell mal mit <code>define()</code> eine Konstante definieren weil die Verwendung von Konstanten ja so einfach ist. &#8220;<em>Ich definiere in Datei A eine Variable die ich in Datei B brauche? Nimm eine Konstante, die sind überall verfügbar.</em>&#8221; Dies ist ein Gedankengang, von dem wir uns schleunigst trennen sollten.<br />
Das fängt damit an, dass Konstanten &#8220;überall&#8221; verfügbar sind. Es interessiert kein anderes Script wo ich z.B. meine JavaScript-Dateien ablege, deswegen braucht es auch kein <code>define( 'SCRIPT_DIR', '/my_ugly_dir/ );</code>. Mal davon abgesehen das ich damit Informationen &#8220;nach außen&#8221; trage die andere nicht interessieren, verseuche ich damit auch den globalen Namensraum. Alle anderen Scripte können nun die Konstante <code>SCRIPT_DIR</code> nicht mehr verwenden da sie bereits belegt ist.<br />
Um diesen Umstand zu umgehen, werden Konstanten gerne mit Prefixen versehen. <code>define( 'MY_UGLY_SCRIPT_DIR', '/my_ugly_script_dir' );</code> ist auch nicht wesentlich besser. Je mehr Plugins auf den Markt kommen, desto einfallsreicher muss ich meine Prefixe aussuchen. Das endet in immer längeren Prefixe und macht den Code am Ende nur unübersichtlicher. Zudem löst es das Problem von Namenskollisionen nicht komplett.</p>
<p>Denn was ist denn wenn ich mehr als ein Plugin schreibe? Hand auf&#8217;s Herz, wir sind doch alles faule Säue. Also kopieren wir einfach Code den wir bereits geschrieben haben um ihn wiederzuverwenden. So gesehen nicht schlimm, ist ja sogar quasi ein empfohlenes Vorgehen. Nur blöd wenn ich in zwei Plugins die gleiche Konstante verwende, sie jedoch in beiden Plugins unterschiedliche Werte enthält (z.B. <code>__FILE__</code>.<br />
Race Condition. Das zuerst geladene Plugin gewinnt. Ich mache mir das Leben also unnötig schwer. Denn Code den ich einmal geschrieben habe, kann ich nicht gefahrlos wiederverwenden ohne ihn erneut anzufassen.</p>
<p>Ewig nur meckern kann aber auch nicht die Lösung sein. Eine Alternative zu <code>define()</code> kommt aus dem OOP-Bereich und ist ein einfacher Datencontainer.<br />
<div class="gistem"><div id="gist-1578910" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="cp">&lt;?php</span></div><div class='line' id='LC2'><span class="k">class</span> <span class="nc">DataContainer</span></div><div class='line' id='LC3'><span class="p">{</span></div><div class='line' id='LC4'>	<span class="k">private</span> <span class="k">static</span> <span class="nv">$data</span> <span class="o">=</span> <span class="k">array</span><span class="p">();</span></div><div class='line' id='LC5'><br/></div><div class='line' id='LC6'>	<span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">__set</span><span class="p">(</span> <span class="nv">$name</span><span class="p">,</span> <span class="nv">$value</span> <span class="p">){</span></div><div class='line' id='LC7'>		<span class="k">if</span><span class="p">(</span> <span class="o">!</span> <span class="nb">isset</span><span class="p">(</span> <span class="nx">self</span><span class="o">::</span><span class="nv">$data</span><span class="p">[</span><span class="nv">$name</span><span class="p">]</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC8'>			<span class="nx">self</span><span class="o">::</span><span class="nv">$data</span><span class="p">[</span><span class="nv">$name</span><span class="p">]</span> <span class="o">=</span> <span class="nv">$value</span><span class="p">;</span></div><div class='line' id='LC9'>		<span class="k">else</span></div><div class='line' id='LC10'>			<span class="k">return</span> <span class="k">FALSE</span><span class="p">;</span></div><div class='line' id='LC11'><br/></div><div class='line' id='LC12'>		<span class="k">return</span> <span class="k">TRUE</span><span class="p">;</span></div><div class='line' id='LC13'>	<span class="p">}</span></div><div class='line' id='LC14'><br/></div><div class='line' id='LC15'>	<span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">__get</span><span class="p">(</span> <span class="nv">$name</span> <span class="p">){</span></div><div class='line' id='LC16'>		<span class="k">if</span><span class="p">(</span> <span class="nb">isset</span><span class="p">(</span> <span class="nx">self</span><span class="o">::</span><span class="nv">$data</span><span class="p">[</span><span class="nv">$name</span><span class="p">]</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC17'>			<span class="k">return</span> <span class="nx">self</span><span class="o">::</span><span class="nv">$data</span><span class="p">[</span><span class="nv">$name</span><span class="p">];</span></div><div class='line' id='LC18'>		<span class="k">else</span></div><div class='line' id='LC19'>			<span class="k">return</span> <span class="k">NULL</span><span class="p">;</span></div><div class='line' id='LC20'>	<span class="p">}</span></div><div class='line' id='LC21'><span class="p">}</span></div><div class='line' id='LC22'><br/></div><div class='line' id='LC23'><span class="nv">$dc</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">DataContainer</span><span class="p">;</span></div><div class='line' id='LC24'><span class="nv">$dc</span><span class="o">-&gt;</span><span class="na">FILE</span> <span class="o">=</span> <span class="nb">basename</span><span class="p">(</span> <span class="k">__FILE__</span> <span class="p">);</span></div><div class='line' id='LC25'><br/></div><div class='line' id='LC26'><span class="nb">var_dump</span><span class="p">(</span> <span class="nv">$dc</span><span class="o">-&gt;</span><span class="na">FILE</span> <span class="p">);</span></div><div class='line' id='LC27'><br/></div><div class='line' id='LC28'><span class="nv">$dc_two</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">DataContainer</span><span class="p">;</span></div><div class='line' id='LC29'><span class="nv">$dc_two</span><span class="o">-&gt;</span><span class="na">FILE</span> <span class="o">=</span> <span class="s1">&#39;mettigel&#39;</span><span class="p">;</span></div><div class='line' id='LC30'><br/></div><div class='line' id='LC31'><span class="nb">var_dump</span><span class="p">(</span> <span class="nv">$dc</span><span class="o">-&gt;</span><span class="na">FILE</span> <span class="p">);</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1578910/8a91635cbb53cb1a2b18ecacacd224d0581a4e1d/file1.php" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1578910#file_file1.php" style="float:right;margin-right:10px;color:#666">file1.php</a>
            <a href="https://gist.github.com/1578910">This Gist</a> is brought to you using <a href="http://en.bainternet.info/2011/simple-gist-embed"><small>Simple Gist Embed</small></a>.
          </div>
        </div>
</div>
</div></p>
<p>Das Prinzip sollte schnell klar sein. Es wird eine Klasse erzeugt die nichts anderes macht als Variablen über die magischen Methoden <code>__set()</code> und <code>__get()</code> entgegen zu nehmen und zu speichern. Da das Array <code>$data</code> als statisch deklariert wurde, wird es bei neuen Instanz der Klasse nicht verändert.<br />
Der Trick an der ganzen Sache besteht darin, in der magischen Methode <code>__set()</code> zu überprüfen ob die Variable <code>$name</code> bereits gesetzt ist. Ist sie es nicht, wird sie gesetzt. Ist sie es, wird <code>FALSE</code> zurück gegeben. So sind einmal gesetzte Variablen vor dem Überschreiben geschützt.<br />
Damit kann man die Klasse DataContainer genauso verwenden wie ein <code>define()</code>. Darüber hinaus kann man sich auch noch eine Methode <code>reset( $name )</code> schreiben, mit der man im Notfall eine einmal gesetzte Pseudo-Konstante wieder löschen kann. Selbst ein <code>redefine()</code>, das es in PHP nicht gibt, wäre damit möglich. Mit so einem Datencontainer sind wir also sogar flexibler als mit <code>define()</code>.</p>
<p>Jetzt stellt sich natürlich die Frage wenn ich den Datencontainer in Datei <code>a.php</code> habe, aber in Datei <code>b.php</code> darauf zugreifen will, wie macht man das?<br />
Da gibt es elegante und weniger elegante Wege. Ein etwas weniger eleganter Weg wäre es den Datencontainer mittels <code>define()</code>verfügbar zu machen.</p>
<pre class="brush:php">$dc = new DataContainer;
$dc-&gt;FILE = basename( __FILE__ );
define( 'DATACONTAINER', serialize( $dc ) );

// somewhere over the rainbow ... ehmm ... in another file
$e = unserialize( DATACONTAINER );
var_dump( $e-&gt;FILE );</pre>
<p>Bitte schlagt mich nicht für diesen Code-Schnipsel. Kann man machen, muss man aber nicht. Denn deutlich eleganter geht es mit einem Autoloader, darüber schreibe ich aber demnächst etwas (Cliffhänger <img src="http://yoda.neun12.de/wp-includes/images/smilies/icon_wink.gif" alt=";)" class="wp-smiley" />  )</p>
<p>Ich hoffe es ist klar geworden das die Verwendung von Konstanten relativ viele Probleme mit sich bringt die man relativ einfach beseitigen kann. Überlassen wir die Verwendung von Konstanten besser WordPress und widmen uns lieber einfacheren und eleganteren Methoden.</p>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-57/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>PHP-Daten in JavaScript einschleusen</title>
		<link>http://yoda.neun12.de/artikel-10</link>
		<comments>http://yoda.neun12.de/artikel-10#comments</comments>
		<pubDate>Sat, 19 Feb 2011 22:17:27 +0000</pubDate>
		<dc:creator><![CDATA[Ralf]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[Anfänger]]></category>
		<category><![CDATA[Fortgeschrittene]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[JS]]></category>
		<category><![CDATA[Lokalisation]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=10</guid>
		<description><![CDATA[Nein, dies wird kein Hacker-Artikel wie man mit PHP und JavaScript Webseiten klein bekommt. Vielmehr geht es mir darum, wie man Daten von PHP zu einem JavaScript übertragen kann. Am Anfang solcher Artikel steht meistens die Frage wozu das gut sein soll. Die Antwort ist zumindest im Fall von WordPress relativ einfach: Um Daten aus [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Nein, dies wird kein Hacker-Artikel wie man mit PHP und JavaScript Webseiten klein bekommt. Vielmehr geht es mir darum, wie man Daten von PHP zu einem JavaScript übertragen kann. Am Anfang solcher Artikel steht meistens die Frage wozu das gut sein soll. Die Antwort ist zumindest im Fall von WordPress relativ einfach: Um Daten aus WordPress in ein JavaScript (JS) zu bekommen. Ob das nun der Benutzername eines Besuchers ist der irgendwo dynamisch eingefügt werden soll oder Texte die Übersetzt werden müssen. Es gibt häufig Situationen wo man die im folgenden beschrieben Techniken ganz gut gebrauchen kann. Ich selber stand z.B. vor dem Problem das ich mit jQuery ein Akkordeon  umsetzen musste und dieses einen Button hatte mit dem sich alle Felder öffnen bzw. schließen ließen. Nun fügte das jQuery-Script je nach Zustand der Felder ein &#8220;Öffne alle&#8221; bzw. &#8220;Schließe alle&#8221; an eine bestimmte Stelle ein. Da ich etwas faul bin, habe ich beide Zeichenketten direkt im JS abgelegt, was zur Folge hatte das man diese nicht mehr über die Funktionen zur Lokalisation übersetzen konnte. Also musste ein Weg her wie ich erst die Zeichenketten in PHP mittels <code>gettext</code> übersetzen und dann in das JS einfügen konnte.</p>
<p>Der folgende Artikel wird etwas länger, deshalb habe ich ihn auf mehrere Seiten aufgeteilt. Diejenigen die sich mit WordPress auskennen, können den Artikel quer lesen da ich auch Grundlagen beschreibe. Interessante Sachen werden dann auf den letzten Seiten zu lesen sein. Diejenigen die sich nicht so gut mit WordPress auskennen, sollten zumindest die Grundlagen von WordPress und guter Programmierung beherrschen. Ich werde nicht jedes mal darauf hinweisen das man normalerweise definitiv nicht <code>echo $_GET['blah'];</code> schreibt, sondern alles auf seine Richtigkeit und Gültigkeit in prüft. Dann mal los&#8230;</p>
<h4>Inhalt</h4>
<ol>
<li><a href="http://yoda.neun12.de/artikel-10/2">Die Vorraussetzungen</a></li>
<li><a href="http://yoda.neun12.de/artikel-10/3">Eleganter mit GET</a></li>
<li><a href="http://yoda.neun12.de/artikel-10/4">JavaScript mal ganz objektiv </a></li>
<li><a href="http://yoda.neun12.de/artikel-10/5">Mein Freund Jason</a></li>
<li><a href="http://yoda.neun12.de/artikel-10/6">Da gibt es doch bestimmt eine App für…?</a></li>
<li><a href="http://yoda.neun12.de/artikel-10/7">DIY – Jsonifice</a></li>
<li><a href="http://yoda.neun12.de/artikel-10/8">Und Action!</a></li>
<li><a href="http://yoda.neun12.de/artikel-10/9">Letzte Anmerkungen</a></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-10/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
