<?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</title>
	<atom:link href="http://yoda.neun12.de/feed" rel="self" type="application/rss+xml" />
	<link>http://yoda.neun12.de</link>
	<description>Debuggen du musst</description>
	<lastBuildDate>Sun, 01 Apr 2012 02:23:02 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<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>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 [...]]]></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><style type="text/css">@import "http://gist.github.com/stylesheets/gist/embed.css"; .gistem .highlight {background: inherit; !important;}</style><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>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 [...]]]></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>3</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>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 [...]]]></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>0</slash:comments>
		</item>
		<item>
		<title>Quick-Tipp: Schnell-Login</title>
		<link>http://yoda.neun12.de/artikel-52</link>
		<comments>http://yoda.neun12.de/artikel-52#comments</comments>
		<pubDate>Sun, 15 Jan 2012 05:34:41 +0000</pubDate>
		<dc:creator>Ralf</dc:creator>
				<category><![CDATA[Code-Snippets]]></category>
		<category><![CDATA[HowTo]]></category>
		<category><![CDATA[Plugin]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=52</guid>
		<description><![CDATA[Hin und wieder gibt es das Bedürfnis sich ohne Angabe von Benutzername und Passwort einzuloggen. Das könnte z.B. der Fall sein wenn man automatisierte Tests durchführen möchte die einen Login benötigen. Oder aber man muss zum Testen immer wieder den Benutzer wechseln um verschiedene Szenarien durchzuspielen. Aber auch wenn man sich in einer eher &#8220;unsicheren [...]]]></description>
			<content:encoded><![CDATA[<p>Hin und wieder gibt es das Bedürfnis sich ohne Angabe von Benutzername und Passwort einzuloggen. Das könnte z.B. der Fall sein wenn man automatisierte Tests durchführen möchte die einen Login benötigen. Oder aber man muss zum Testen immer wieder den Benutzer wechseln um verschiedene Szenarien durchzuspielen.<br />
Aber auch wenn man sich in einer eher &#8220;unsicheren Umgebung&#8221; befindet (z.B. schlecht abgesichertes öffentliches Netzwerk) möchte man vielleicht nicht so gerne seine Login-Daten eintippen. Es wäre also ganz praktisch wenn man sich (automatisiert) einloggen kann ohne ständig Login-Daten einzutippen.</p>
<p>WordPress lässt sich relativ einfach dazu bringen Login-Daten automatisiert anzunehmen. In erster Linie ist die Funktion <code>wp_signon()</code> dafür zuständig den Login durchzuführen. Dazu übergibt man ihr Benutzername und Passwort, die Funktion gibt daraufhin <code>true</code> zurück bzw. ein WordPress-Fehler-Objekt. Dies kann man bequem mit <code>is_wp_error()</code> abfragen und so mit nur wenigen Zeilen einen Login durchführen.<div class="gistem"><div id="gist-1529022" 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</span><span class="p">(</span> <span class="nb">dirname</span><span class="p">(</span><span class="k">__FILE__</span><span class="p">)</span> <span class="o">.</span> <span class="s1">&#39;/wp-load.php&#39;</span> <span class="p">);</span></div><div class='line' id='LC3'><span class="nx">is_wp_error</span><span class="p">(</span></div><div class='line' id='LC4'>	<span class="nx">wp_signon</span><span class="p">(</span></div><div class='line' id='LC5'>		  <span class="k">array</span><span class="p">(</span></div><div class='line' id='LC6'>			<span class="s1">&#39;user_login&#39;</span><span class="o">=&gt;</span><span class="s1">&#39;YourLoginName&#39;</span><span class="p">,</span></div><div class='line' id='LC7'>			<span class="s1">&#39;user_password&#39;</span><span class="o">=&gt;</span><span class="s1">&#39;YoUrAw3s0M3P455W0rD&#39;</span></div><div class='line' id='LC8'>			<span class="p">)</span> </div><div class='line' id='LC9'>		 <span class="p">)</span></div><div class='line' id='LC10'><span class="p">)</span> <span class="o">?</span> <span class="k">die</span><span class="p">(</span><span class="s1">&#39;Mooo... :(&#39;</span><span class="p">)</span> <span class="o">:</span> <span class="nx">wp_safe_redirect</span><span class="p">(</span> <span class="nx">admin_url</span><span class="p">()</span> <span class="p">);</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1529022/41c58a4015161cb71154d1fdb3f0c91a4da5d0e1/quicklogin.php" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1529022#file_quicklogin.php" style="float:right;margin-right:10px;color:#666">quicklogin.php</a>
            <a href="https://gist.github.com/1529022">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>Speichert man den Code in einer separaten Datei ab, so muss zuerst <code>wp-load.php</code> eingebunden werden um die WordPress-Funktionen verfügbar zu machen. Hier bitte auf den Pfad achten, iom Gist liegt die Datei im gleichen Verzeichnis wie <code>wp-load.php</code>.  Danach wird direkt <code>wp_signon()</code> mit einem Array aus Benutzername und Passwort gefüttert, welches wiederum direkt als Parameter an <code>is_wp_error()</code> übergeben wird.<br />
Durch Aufruf der Datei ist man direkt eingeloggt und wird ins Backend umgeleitet. Möchte man lieber ins Frontend umgeleitet werden, so ersetzt man einfach <code>admin_url()</code> durch <code>site_url()</code>.</p>
<p>Ich habe mir für meine Entwicklungsarbeit ein kleines Plugin geschrieben mit dem ich recht schnell zwischen verschiedenen Benutzern hin- und her wechseln kann. Dazu listet mir das Plugin auf der Login-Seite die Test-User auf, welche ich zuvor angelegt habe. Durch einen Klick auf einen entsprechenden User-Namen kann ich mich dann ohne Eingabe von Benutzername und Passwort anmelden. Auf Optik habe ich verzichtet, da es ein Werkzeug bei der Entwicklung ist. Wer mag, kann dem ganzen ja noch ein bisschen optischen Feinschliff verpassen.<br />
Das Plugin <a title="WP-Quicklogin" href="https://github.com/RalfAlbert/WP-Quicklogin">WP-Quicklogin</a> ist auf Github zu finden.</p>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-52/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WordPress Version testen</title>
		<link>http://yoda.neun12.de/artikel-58</link>
		<comments>http://yoda.neun12.de/artikel-58#comments</comments>
		<pubDate>Wed, 11 Jan 2012 08:14:42 +0000</pubDate>
		<dc:creator>Ralf</dc:creator>
				<category><![CDATA[Code-Snippets]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=58</guid>
		<description><![CDATA[Momentan habe ich es mir zur Aufgabe gemacht ein veraltetes Plugin auf eine neue Codebasis zu setzen (Refactoring). Um welches Plugin es sich dabei handelt, werde ich verraten wenn es in einem vorzeigbaren Zustand ist. Derzeit braucht es noch recht viel Arbeit. Dabei fallen aber immer wieder ein paar Sachen ab die ich für erwähnenswert [...]]]></description>
			<content:encoded><![CDATA[<p>Momentan habe ich es mir zur Aufgabe gemacht ein veraltetes Plugin auf eine neue Codebasis zu setzen (Refactoring). Um welches Plugin es sich dabei handelt, werde ich verraten wenn es in einem vorzeigbaren Zustand ist. Derzeit braucht es noch recht viel Arbeit.<br />
Dabei fallen aber immer wieder ein paar Sachen ab die ich für erwähnenswert halte. Mein <a title="define( RACE_CONDITION, TRUE ) – Das Rennen um die Konstanten" href="http://yoda.neun12.de/artikel-57">letzter Artikel</a> war übrigens auch das Ergebnis dieser Arbeit. Diesmal ist es eine Klasse mit der man die minimale WordPress- und PHP-Version testen kann (MySQL könnte man auch testen, ich denke aber das wird kaum jemand machen da es eher selten der Fall ist das man eine bestimmte MySQL-Version voraussetzt). Minimale Version bedeutet hierbei, man testet ob WordPress bzw. PHP mindestens Version X hat.<br />
Bei dem Tempo das Automattic bei der Entwickelung von WordPress an den Tag legt (alleine für dieses Jahr sind 3 Versionen geplant), wird es immer wichtiger zumindest zu  prüfen unter welcher WP-Version ein Plugin oder Theme aktiviert wird. Kann man natürlich auch sein lassen, wenn man den Anwender lieber mit Fehlermeldungen bzw. nicht funktionierenden Funktionen beglücken möchte. Ich persönlich halte es aber für empfehlenswert zu prüfen und ggf. auf eine zu niedrige Version hinzuweisen.</p>
<p>Die Klasse lässt sich vielfältig konfigurieren und flexibel einsetzen. Mit der statischen Methode <code>is_WP()</code> lässt sich z.B. prüfen ob WordPress bereits gestartet wurde. Ist dies nicht der Fall, werden 403-Header (forbidden) gesendet und das Script beendet. Dies ist z.B. nützlich um ein Script gegen direktes Aufrufen zu schützen.<br />
Bsp.:</p>
<pre class="brush:php">// beendet das Script falls WordPress nicht zuvor gestartet wurde
WP_Environment_Check::is_WP();</pre>
<p>Kern der Klasse sind allerdings die drei Methoden <code>check_wp()</code>, <code>check_php()</code> und <code>run_all_tests()</code> (die Methode <code>check_mysql()</code> ist, wie erwähnt, nur der Vollständigkeit halber dabei und dürfte eher selten Anwendung finden). Konfiguriert man ein Array oder ein Objekt mit den entsprechenden Werten und übergibt das Array bzw. Object der Methode <code>run_all_tests()</code>, so werden die entsprechenden Versionen geprüft und ggf. das Script beendet. Natürlich kann man auch nur einzelne Komponenten testen. Im Gist ist noch eine Datei mit einigen Beispielen, ich denke dadurch wird klar wie man die Klasse verwenden kann.<br />
Im Normalfall ruft man die Klasse beim Aktivieren des Plugins auf, so dass das Plugin erst gar nicht aktiviert wird.</p>
<p>Nun möchte man vielleicht nicht gleich mit dem Hammer zuschlagen und das Script beenden weil es sich um ein Theme und nicht um ein Plugin handelt. Dafür ist die Methode <code>set_die_on_fail()</code> nützlich. Übergibt man ihr den Wert <code>TRUE</code>, so wird das Script bei einen fehlerhaften Test nicht beendet, sondern <code>FALSE</code> als Rückgabewert zurück gegeben. Die Rückgabewerte kann man dann entsprechend auswerten und Meldungen ausgeben.</p>
<p>Falls man mit den Standardmeldungen nicht glücklich ist, kann man diese ebenfalls recht einfach anpassen. Einfach der Klasse einen neuen String übergeben. Das macht z.B. Übersetzungen der Fehlermeldungen recht einfach. Auch hierzu gibt es ein Beispiel im Gist.</p>
<p>Vielleicht findet der eine oder andere die Klasse ganz nützlich oder erweitert sie sogar. In beiden Fällen würde ich mich über Feedback natürlich freuen. Und hier noch der Gist zur Klasse und den Beispielen:<div class="gistem"><div id="gist-1593410" 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"> * Class to check the environment (WordPress-, PHP and MySQL-version)</span></div><div class='line' id='LC5'><span class="sd"> * Test only on minimum or equal version</span></div><div class='line' id='LC6'><span class="sd"> * </span></div><div class='line' id='LC7'><span class="sd"> * @author Ralf Albert</span></div><div class='line' id='LC8'><span class="sd"> * @version 1.0</span></div><div class='line' id='LC9'><span class="sd"> * </span></div><div class='line' id='LC10'><span class="sd"> * @var array|object $versions (optional) Array with key=&gt;val or object $version-&gt;wp|php|mysql; what to test =&gt; minimum version</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="k">class</span> <span class="nc">WP_Environment_Check</span></div><div class='line' id='LC14'><span class="p">{</span></div><div class='line' id='LC15'>	<span class="sd">/**</span></div><div class='line' id='LC16'><span class="sd">	 * </span></div><div class='line' id='LC17'><span class="sd">	 * WP version</span></div><div class='line' id='LC18'><span class="sd">	 * @access public</span></div><div class='line' id='LC19'><span class="sd">	 * @var string minimum or equal version of WordPress</span></div><div class='line' id='LC20'><span class="sd">	 */</span></div><div class='line' id='LC21'>	<span class="k">public</span> <span class="nv">$wp</span>	  <span class="o">=</span> <span class="s1">&#39;3.2&#39;</span><span class="p">;</span></div><div class='line' id='LC22'><br/></div><div class='line' id='LC23'>	<span class="sd">/**</span></div><div class='line' id='LC24'><span class="sd">	 * </span></div><div class='line' id='LC25'><span class="sd">	 * PHP version</span></div><div class='line' id='LC26'><span class="sd">	 * @access public</span></div><div class='line' id='LC27'><span class="sd">	 * @var string minimum or equal version of PHP</span></div><div class='line' id='LC28'><span class="sd">	 */</span></div><div class='line' id='LC29'>	<span class="k">public</span> <span class="nv">$php</span>   <span class="o">=</span> <span class="s1">&#39;5.2&#39;</span><span class="p">;</span></div><div class='line' id='LC30'><br/></div><div class='line' id='LC31'>	<span class="sd">/**</span></div><div class='line' id='LC32'><span class="sd">	 * </span></div><div class='line' id='LC33'><span class="sd">	 * MySQL version</span></div><div class='line' id='LC34'><span class="sd">	 * @access public</span></div><div class='line' id='LC35'><span class="sd">	 * @var string minimum or equal version of MySQL</span></div><div class='line' id='LC36'><span class="sd">	 */</span></div><div class='line' id='LC37'>	<span class="k">public</span> <span class="nv">$mysql</span> <span class="o">=</span> <span class="s1">&#39;5.0&#39;</span><span class="p">;</span></div><div class='line' id='LC38'><br/></div><div class='line' id='LC39'>	<span class="sd">/**</span></div><div class='line' id='LC40'><span class="sd">	 * </span></div><div class='line' id='LC41'><span class="sd">	 * Exit message if WordPress test failed</span></div><div class='line' id='LC42'><span class="sd">	 * @access public</span></div><div class='line' id='LC43'><span class="sd">	 * @var string</span></div><div class='line' id='LC44'><span class="sd">	 */</span></div><div class='line' id='LC45'>	<span class="k">public</span> <span class="nv">$exit_msg_wp</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="p">;</span></div><div class='line' id='LC46'><br/></div><div class='line' id='LC47'>	<span class="sd">/**</span></div><div class='line' id='LC48'><span class="sd">	 * </span></div><div class='line' id='LC49'><span class="sd">	 * Exit message if PHP test failed</span></div><div class='line' id='LC50'><span class="sd">	 * @access public</span></div><div class='line' id='LC51'><span class="sd">	 * @var string</span></div><div class='line' id='LC52'><span class="sd">	 */</span></div><div class='line' id='LC53'>	<span class="k">public</span> <span class="nv">$exit_msg_php</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="p">;</span></div><div class='line' id='LC54'><br/></div><div class='line' id='LC55'>	<span class="sd">/**</span></div><div class='line' id='LC56'><span class="sd">	 * </span></div><div class='line' id='LC57'><span class="sd">	 * Exit message if MySQL test failed</span></div><div class='line' id='LC58'><span class="sd">	 * @access public</span></div><div class='line' id='LC59'><span class="sd">	 * @var string</span></div><div class='line' id='LC60'><span class="sd">	 */</span></div><div class='line' id='LC61'>	<span class="k">public</span> <span class="nv">$exit_msg_mysql</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="p">;</span></div><div class='line' id='LC62'><br/></div><div class='line' id='LC63'>	<span class="sd">/**</span></div><div class='line' id='LC64'><span class="sd">	 * </span></div><div class='line' id='LC65'><span class="sd">	 * If set to true, the class will die with a message if a WP|PHP|MySQL test fail.</span></div><div class='line' id='LC66'><span class="sd">	 * Does not affect is_WP() or if forbidden_headers() is called withot a message </span></div><div class='line' id='LC67'><span class="sd">	 * @access public static</span></div><div class='line' id='LC68'><span class="sd">	 * @var bool true (default)|false</span></div><div class='line' id='LC69'><span class="sd">	 */</span></div><div class='line' id='LC70'>	<span class="k">public</span> <span class="k">static</span> <span class="nv">$die_on_fail</span> <span class="o">=</span> <span class="k">TRUE</span><span class="p">;</span></div><div class='line' id='LC71'><br/></div><div class='line' id='LC72'>	<span class="sd">/**</span></div><div class='line' id='LC73'><span class="sd">	 * </span></div><div class='line' id='LC74'><span class="sd">	 * Constructor</span></div><div class='line' id='LC75'><span class="sd">	 * Run all test that are defined in $version</span></div><div class='line' id='LC76'><span class="sd">	 * @access public </span></div><div class='line' id='LC77'><span class="sd">	 * @param array|object $versions</span></div><div class='line' id='LC78'><span class="sd">	 */</span></div><div class='line' id='LC79'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">__construct</span><span class="p">(</span> <span class="nv">$versions</span> <span class="o">=</span> <span class="k">NULL</span> <span class="p">){</span></div><div class='line' id='LC80'>		<span class="nx">self</span><span class="o">::</span><span class="na">is_WP</span><span class="p">();</span></div><div class='line' id='LC81'><br/></div><div class='line' id='LC82'>		<span class="k">if</span><span class="p">(</span> <span class="o">!</span> <span class="k">empty</span><span class="p">(</span> <span class="nv">$versions</span> <span class="p">)</span> <span class="o">||</span> <span class="p">(</span> <span class="nb">is_array</span><span class="p">(</span> <span class="nv">$versions</span> <span class="p">)</span> <span class="o">||</span> <span class="nb">is_object</span><span class="p">(</span> <span class="nv">$versions</span> <span class="p">)</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC83'>			<span class="nv">$this</span><span class="o">-&gt;</span><span class="na">run_all_tests</span><span class="p">(</span> <span class="nv">$versions</span> <span class="p">);</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="sd">/**</span></div><div class='line' id='LC87'><span class="sd">	 * </span></div><div class='line' id='LC88'><span class="sd">	 * Set $die_on_fail</span></div><div class='line' id='LC89'><span class="sd">	 * @param bool $status True exits the script with a message </span></div><div class='line' id='LC90'><span class="sd">	 */</span></div><div class='line' id='LC91'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">set_die_on_fail</span><span class="p">(</span> <span class="nv">$status</span> <span class="o">=</span> <span class="k">TRUE</span> <span class="p">){</span></div><div class='line' id='LC92'>		<span class="k">if</span><span class="p">(</span> <span class="o">!</span> <span class="nb">is_bool</span><span class="p">(</span> <span class="nv">$status</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC93'>			<span class="nv">$status</span> <span class="o">=</span> <span class="p">(</span><span class="nx">bool</span><span class="p">)</span> <span class="nv">$status</span><span class="p">;</span></div><div class='line' id='LC94'><br/></div><div class='line' id='LC95'>		<span class="nx">self</span><span class="o">::</span><span class="nv">$die_on_fail</span> <span class="o">=</span> <span class="nv">$status</span><span class="p">;</span></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">	 * Check if WordPress is active (if $wp is an object of class wp() )</span></div><div class='line' id='LC101'><span class="sd">	 * @access public static</span></div><div class='line' id='LC102'><span class="sd">	 * @return bool true|die with message and send forbidden-headers if WP is not active</span></div><div class='line' id='LC103'><span class="sd">	 */</span></div><div class='line' id='LC104'>	<span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">is_WP</span><span class="p">(){</span></div><div class='line' id='LC105'>		<span class="k">global</span> <span class="nv">$wp</span><span class="p">;</span></div><div class='line' id='LC106'><br/></div><div class='line' id='LC107'>		<span class="k">if</span><span class="p">(</span> <span class="o">!</span> <span class="nv">$wp</span> <span class="nx">instanceof</span> <span class="nx">WP</span> <span class="p">)</span></div><div class='line' id='LC108'>			<span class="nx">self</span><span class="o">::</span><span class="na">forbidden_header</span><span class="p">();</span></div><div class='line' id='LC109'>		<span class="k">else</span></div><div class='line' id='LC110'>			<span class="k">return</span> <span class="k">TRUE</span><span class="p">;</span></div><div class='line' id='LC111'>	<span class="p">}</span></div><div class='line' id='LC112'><br/></div><div class='line' id='LC113'>	<span class="sd">/**</span></div><div class='line' id='LC114'><span class="sd">	 * </span></div><div class='line' id='LC115'><span class="sd">	 * Run all tests</span></div><div class='line' id='LC116'><span class="sd">	 * @access public</span></div><div class='line' id='LC117'><span class="sd">	 * @param array|object $versions</span></div><div class='line' id='LC118'><span class="sd">	 * @return bool true if all tests passed successfully</span></div><div class='line' id='LC119'><span class="sd">	 */</span></div><div class='line' id='LC120'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">run_all_tests</span><span class="p">(</span> <span class="nv">$versions</span> <span class="o">=</span> <span class="k">NULL</span> <span class="p">){</span></div><div class='line' id='LC121'>		<span class="k">if</span><span class="p">(</span> <span class="k">empty</span><span class="p">(</span> <span class="nv">$versions</span> <span class="p">)</span> <span class="o">||</span> <span class="p">(</span> <span class="o">!</span> <span class="nb">is_array</span><span class="p">(</span> <span class="nv">$versions</span> <span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="o">!</span> <span class="nb">is_object</span><span class="p">(</span> <span class="nv">$versions</span> <span class="p">)</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC122'>			<span class="k">return</span> <span class="k">FALSE</span><span class="p">;</span></div><div class='line' id='LC123'><br/></div><div class='line' id='LC124'>		<span class="nv">$tests</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span> <span class="s1">&#39;wp&#39;</span><span class="p">,</span> <span class="s1">&#39;php&#39;</span><span class="p">,</span> <span class="s1">&#39;mysql&#39;</span> <span class="p">);</span></div><div class='line' id='LC125'><br/></div><div class='line' id='LC126'>		<span class="k">foreach</span><span class="p">(</span> <span class="nv">$versions</span> <span class="k">as</span> <span class="nv">$test</span> <span class="o">=&gt;</span> <span class="nv">$version</span> <span class="p">){</span></div><div class='line' id='LC127'>			<span class="c1">// check if the wanted test is available (means: is the test x a method &#39;check_x&#39;)</span></div><div class='line' id='LC128'>			<span class="k">if</span><span class="p">(</span> <span class="nb">in_array</span><span class="p">(</span> <span class="nx">strtolower</span><span class="p">(</span> <span class="nv">$test</span> <span class="p">),</span> <span class="nv">$tests</span> <span class="p">)</span> <span class="p">){</span></div><div class='line' id='LC129'>				<span class="nv">$method</span> <span class="o">=</span> <span class="nx">strtolower</span><span class="p">(</span> <span class="nv">$test</span> <span class="p">);</span></div><div class='line' id='LC130'>				<span class="nv">$func</span> <span class="o">=</span> <span class="s1">&#39;check_&#39;</span> <span class="o">.</span> <span class="nv">$test</span><span class="p">;</span> <span class="c1">// create the method (check_wp|check_php|check_mysql)</span></div><div class='line' id='LC131'>				<span class="nv">$this</span><span class="o">-&gt;</span><span class="nv">$method</span> <span class="o">=</span> <span class="nv">$version</span><span class="p">;</span> <span class="c1">// set $this-&gt;wp|php|mysql to version x</span></div><div class='line' id='LC132'><br/></div><div class='line' id='LC133'>				<span class="k">if</span><span class="p">(</span> <span class="o">!</span> <span class="nb">call_user_func</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="nv">$func</span> <span class="p">)</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC134'>					<span class="k">die</span><span class="p">(</span> <span class="s1">&#39;Test &#39;</span> <span class="o">.</span> <span class="nx">__CLASS__</span> <span class="o">.</span> <span class="s1">&#39;::&#39;</span> <span class="o">.</span> <span class="nv">$func</span> <span class="o">.</span> <span class="s1">&#39; failed!&#39;</span> <span class="p">);</span> <span class="c1">// this should never happen...</span></div><div class='line' id='LC135'>			<span class="p">}</span></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="k">return</span> <span class="k">TRUE</span><span class="p">;</span></div><div class='line' id='LC139'>	<span class="p">}</span></div><div class='line' id='LC140'><br/></div><div class='line' id='LC141'>	<span class="sd">/**</span></div><div class='line' id='LC142'><span class="sd">	 * </span></div><div class='line' id='LC143'><span class="sd">	 * Check WordPress version</span></div><div class='line' id='LC144'><span class="sd">	 * @access public</span></div><div class='line' id='LC145'><span class="sd">	 * @return bool true returns true if the test passed successfully. Die with a message if not.</span></div><div class='line' id='LC146'><span class="sd">	 */</span></div><div class='line' id='LC147'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">check_wp</span><span class="p">(){</span></div><div class='line' id='LC148'>		<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">wp</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC149'>			<span class="k">return</span> <span class="k">FALSE</span><span class="p">;</span></div><div class='line' id='LC150'><br/></div><div class='line' id='LC151'>		<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">exit_msg_wp</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC152'>			<span class="nv">$this</span><span class="o">-&gt;</span><span class="na">exit_msg_wp</span> <span class="o">=</span> <span class="s1">&#39;This plugin requires WordPress &#39;</span> <span class="o">.</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">wp</span> <span class="o">.</span> <span class="s1">&#39; or newer. &lt;a href=&quot;http://codex.wordpress.org/Upgrading_WordPress&quot;&gt;Please update WordPress&lt;/a&gt; or delete the plugin.&#39;</span><span class="p">;</span></div><div class='line' id='LC153'><br/></div><div class='line' id='LC154'>		<span class="k">global</span> <span class="nv">$wp_version</span><span class="p">;</span></div><div class='line' id='LC155'>		<span class="k">if</span><span class="p">(</span> <span class="o">!</span> <span class="nb">version_compare</span><span class="p">(</span> <span class="nv">$wp_version</span><span class="p">,</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">wp</span><span class="p">,</span> <span class="s1">&#39;&gt;=&#39;</span> <span class="p">)</span> <span class="p">){</span></div><div class='line' id='LC156'>			<span class="k">return</span> <span class="nx">self</span><span class="o">::</span><span class="na">forbidden_header</span><span class="p">(</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">exit_msg_wp</span> <span class="p">);</span></div><div class='line' id='LC157'>		<span class="p">}</span></div><div class='line' id='LC158'><br/></div><div class='line' id='LC159'>		<span class="k">return</span> <span class="k">TRUE</span><span class="p">;</span></div><div class='line' id='LC160'>	<span class="p">}</span></div><div class='line' id='LC161'><br/></div><div class='line' id='LC162'>	<span class="sd">/**</span></div><div class='line' id='LC163'><span class="sd">	 * </span></div><div class='line' id='LC164'><span class="sd">	 * Check PHP version</span></div><div class='line' id='LC165'><span class="sd">	 * @access public</span></div><div class='line' id='LC166'><span class="sd">	 * @return bool true|die with message</span></div><div class='line' id='LC167'><span class="sd">	 */</span></div><div class='line' id='LC168'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">check_php</span><span class="p">(){</span></div><div class='line' id='LC169'>		<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">php</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC170'>			<span class="k">return</span> <span class="k">FALSE</span><span class="p">;</span></div><div class='line' id='LC171'><br/></div><div class='line' id='LC172'>		<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">exit_msg_php</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC173'>			<span class="nv">$this</span><span class="o">-&gt;</span><span class="na">exit_msg_php</span> <span class="o">=</span> <span class="s1">&#39;This plugin requires at least PHP version &lt;strong&gt;&#39;</span> <span class="o">.</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">php</span> <span class="o">.</span> <span class="s1">&#39;&lt;/strong&gt;&#39;</span><span class="p">;</span> </div><div class='line' id='LC174'><br/></div><div class='line' id='LC175'>		<span class="k">if</span><span class="p">(</span> <span class="o">!</span> <span class="nb">version_compare</span><span class="p">(</span> <span class="k">PHP_VERSION</span><span class="p">,</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">php</span><span class="p">,</span> <span class="s1">&#39;&gt;=&#39;</span> <span class="p">)</span> <span class="p">){</span></div><div class='line' id='LC176'>			<span class="k">return</span> <span class="nx">self</span><span class="o">::</span><span class="na">forbidden_header</span><span class="p">(</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">exit_msg_php</span> <span class="p">);</span></div><div class='line' id='LC177'>		<span class="p">}</span></div><div class='line' id='LC178'><br/></div><div class='line' id='LC179'>		<span class="k">return</span> <span class="k">TRUE</span><span class="p">;</span></div><div class='line' id='LC180'>	<span class="p">}</span></div><div class='line' id='LC181'><br/></div><div class='line' id='LC182'>	<span class="sd">/**</span></div><div class='line' id='LC183'><span class="sd">	 * </span></div><div class='line' id='LC184'><span class="sd">	 * Check MYSQL version</span></div><div class='line' id='LC185'><span class="sd">	 * @access public</span></div><div class='line' id='LC186'><span class="sd">	 * @return bool true|die with message</span></div><div class='line' id='LC187'><span class="sd">	 */</span></div><div class='line' id='LC188'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">check_mysql</span><span class="p">(){</span></div><div class='line' id='LC189'>		<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">mysql</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC190'>			<span class="k">return</span> <span class="k">FALSE</span><span class="p">;</span></div><div class='line' id='LC191'><br/></div><div class='line' id='LC192'>		<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">exit_msg_mysql</span> <span class="p">)</span> <span class="p">)</span></div><div class='line' id='LC193'>			<span class="nv">$this</span><span class="o">-&gt;</span><span class="na">exit_msg_mysql</span> <span class="o">=</span> <span class="s1">&#39;This plugin requires at least MySQL version &lt;strong&gt;&#39;</span> <span class="o">.</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mysql</span> <span class="o">.</span> <span class="s1">&#39;&lt;/strong&gt;&#39;</span><span class="p">;</span></div><div class='line' id='LC194'><br/></div><div class='line' id='LC195'>		<span class="k">global</span> <span class="nv">$wpdb</span><span class="p">;</span></div><div class='line' id='LC196'>		<span class="k">if</span><span class="p">(</span> <span class="o">!</span> <span class="nb">version_compare</span><span class="p">(</span> <span class="nv">$wpdb</span><span class="o">-&gt;</span><span class="na">db_version</span><span class="p">(),</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mysql</span><span class="p">,</span> <span class="s1">&#39;&gt;=&#39;</span> <span class="p">)</span> <span class="p">){</span></div><div class='line' id='LC197'>			<span class="k">return</span> <span class="nx">self</span><span class="o">::</span><span class="na">forbidden_header</span><span class="p">(</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">exit_msg_mysql</span> <span class="p">);</span></div><div class='line' id='LC198'>		<span class="p">}</span></div><div class='line' id='LC199'><br/></div><div class='line' id='LC200'>		<span class="k">return</span> <span class="k">TRUE</span><span class="p">;</span></div><div class='line' id='LC201'>	<span class="p">}</span></div><div class='line' id='LC202'><br/></div><div class='line' id='LC203'>	<span class="sd">/**</span></div><div class='line' id='LC204'><span class="sd">	 * </span></div><div class='line' id='LC205'><span class="sd">	 * Send forbidden-headers (403) if no message is set. Only dies if a message is set</span></div><div class='line' id='LC206'><span class="sd">	 * @access public static</span></div><div class='line' id='LC207'><span class="sd">	 * @param string (optional) $exit_msg</span></div><div class='line' id='LC208'><span class="sd">	 */</span></div><div class='line' id='LC209'>	<span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">forbidden_header</span><span class="p">(</span> <span class="nv">$exit_msg</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span> <span class="p">){</span></div><div class='line' id='LC210'><br/></div><div class='line' id='LC211'>		<span class="k">if</span><span class="p">(</span> <span class="k">empty</span><span class="p">(</span> <span class="nv">$exit_msg</span> <span class="p">)</span> <span class="p">){</span></div><div class='line' id='LC212'>			<span class="nx">header</span><span class="p">(</span> <span class="s1">&#39;Status: 403 Forbidden&#39;</span> <span class="p">);</span></div><div class='line' id='LC213'>			<span class="nx">header</span><span class="p">(</span> <span class="s1">&#39;HTTP/1.1 403 Forbidden&#39;</span> <span class="p">);</span></div><div class='line' id='LC214'>			<span class="k">die</span><span class="p">(</span> <span class="s2">&quot;I&#39;m sorry Dave, I&#39;m afraid I can&#39;t do that.&quot;</span> <span class="p">);</span></div><div class='line' id='LC215'>		<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>		</div><div class='line' id='LC216'>			<span class="k">if</span><span class="p">(</span> <span class="k">FALSE</span> <span class="o">===</span> <span class="nx">self</span><span class="o">::</span><span class="nv">$die_on_fail</span> <span class="p">)</span></div><div class='line' id='LC217'>				<span class="k">return</span> <span class="k">FALSE</span><span class="p">;</span></div><div class='line' id='LC218'>			<span class="k">else</span>			</div><div class='line' id='LC219'>				<span class="k">die</span><span class="p">(</span> <span class="nv">$exit_msg</span> <span class="p">);</span></div><div class='line' id='LC220'>		<span class="p">}</span></div><div class='line' id='LC221'>	<span class="p">}</span>	</div><div class='line' id='LC222'><span class="p">}</span></div><div class='line' id='LC223'><br/></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1593410/e3c8391441bffc740bc2e95add72ebce5b6ed944/_wp_environment_check.php" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1593410#file__wp_environment_check.php" style="float:right;margin-right:10px;color:#666">_wp_environment_check.php</a>
            <a href="https://gist.github.com/1593410">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="cm">/*</span></div><div class='line' id='LC3'><span class="cm"> * Mocking</span></div><div class='line' id='LC4'><span class="cm"> */</span></div><div class='line' id='LC5'><span class="k">class</span> <span class="nc">WP</span><span class="p">{}</span></div><div class='line' id='LC6'><span class="nv">$wp</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WP</span><span class="p">;</span></div><div class='line' id='LC7'><br/></div><div class='line' id='LC8'><span class="k">class</span> <span class="nc">WPDB</span></div><div class='line' id='LC9'><span class="p">{</span></div><div class='line' id='LC10'>	<span class="k">public</span> <span class="k">function</span> <span class="nf">db_version</span><span class="p">(){</span></div><div class='line' id='LC11'>		<span class="k">return</span> <span class="s1">&#39;5.1&#39;</span><span class="p">;</span></div><div class='line' id='LC12'>	<span class="p">}</span></div><div class='line' id='LC13'><span class="p">}</span></div><div class='line' id='LC14'><span class="nv">$wpdb</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WPDB</span><span class="p">();</span></div><div class='line' id='LC15'><br/></div><div class='line' id='LC16'><span class="nv">$wp_version</span> <span class="o">=</span> <span class="s1">&#39;3.3.1&#39;</span><span class="p">;</span></div><div class='line' id='LC17'><span class="cm">/* end mocking */</span></div><div class='line' id='LC18'><br/></div><div class='line' id='LC19'><span class="cm">/*</span></div><div class='line' id='LC20'><span class="cm"> * Creating an instance ov WP_Environment_Check</span></div><div class='line' id='LC21'><span class="cm"> * Setup the minimum versions</span></div><div class='line' id='LC22'><span class="cm"> * Setup an exit-message if the WordPress test fail</span></div><div class='line' id='LC23'><span class="cm"> * Performs every single test one by one  </span></div><div class='line' id='LC24'><span class="cm"> */</span></div><div class='line' id='LC25'><br/></div><div class='line' id='LC26'><span class="nv">$a</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WP_Environment_Check</span><span class="p">();</span></div><div class='line' id='LC27'><span class="nv">$a</span><span class="o">-&gt;</span><span class="na">wp</span> <span class="o">=</span> <span class="s1">&#39;3.3.1&#39;</span><span class="p">;</span></div><div class='line' id='LC28'><span class="nv">$a</span><span class="o">-&gt;</span><span class="na">php</span> <span class="o">=</span> <span class="s1">&#39;5.2&#39;</span><span class="p">;</span></div><div class='line' id='LC29'><span class="nv">$a</span><span class="o">-&gt;</span><span class="na">mysql</span> <span class="o">=</span> <span class="s1">&#39;5.1&#39;</span><span class="p">;</span></div><div class='line' id='LC30'><span class="nv">$a</span><span class="o">-&gt;</span><span class="na">exit_msg_wp</span> <span class="o">=</span> <span class="s1">&#39;The plugin &lt;em&gt;&lt;a href=&quot;http://example.com/my_plugin/&quot;&gt;Acme Plugin&lt;/a&gt;&lt;/em&gt; requires WordPress &#39;</span> <span class="o">.</span> <span class="nv">$a</span><span class="o">-&gt;</span><span class="na">wp</span> <span class="o">.</span> <span class="s1">&#39; or newer. &lt;a href=&quot;http://codex.wordpress.org/Upgrading_WordPress&quot;&gt;Please update WordPress&lt;/a&gt; or delete the plugin.&#39;</span><span class="p">;</span></div><div class='line' id='LC31'><span class="nv">$a</span><span class="o">-&gt;</span><span class="na">check_wp</span><span class="p">();</span></div><div class='line' id='LC32'><span class="nv">$a</span><span class="o">-&gt;</span><span class="na">check_php</span><span class="p">();</span></div><div class='line' id='LC33'><span class="nv">$a</span><span class="o">-&gt;</span><span class="na">check_mysql</span><span class="p">();</span></div><div class='line' id='LC34'><br/></div><div class='line' id='LC35'><span class="cm">/*</span></div><div class='line' id='LC36'><span class="cm"> * Creating an object with the minimum versions</span></div><div class='line' id='LC37'><span class="cm"> * Create an instance of WP_Environment_Check</span></div><div class='line' id='LC38'><span class="cm"> * Performs all tests at once</span></div><div class='line' id='LC39'><span class="cm"> */</span></div><div class='line' id='LC40'><br/></div><div class='line' id='LC41'><span class="nv">$v</span> <span class="o">=</span> <span class="k">new</span> <span class="k">stdClass</span><span class="p">();</span></div><div class='line' id='LC42'><span class="nv">$v</span><span class="o">-&gt;</span><span class="na">wp</span> <span class="o">=</span> <span class="s1">&#39;3.3.1&#39;</span><span class="p">;</span></div><div class='line' id='LC43'><span class="nv">$v</span><span class="o">-&gt;</span><span class="na">php</span> <span class="o">=</span> <span class="s1">&#39;5.2&#39;</span><span class="p">;</span></div><div class='line' id='LC44'><span class="nv">$v</span><span class="o">-&gt;</span><span class="na">mysql</span> <span class="o">=</span> <span class="s1">&#39;5.0&#39;</span><span class="p">;</span></div><div class='line' id='LC45'><span class="nv">$a</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WP_Environment_Check</span><span class="p">();</span></div><div class='line' id='LC46'><br/></div><div class='line' id='LC47'><span class="nv">$a</span><span class="o">-&gt;</span><span class="na">run_all_tests</span><span class="p">(</span> <span class="nv">$v</span> <span class="p">);</span></div><div class='line' id='LC48'><br/></div><div class='line' id='LC49'><br/></div><div class='line' id='LC50'><span class="cm">/*</span></div><div class='line' id='LC51'><span class="cm"> * Setup an array with the minimum versions</span></div><div class='line' id='LC52'><span class="cm"> * Performs all test by creating an instance of WP_Environment_Check</span></div><div class='line' id='LC53'><span class="cm"> */</span></div><div class='line' id='LC54'><br/></div><div class='line' id='LC55'><span class="nv">$v</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span> <span class="s1">&#39;wp&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;3.0&#39;</span><span class="p">,</span> <span class="s1">&#39;php&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;5.2&#39;</span><span class="p">,</span> <span class="s1">&#39;MySQL&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;5.1&#39;</span> <span class="p">);</span></div><div class='line' id='LC56'><span class="nv">$a</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WP_Environment_Check</span><span class="p">(</span> <span class="nv">$v</span> <span class="p">);</span></div><div class='line' id='LC57'><br/></div><div class='line' id='LC58'><span class="cm">/*</span></div><div class='line' id='LC59'><span class="cm"> * Store testresult in an object. Disable dying if tests failed</span></div><div class='line' id='LC60'><span class="cm"> */</span></div><div class='line' id='LC61'><br/></div><div class='line' id='LC62'><span class="nv">$a</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WP_Environment_Check</span><span class="p">();</span></div><div class='line' id='LC63'><span class="nv">$a</span><span class="o">-&gt;</span><span class="na">set_die_on_fail</span><span class="p">(</span> <span class="k">FALSE</span> <span class="p">);</span></div><div class='line' id='LC64'><span class="nv">$a</span><span class="o">-&gt;</span><span class="na">wp</span> <span class="o">=</span> <span class="s1">&#39;3.3.1&#39;</span><span class="p">;</span></div><div class='line' id='LC65'><span class="nv">$a</span><span class="o">-&gt;</span><span class="na">php</span> <span class="o">=</span> <span class="s1">&#39;5.2&#39;</span><span class="p">;</span></div><div class='line' id='LC66'><span class="nv">$a</span><span class="o">-&gt;</span><span class="na">mysql</span> <span class="o">=</span> <span class="s1">&#39;7.0&#39;</span><span class="p">;</span></div><div class='line' id='LC67'><br/></div><div class='line' id='LC68'><span class="nv">$r</span> <span class="o">=</span> <span class="k">new</span> <span class="k">stdClass</span><span class="p">();</span></div><div class='line' id='LC69'><br/></div><div class='line' id='LC70'><span class="nv">$r</span><span class="o">-&gt;</span><span class="na">wp</span> <span class="o">=</span> <span class="nv">$a</span><span class="o">-&gt;</span><span class="na">check_wp</span><span class="p">();</span></div><div class='line' id='LC71'><span class="nv">$r</span><span class="o">-&gt;</span><span class="na">php</span> <span class="o">=</span> <span class="nv">$a</span><span class="o">-&gt;</span><span class="na">check_php</span><span class="p">();</span></div><div class='line' id='LC72'><span class="nv">$r</span><span class="o">-&gt;</span><span class="na">mysql</span> <span class="o">=</span> <span class="nv">$a</span><span class="o">-&gt;</span><span class="na">check_mysql</span><span class="p">();</span> <span class="c1">// fail on MYSQL -&gt; &#39;mysql&#39; =&gt; false</span></div><div class='line' id='LC73'><br/></div><div class='line' id='LC74'><span class="nb">var_dump</span><span class="p">(</span> <span class="nv">$r</span> <span class="p">);</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1593410/74c2b4589e02c653cc798f9ba382e9e6443a3c3d/wp_environment_check-test.php" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1593410#file_wp_environment_check_test.php" style="float:right;margin-right:10px;color:#666">wp_environment_check-test.php</a>
            <a href="https://gist.github.com/1593410">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>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-58/feed</wfw:commentRss>
		<slash:comments>0</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>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 [...]]]></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>Performance ist nicht gleich Performance</title>
		<link>http://yoda.neun12.de/artikel-54</link>
		<comments>http://yoda.neun12.de/artikel-54#comments</comments>
		<pubDate>Fri, 06 Jan 2012 18:10:44 +0000</pubDate>
		<dc:creator>Ralf</dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Plugin]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=54</guid>
		<description><![CDATA[Ich bin kein großer Fan von Performance-Tests, dass sage ich gleich vorweg. Der Grund ist schlichtweg der, dass man vergleichbare Umgebungen voraussetzen muss um die Ergebnisse übertragbar zu machen. Wenn ich Plugin auf System A teste, rennt es noch wie doof. Teste ich es aber auf System B, hinkt und hakt es wie ein lahmer [...]]]></description>
			<content:encoded><![CDATA[<p>Ich bin kein großer Fan von Performance-Tests, dass sage ich gleich vorweg. Der Grund ist schlichtweg der, dass man vergleichbare Umgebungen voraussetzen muss um die Ergebnisse übertragbar zu machen. Wenn ich Plugin auf System A teste, rennt es noch wie doof. Teste ich es aber auf System B, hinkt und hakt es wie ein lahmer Gaul.<br />
Der Grund dafür liegt in der Optimierung der Systeme, sofern sie optimiert sind. Als Beispiel möchte ich nur die Anbindung an den MySQL-Server nennen. Hier gibt es etliche verschiedene Konfigurationen für die unterschiedlichsten Anwendungsfälle. Werden viele kleine Datensätze abgefragt, optimiert man den MySQL-Server anders als wenn man ihn für wenige große Datensätze benötigt. Somit würde das gleiche Plugin auf beiden Systemen unterschiedlich performant sein, alleine deshalb weil die Anbindung an die Datenbank anders ist.<br />
Nicht viel anders sieht es beim Server selber aus. Auch hier gibt es unzählige Optimierungsvarianten. Hinzu kommt noch unterschiedliche Server-Software, Betriebssysteme auf denen der Server läuft bis hin zu der Hardware die einen sehr wesentlichen Teil der Performance ausmacht. Wie soll man da einen gemeinsamen Nenner finden den man als Grundlage des Vergleichs heranziehen kann?</p>
<p>Viele Tests messen einfach das, was man einfach messen kann. Das wäre dann z.B. der Speicherverbrauch. Dann wird auch gerne die Ausführungszeit gemessen, was aber aufgrund der unterschiedlichen Systeme schon kaum noch Aussagekraft hat. Reicht das alles nicht, kommen gerne noch so obskure Faktoren wie Codezeilen oder Anzahl der verwendeten Hooks und Filter hinzu.<br />
Selten bis gar nicht wird die Code-Qualität bewertet. Dies ist für mich aber ein sehr wichtiges Kriterium. Denn ein schlampig programmiertes Plugin läuft oft auch schlampig, wirft Fehlermeldungen und ist nicht zukunftssicher. Häufig sieht man Plugins die über die Jahre gewachsen sind bis der Autor selber den Überblick verliert. Entweder wird das Plugin dann von Grund auf neu programmiert und weiter gepflegt. Oder aber, was häufiger vorkommt, man lässt das Plugin so wie es ist und kümmert sich nicht mehr darum.<br />
Nun ist Code-Qualität nicht ganz so einfach zu &#8220;messen&#8221;. Man muss den Code bewerten und hierzu eine Reihe von Kriterien heranziehen. das kostet Zeit und Mühe, weshalb es wohl niemand macht. Ein Kriterium wären zum Beispiel die Übersichtlichkeit. Das kann eigentlich jeder bewerten der sich den Code anschaut. Oder aber auch ob der Code ein Wust aus wilden Zeilen darstellt die kaum entzifferbar sind. Ist der Code gut kommentiert damit auch jemand der nicht so viel Ahnung von Programmierung hat versteht was da vor sich geht. Hält der Code sich an gewisse Programmierrichtlinien. Nur um mal einige wenige Kriterien zu nenne die man verwenden kann.<br />
All das kann man mit Noten bewerten, sogar relativ objektiv. Nun werden einige sagen &#8220;<em>Hauptsache es rennt!</em>&#8220;. Das ist natürlich auch ein Argument. Also zieht man noch die Anzahl an Fehlern, Notices usw. heran die das Plugin wirft wenn man es einsetzt. Auch grausam geschriebener Code kann fehlerfrei laufen. So kommt man schon zu einen recht guten und nachvollziehbaren Ergebnis.<br />
Kennt man sich bei der Programmierung ein wenig besser aus, dann kann man auch noch einzelne Code-Abschnitte genauer unter die Lupe nehmen. Ist der Code gemäß den empfohlenen Vorgaben geschrieben? Wenn nicht, macht es Sinn von den Vorgaben abzuweichen? Gibt es &#8220;merkwürdige&#8221; Programmiertechniken im Code oder ist alles auf den ersten Blick verständlich?</p>
<p>Für mich sind dies deutlich wichtigere Faktoren als Millisekunden Laufzeit und Megabyte Speicherverbrauch. Denn dies sind Faktoren die ich erklären kann, so dass auch jemand der weniger Ahnung hat versteht wie ich zu meinen Testergebnis gekommen bin. Und vor allem wird schnell deutlich wo noch Potenzial für Verbesserungen besteht. Code der leicht verständlich ist, wird auch gerne von anderen gepflegt, so dass er sich recht schnell verbreitet und mit der Zeit (hoffentlich) besser wird.</p>
<p>Ein ziemlich merkwürdiger Test macht hingegen gerade auf <a title="G+" href="https://plus.google.com/110569673423509816572/posts/bdbhLMhuaBU">Google+</a> die Runde. Es geht um den <a title="Dev4Press" href="http://www.dev4press.com/2012/blog/benchmark/plugins-performance-testing-2012-january/">Plugin-Test von MillaN</a>. <a title="Sergej Müller" href="http://ebiene.de/">Sergej Müller</a> hat sich wohl zurecht gefragt wie MillaN auf seine Ergebnisse kommt. Getestet wurden 35 Plugins aus den unterschiedlichsten Kategorien und mit einem Wert von 1 (schlecht) bis 5 (sehr gut) bewertet. Nur wie dieser Wert zustande kommt, bleibt vielen vollkommen unergründlich.<br />
Vielleicht ist weniger Speicherverbrauch besser als mehr? Also <a title="FPW Post Instructions" href="http://wordpress.org/extend/plugins/fpw-post-instructions/">FPW Post Instructions</a> bekommt eine 4 bei einem konstanten Speicherverbrauch von 0,1MB. GD Press Tools Pro verbraucht zwar 29 mal so viel Speicher (2,9MB), bekommt aber die Bestnote 5. Es scheint also etwas mit dem Speicherverbrauch im Frontend bzw. Backend zu tun zu haben. Denn GD Press Tools Pro verbraucht im Frontend &#8220;nur&#8221; 2MB Speicher, während FPW Post Instructions sowohl vorne wie hinten den gleichen Speicherverbrauch hat. So wirklich schlüssig ist das Konzept jedoch nicht. Denn <a title="WP Event Manager" href="http://wp-events-plugin.com/">Event Manager</a> bekommt die schlechteste Note 1 bei einem Speicherverbrauch von 5 bzw 3,7MB (Front-/Backend). GD Custom Posts And Taxonomies Tools Lite bekommt für die gleiche Leistung (1,5/1,3MB) eine noch ganz gute 4 verpasst. Event Manager ist also schlechter obwohl es mehr Speicher einspart?<br />
Ich könnte jetzt noch weiter rätseln ob es vielleicht an der Ausführungszeit liegt oder an der Anzahl der verwendeten Hooks. Vielleicht auch am Mondstand beim Test des Plugins. Man weiß es nicht und der Autor trägt auch nicht zur Aufklärung bei.</p>
<blockquote><p>Grade 2 plugins have only some elements of optimization, but they are close to grade 1. Adminimize plugin shouldn’t even load on the front end except for some elements, and that needs to be optimized.</p></blockquote>
<p>Das soll also der Grund sein warum einige Plugins schlechter sind als andere? Adminimize soll z.B. im Frontend nur das laden was es benötigt, was es im Prinzip auch macht, dies sollte aber optimiert werden? Hö? Es scheint also darum zu gehen was ein Plugin im Front- bzw. Backend lädt. Da ist es wohl egal welche Aufgabe es hat, wenn es nicht den geheimen Richtlinien des Autors entspricht, ist es schlecht.</p>
<p>Na dann schauen wir uns doch mal eins dieser supertollen Grade-5 Plugins an. Ich habe mich für GD Unit Converter entschieden und es mal unter die Lupe genommen. Was mir beim ersten Blick auffiel, waren folgende Codezeilen:</p>
<pre class="brush:php">$this-&gt;script = $_SERVER["PHP_SELF"];
$this-&gt;script = end(explode("/", $this-&gt;script));</pre>
<p>Und? Sinn erkannt? Also ich habe erst mal längere Zeit gerätselt was da passiert bis ich den Code kopiert und getestet habe. OK, ich schreibe es mal ein wenig um:</p>
<pre class="brush:php">$this-&gt;script = basename(__FILE__);</pre>
<p>So einfach kann PHP sein. Der nächste Horror folgt sofort:</p>
<pre class="brush:php">    private function plugin_path_url() {
        $this-&gt;plugin_url = plugins_url("/gd-unit-converter/");
        $this-&gt;plugin_path = dirname(dirname(__FILE__))."/";

        define("GDUNITCONVERTER_URL", $this-&gt;plugin_url);
        define("GDUNITCONVERTER_PATH", $this-&gt;plugin_path);
    }</pre>
<p>Da werden also zwei globale Variablen definiert die zwanzig Zeilen später bei einem <code>wp_enqueue_script()</code> wieder verwendet werden. Klar, man hätte auch einfach auf <code>$this-&gt;plugin_url</code> zurück greifen können (OOP, u know!?). Aber warum sparsam mit dem Speicher umgehen wenn man doch so schön sinnlos welchen durch Verwendung globaler Variablen verschwenden kann?<br />
Ach ja. Weil man anderen gerne vorschreibt sie sollen doch bitte schön sparsam mit dem Speicher umgehen:</p>
<blockquote><p>I am sure that many developers will say that these results are not important, but considering that most of the WordPress users are on shared hosting with limited memory and resources available to them, this is most important thing to have plugins they need and still have server running fine.</p></blockquote>
<p>Also Wasser predigen und Wein saufen. Contactform 7 bekommt übrigens nur eine schwache 2, dafür aber eine extra Erwähnung:</p>
<blockquote><p>All tested plugins, but one, used the internal WordPress AJAX handling. Contact Form 7 uses own handler and that is not something I can recommend. Using WP handler is best solution considering that it is already written with security concerns in mind and it is very easy to use, making plugin fit better with WP development concepts.</p></blockquote>
<p>Muss ich extra erwähnen das GD Unit Converter seinen eigenen Caching-Mechanismus mitbringt und mal ganz elegant auf den in WordPress bereits eingebauten Caching-Mechanismus pfeift?<br />
Natürlich darf auch der eigene Logger nicht fehlen, der zwar nicht genutzt wird aber dennoch geladen werden muss (require_once). Über solch lustige Konstrukte wie folgenden wundert man sich dann schon gar nicht mehr.</p>
<pre class="brush:php">$js_url = defined("SCRIPT_DEBUG") &amp;&amp; SCRIPT_DEBUG ? "js/src/unit-converter.js" : "js/unit-converter.js";</pre>
<p>Wenn <code>SCRIPT_DEBUG</code> definiert ist, sollen die JavaScripte aus dem nicht vorhandenen Verzeichnis <code>js/src/</code> geladen werden. Das gibt lustige Fehlermeldungen wenn man sein Blog im Debug-Modus startet. So lustig, das man das Plugin sofort deaktiviert.</p>
<p>Es ist einfach schlau daher zu reden und dann selber solch einen Mist zu veröffentlichen. Gefühlt die Hälfte des Codes die das Plugin umfasst ist sinnlos, wird nicht benötigt, verstößt gegen Coding Guidelines oder ist schlichtweg Speicherverschwendung. Hier sollte der Herr MilanN vielleicht selber noch mal Hand anlegen und das Plugin um fluffige 90% Code reduzieren bevor er ihm die Bestnote 5 verpasst. Ich habe mich vorhin mal eine Stunde lang hingesetzt und versucht das Plugin von Scratch (also ohne Vorlage) nachzubauen. Nach einer Stunde hatte ich bereits brauchbare Ergebnisse und kam mit einem Zehntel an Code aus. Der Speicherverbrauch dürfte noch sparsamer sein, da ich nicht total unnützes Zeug lade, sondern mich darauf beschränke das zu nutzen, was ich benötige.</p>
<p>Solche Tests die nicht klar machen wie eine Bewertung zu Stande kommt und bei denen der Autor sich die Testbedingungen so zurecht biegt das er sich selbst Bestnoten verpassen kann, kann man getrost außer Acht lassen. Hier muss sich jeder selber fragen wie objektiv der Test sein kann wenn die eigenen Plugins den Maßstab vorgeben. Da sollte man sich als Autor nicht wundern wenn andere einen auf den Zahn fühlen und zeigen wo der Mops die Locken hat.</p>
<h3>Fazit</h3>
<p><em>Gute Tests sind objektiv und vergleichen nicht eigene Arbeit mit der von Fremden.</em> Wird die eigene Arbeit dennoch im Test mit einbezogen, dürfen die Testkriterien nicht auf die eigene Optimierung hin zugeschnitten sein.<br />
<em>Die Testkriterien sollten klar und verständlich sein.</em> Was man als Leser nicht nachvollziehen kann, ist nichts wert. Ist es fraglich wie eine Bewertung zu Stande gekommen ist, ist der ganze Test wertlos. <a title="Texto" href="http://www.texto.de/plugin-performance-ich-kapiers-nicht-1323/">Moinka Thon-Soun hat auf Texto</a> in einen Artikel beschrieben wie ein schlecht gemachter Test auf einen Laien wirkt. Nämlich verwirrend, sonst nichts.<br />
<em>Die Tests sollten nachprüfbar sein.</em> Dazu müssen Testscripte zugänglich sein und die Testumgebung erläutert werden.<br />
<em>Test sollten nicht auf einen einzelnen Aspekt fokussiert sein.</em> Jeder Test hat einen Schwerpunkt, dies rechtfertigt jedoch nicht eine schlechte Bewertung weil ein Testkandidat eben nicht genau den Schwerpunkt trifft. Ein guter Tests umfasst mehrere Aspekte und bildet aus den Einzelergebnissen eine Bewertung. Jedes Plugin hat seine Stärken und Schwächen. Ein Plugin das optisch gut gestylt daher kommt, verbraucht eben mehr Speicher (mehr Grafiken, mehr CSS, mehr Code) als ein Plugin welches sehr spartanisch gestaltet ist. Was nützt einem aber ein Plugin das am falschen Ende spart, wenn es durch seinen Purismus nur schwer bedienbar ist?<br />
<em>Tests sollten sich auf das beschränken, was unter anderen Systemen ähnliche (vergleichbare) Ergebnisse liefert.</em> Eine systemunabhängiger Wert sind z.B. Fehlermeldungen (auch Notices und Deprecated Meldungen) . Die werden auf jeden System gleich sein, denn falsch ist hier wie da falsch.<br />
<em>Test sollten realitätsnah sein.</em> Im Labor gelten andere Regeln als in der Wildnis. Selbst wenn ein Plugin im Test wunderbar abschneidet, kann es dadurch versagen das es andere Plugins behindert oder gar komplett ausschaltet. Man kann nicht alle Kombinationen von Plugins prüfen, jedoch gibt es eine Reihe von Regeln für ein friedliches Miteinander die man beachten sollte.</p>
<p>Also bitte nicht jeden Test blauäugig Glauben schenken. Lieber einmal mehr als einmal zu wenig an den Ergebnissen zweifeln. Wir wissen doch alle: Die Statistik die man selber gefälscht hat, ist immer noch die beste <img src='http://yoda.neun12.de/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-54/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Quick-Tipp: Benutzer nach Anzahl der Beiträge sortieren</title>
		<link>http://yoda.neun12.de/artikel-48</link>
		<comments>http://yoda.neun12.de/artikel-48#comments</comments>
		<pubDate>Mon, 26 Dec 2011 03:11:38 +0000</pubDate>
		<dc:creator>Ralf</dc:creator>
				<category><![CDATA[Code-Snippets]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=48</guid>
		<description><![CDATA[Seit WordPress3.1 lassen sich einige Tabellen im Backend durch einen Klick auf die Spaltenüberschrift sortieren. Auf der Benutzer-Seite lassen sich so z.B. die Benutzer nach Name, E-Mail oder Benutzername sortieren. Wer ein Blog mit vielen Autoren betreibt, möchte vielleicht auch mal die Benutzer nach Anzahl der geschriebenen Beiträge sortieren lassen. Dies ist jedoch nicht möglich, [...]]]></description>
			<content:encoded><![CDATA[<p>Seit WordPress3.1 lassen sich einige Tabellen im Backend durch einen Klick auf die Spaltenüberschrift sortieren. Auf der Benutzer-Seite lassen sich so z.B. die Benutzer nach Name, E-Mail oder Benutzername sortieren.<br />
Wer ein Blog mit vielen Autoren betreibt, möchte vielleicht auch mal die Benutzer nach Anzahl der geschriebenen Beiträge sortieren lassen. Dies ist jedoch nicht möglich, da nur die ersten drei Spalten sortierbar sind. Mit ein paar Zeilen PHP kann man dies jedoch ändern.</p>
<p>Dazu filtern wir das Array mit den sortierbaren Spalten und fügen den Spalten-Schlüssel &#8216;<code>posts</code>&#8216; hinzu. Den Spalten-Schlüssel finden wir in den Core-Dateien, genauer gesagt in der Klasse <code>WP_Users_List_Table</code> (<a title="WP-Trac" href="http://core.trac.wordpress.org/browser/tags/3.3/wp-admin/includes/class-wp-users-list-table.php#L160">wp-admin/includes/class-wp-list-users-table.php; Zeile 160 &#8211; 174</a>) (direkt da drunter finden wir dann übrigens auch gleich die sortierbaren Spalten).<br />
Der Name des benötigten Filters setzt sich aus einem Muster und den Screennamen zusammen: <code>manage_xxx_sortable_columns</code>. xxx ist dabei durch den Screennamen zu ersetzen. Dies funktioniert auch mit anderen Seiten im Backend, sofern dort eine Tabelle mit <code>WP_List_Table</code> erstellt wurde. Dazu ein anderes mal mehr.</p>
<p>Der Wert für den entsprechenden Eintrag im Array kann entweder ein String oder ein Array sein. Übergibt man lediglich einen String, so legt man nur fest wonach sortiert werden soll. In diesen Fall wird dann die Standardsortierung <code>asc</code> (Ascending = Aufsteigend) verwendet. Möchte man eine absteigende Reihenfolge (<code>desc</code> = Descending = Absteigend), so muss man anstatt eines String ein Array übergeben. Der erste Wert im Array ist dabei der Schlüssel nach dem sortiert werden soll und der zweite Wert die Reihenfolge (<code>asc</code>/<code>desc</code>).<br />
In unseren Fall ist es ganz sinnvoll absteigend zu sortieren damit die Benutzer mit den meisten Beiträge als erstes aufgelistet werden. Wir übergeben also ein Array. Da wir nach Anzahl der Beiträge sortieren wollen, ist der erste Wert demnach &#8216;<code>post_count</code>&#8216; und der zweite Wert &#8216;<code>desc</code>&#8216;.</p>
<p>Das modifizierte Array mit <code>return</code> zurück geben und schon sind wir fertig. Im großen und Ganzen ist das alles eine recht interessante Sache da man auch Spalten hinzufügen bzw. entfernen kann. Dieser Code-Schnipsel ist lediglich ein kleiner Einstieg, ich werde demnächst noch etwas zu den Thema &#8220;Spalten in Tabellen&#8221; schreiben. Hier noch das komplette Plugin (wer es nicht als Plugin haben will, kopiert sich den Filter und die Funktion in die <code>functions.php</code>. Mit PHP5.3 ist das übrigens alles sehr kompakt und ein schöner Fall für eine anonyme Funktion).</p>
<div class="gistem"><div id="gist-1520418" 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="cm">/*</span></div><div class='line' id='LC3'><span class="cm">Plugin Name: Sortable post column</span></div><div class='line' id='LC4'><span class="cm">Description: Make posts column on users screen sortable</span></div><div class='line' id='LC5'><span class="cm">Version: 0.0.1</span></div><div class='line' id='LC6'><span class="cm">Author: Ralf Albert</span></div><div class='line' id='LC7'><span class="cm">Author URI: http://yoda.neun12.de </span></div><div class='line' id='LC8'><span class="cm">*/</span></div><div class='line' id='LC9'><br/></div><div class='line' id='LC10'><span class="c1">// make posts-column sortable</span></div><div class='line' id='LC11'><span class="nx">add_filter</span><span class="p">(</span> <span class="s1">&#39;manage_users_sortable_columns&#39;</span><span class="p">,</span> <span class="s1">&#39;register_user_post_column_sortable&#39;</span> <span class="p">);</span></div><div class='line' id='LC12'><br/></div><div class='line' id='LC13'><span class="k">function</span> <span class="nf">register_user_post_column_sortable</span><span class="p">(</span> <span class="nv">$columns</span> <span class="p">){</span></div><div class='line' id='LC14'>	<span class="nv">$columns</span><span class="p">[</span><span class="s1">&#39;posts&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span> <span class="s1">&#39;post_count&#39;</span><span class="p">,</span> <span class="s1">&#39;desc&#39;</span> <span class="p">);</span></div><div class='line' id='LC15'>	<span class="k">return</span> <span class="nv">$columns</span><span class="p">;</span></div><div class='line' id='LC16'><span class="p">}</span></div><div class='line' id='LC17'><br/></div><div class='line' id='LC18'><span class="cm">/* PHP5.3 style */</span></div><div class='line' id='LC19'><span class="cm">/*</span></div><div class='line' id='LC20'><span class="cm">add_filter( &#39;manage_users_sortable_columns&#39;, </span></div><div class='line' id='LC21'><span class="cm">	function( $columns ){		</span></div><div class='line' id='LC22'><span class="cm">		$columns[&#39;posts&#39;] = array( &#39;post_count&#39;, &#39;desc&#39; );</span></div><div class='line' id='LC23'><span class="cm">		</span></div><div class='line' id='LC24'><span class="cm">		return $columns;</span></div><div class='line' id='LC25'><span class="cm">	}</span></div><div class='line' id='LC26'><span class="cm">);</span></div><div class='line' id='LC27'><span class="cm">*/</span></div><div class='line' id='LC28'><br/></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1520418/a4fa0275e5e3bca0d38379cd0f24f1946f6ef40f/sortable_posts_column.php" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1520418#file_sortable_posts_column.php" style="float:right;margin-right:10px;color:#666">sortable_posts_column.php</a>
            <a href="https://gist.github.com/1520418">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>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-48/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>XML mit poEdit übersetzen</title>
		<link>http://yoda.neun12.de/artikel-42</link>
		<comments>http://yoda.neun12.de/artikel-42#comments</comments>
		<pubDate>Sat, 10 Dec 2011 18:57:26 +0000</pubDate>
		<dc:creator>Ralf</dc:creator>
				<category><![CDATA[Allgemein]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=42</guid>
		<description><![CDATA[Vor einiger Zeit stand ich vor dem Problem das ich XML-Dateien hatte die zu übersetzende Zeichenketten enthielten. Mein erster, wahrscheinlich auch naheliegendster, Gedanke war, die zu übersetzenden Zeichenketten einfach in ein __() zu packen und zu hoffen das poEdit dies erkennt. Das Problem daran war aber, dass __() eine PHP-Funktion ist und die XML-Dateien mit [...]]]></description>
			<content:encoded><![CDATA[<p>Vor einiger Zeit stand ich vor dem Problem das ich XML-Dateien hatte die zu übersetzende Zeichenketten enthielten. Mein erster, wahrscheinlich auch naheliegendster, Gedanke war, die zu übersetzenden Zeichenketten einfach in ein <code>__()</code> zu packen und zu hoffen das poEdit dies erkennt. Das Problem daran war aber, dass <code>__()</code> eine PHP-Funktion ist und die XML-Dateien mit <code>simplexml</code> verarbeitet wurden. Die PHP-Funktion würde also erst gar nicht ausgeführt werden, selbst wenn poEdit die Zeichenketten erkennen würde. Unter Zuhilfenahme von Suchmaschinen lies sich aber recht schnell eine Lösung für das Problem finden.</p>
<p><a class="highslide" onclick="return hs.expand(this)"  href="../wp-content/uploads/2011/12/poedit_1.jpg"><img class="size-thumbnail wp-image-44 alignright" title="poEdit Einstellungen" src="../wp-content/uploads/2011/12/poedit_1-150x150.jpg" alt="" width="150" height="150" /></a>In poEdit muss man einen neuen Parser anlegen (Datei -&gt; Einstellungen -&gt; Parser):</p>
<ul>
<li>Sprache: <code>XML</code></li>
<li>Durch Semikola getrennte Liste der Dateiendungen (z.B. <em>.cpp;</em>.h): <code>*.xml</code></li>
<li>Parser Befehl: <code>xgettext --force-po -o %o %C %K %F -L glade</code></li>
<li>Ein Eintrag in der Schlüsselwortliste: <code>-k%k</code></li>
<li>Ein Eintrag in der Eingabedatei-Liste: <code>%f</code></li>
<li>Zeichensatz des Quellcodes: <code>--from-code=%c</code></li>
</ul>
<p>Erzeugt man nun einen neuen Katalog, so fügt man in den Katalogoptionen unter Schlüsselwörter noch ein zusätzliches Schlüsselwort ein. Diesen kann man relativ frei wählen, ich habe mich hier für <code>translate</code> entschieden.<br />
In der XML-Datei muss man nun noch die zu übersetzenden Zeichenketten mit seinen gewählten Schlüsselwort umschließen:</p>
<pre class="brush:xml">&lt;root&gt;
  &lt;title&gt;&lt;translate&gt;My headline&lt;/translate&gt;&lt;/title&gt;
  &lt;text&gt;&lt;translate&gt;This is the text&lt;/translate&gt;&lt;/text&gt;
  &lt;options&gt;
   &lt;font&gt;strong&lt;/font&gt;
   &lt;color&gt;black&lt;/color&gt;
  &lt;/options&gt;
&lt;/root&gt;</pre>
<p>poEdit ist nun in der Lage die in der XML-Datei mit <code>translate</code> gekennzeichneten Zeichenketten zu übersetzen.</p>
<p><a class="highslide" onclick="return hs.expand(this)"  href="http://yoda.neun12.de/wp-content/uploads/2011/12/poedit_2.jpg"><img class="alignleft size-thumbnail wp-image-43" title="poEdit Einstellungen" src="http://yoda.neun12.de/wp-content/uploads/2011/12/poedit_2-150x150.jpg" alt="" width="150" height="150" /></a>Unter Windows kann es vorkommen das man noch eine Fehlermeldung erhält das <code>glade</code> und/oder <code>expat</code> nicht unterstützt werden. Das liegt an der mit poEdit ausgelieferten Version von <code>gettext</code>. In diesen Fall sollte man sich das vom <a title="gnuwin32 Projekt" href="http://gnuwin32.sourceforge.net/packages/gettext.htm">gnuwin32 Projekt bereit gestellte gettext-Paket</a> runterladen.<br />
Die in dem Paket enthaltenen Dateien kopiert man sich dann in <code>poedit/bin/</code> (vorher das Verzeichnis sichern). In einigen Quellen wird angegeben das man lediglich die <code>gettext.exe</code> kopieren muss, andere sagen man kopiert sich die <code>gettext.exe</code>, startet sie und schaut welche Abhängigkeiten/Bibliotheken (.dll Dateien) noch fehlen. Ich habe einfach das komplette Paket kopiert (WinXP / Win7) und es funktioniert einwandfrei.</p>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-42/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WP_Editor mit externen Seitenaufrufen verwenden</title>
		<link>http://yoda.neun12.de/artikel-37</link>
		<comments>http://yoda.neun12.de/artikel-37#comments</comments>
		<pubDate>Wed, 05 Oct 2011 22:06:52 +0000</pubDate>
		<dc:creator>Ralf</dc:creator>
				<category><![CDATA[Code-Snippets]]></category>
		<category><![CDATA[HowTo]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=37</guid>
		<description><![CDATA[Frank hat auf WordPress Deutschland schon vom neuen Editor in WordPress 3.3 berichtet. Die Verwendung der Klasse WP_Editor ist mit der Funktion wp_editor() denkbar einfach. Im einfachsten Fall übergibt man der Funktion einen String für den Content und eine ID für die Textarea. Beide Angaben sind Pflichtangaben, einen leeren Editor &#8211; was wohl die Standardsituation [...]]]></description>
			<content:encoded><![CDATA[<p><a title="Frank Bültge" href="http://bueltge.de/">Frank</a> hat auf <a title="WordPress Deutschland" href="wordpress-deutschland.org">WordPress Deutschland</a> schon vom <a title="WordPress Deutschland" href="http://blog.wordpress-deutschland.org/2011/09/27/editor-update-in-wordpress-3-3.html">neuen Editor in WordPress 3.3 </a>berichtet. Die Verwendung der Klasse <code>WP_Editor</code> ist mit der Funktion <code>wp_editor()</code> denkbar einfach. Im einfachsten Fall übergibt man der Funktion einen String für den Content und eine ID für die Textarea. Beide Angaben sind Pflichtangaben, einen leeren Editor &#8211; was wohl die Standardsituation sein dürfte &#8211; muss man also mit der Übergabe eines leeren Strings oder ein Boolean <code>FALSE</code> erzwingen.</p>
<p>Die genaue Konfiguration der Editor-Klasse soll aber nicht Gegenstand des Beitrages sein. Denn beim Testen der neuen Editor-Klasse bin ich auf ein ganz anderes Problem gestoßen zu dem ich hier ein paar Worte schreiben will.</p>
<p>Mein Wunsch war es nämlich, den Editor in einer Thickbox zu öffnen, dazu sollte der Editor mittels einem Ajax-Request in die Thickbox geladen werden. Was auf den ersten Blick recht simple erscheint, birgt ein paar Stolperfallen in sich. Denn der alleinige Aufruf von <code>wp_editor()</code> erzeugt zwar das benötigte HTML, jedoch nicht die ebenfalls benötigten JavaScripte.</p>
<p>Die Ausgangssituation ist folgende: Ich habe für den TinyMCE ein Plugin welches eine Thickbox öffnet und den Inhalt der Datei <code>editor_popup.php</code> in die Thickbox lädt. Die Datei <code>editor_popup.php</code> hat anfangs folgenden schlichten Inhalt:</p>
<pre class="brush:php">&lt;?php
// get wp-load
$abspath = isset( $_GET['abspath'] ) ? $_GET['abspath'] : '';
if( '' != $abspath )
	require_once $abspath.'/wp-load.php';
else
	die('No abspath submitted!');
?&gt;
&lt;!DOCTYPE html&gt;

&lt;html&gt;
	&lt;head&gt;
		&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;
		&lt;title&gt;Thickbox test&lt;/title&gt;
	&lt;/head&gt;

	&lt;body&gt;

		&lt;div id="editorwrapper"&gt;
			&lt;form action="display.php" method="get" target="_blank"&gt;
&lt;?php
	wp_editor( '&lt;p&gt;Some more content&lt;/p&gt;', 'editortest' );
?&gt;
				&lt;input type="submit" value="Submit" /&gt;
			&lt;/form&gt;
		&lt;/div&gt;

	&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Den ABSPATH übergebe ich als GET-Request, somit ist es ein Leichtes <code>wp-load.php</code> einzubinden um an die WordPress-Funktionen zu gelangen. Der Rest ist ein bisschen HTML und der Aufruf der Funktion <code>wp_editor()</code>.<br />
Dies führte jedoch zu keinem Ergebnis, denn es fehlt so ziemlich alles an JavaScript was benötigt wird damit der Editor überhaupt betriebsbereit ist.</p>
<p>Schaut man sich die Klasse WP_Editor einmal etwas genauer an, so findet man zwei Methoden die das Einbinden und die Ausgabe des benötigten JavaScriptes übernehmen. Dies sind zum einen <code>enqueue_scripts()</code> und <code>editor_js()</code>. Diese Methoden übernehmen die Ausgabe bzw. das Einreihen des benötigten JavaScriptes und werden in den Hooks &#8216;<em>admin_print_footer_scripts</em>&#8216; / &#8216;<em>wp_print_footer_scripts</em>&#8216; bzw. &#8216;<em>admin_footer</em>&#8216; und &#8216;<em>wp_footer</em>&#8216; eingehakt.<br />
Da wir in unserer Testseite weder den einen noch den anderen Hook automatisch ausführen, müssen wir dies von Hand machen. Dazu fügen wir einfach vor dem schließenden <code>&lt;/body&gt;</code> ein <code>&lt;?php do_action( 'wp_footer' ); ?&gt;</code> ein. Um noch das passende Loook&amp;Feel von WordPress zu bekommen, nutzen wir das Admin-CSS und optional noch z.B. das Stylesheet &#8216;<em>colors-fresh</em>&#8216; um ein paar Buttons zu stylen.</p>
<pre class="brush:php">&lt;?php
add_filter( 'show_admin_bar', '__return_false' );

$styles = array( 'wp-admin', 'colors-fresh'  );
wp_print_styles( $styles );
?&gt;</pre>
<p>Dieser Code kommt vor dem schließenden <code>&lt;/head&gt;</code>. Nebenbei habe ich noch die Admin-Bar entfernt, da diese in einem kleinen Popup eher suboptimal dargestellt wird und obendrein eher nutzlos ist.</p>
<p>Et voilá! Da ist der funktionierende Editor. Und hier noch einmal das komplette Script zusammen:</p>
<pre class="brush:php">&lt;?php
// get wp-load
$abspath = isset( $_GET['abspath'] ) ? $_GET['abspath'] : '';
if( '' != $abspath )
	require_once $abspath.'/wp-load.php';
else
	die('No abspath submitted!');
?&gt;
&lt;!DOCTYPE html&gt;

&lt;html&gt;
	&lt;head&gt;
		&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;
		&lt;title&gt;Thickbox test&lt;/title&gt;

&lt;?php
add_filter( 'show_admin_bar', '__return_false' );

$styles = array( 'wp-admin', 'colors-fresh'  );
wp_print_styles( $styles );
?&gt;
	&lt;/head&gt;

	&lt;body&gt;

		&lt;div id="editorwrapper"&gt;
			&lt;form action="display.php" method="get" target="_blank"&gt;
&lt;?php
wp_editor( '&lt;p&gt;Some content&lt;/p&gt;', 'editortest' );  //, $settings );
?&gt;
				&lt;input type="submit" value="Submit" /&gt;
			&lt;/form&gt;
		&lt;/div&gt;
&lt;?php
do_action( 'wp_footer' );
?&gt;
	&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Wenn wir dieses Script nun in der Datei <code>wp-content/plugins/editor_popup.php</code> abspeichern, dann können wir sie z.B. mit <code>http://example.com/wp-content/plugins/editor_popup.php?abspath=c:/htdocs/wordpress</code> in einem Ajax-Request aufrufen und z.B. in einer Thickbox darstellen.</p>
<p>Wie man dann den Editor an seine Bedürfnisse anpasst, ist genug Stoff für einen eigenen Artikel. Ich hoffe dem einen oder anderen schon vor Erscheinen von WordPress 3.3 eine kleine Hilfe gegeben zu haben wie man solch ein Problem lösen kann.</p>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-37/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

