<?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>Coyote Tracks &#187; PHP</title>
	<atom:link href="http://kagan.mactane.org/blog/tag/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://kagan.mactane.org/blog</link>
	<description>The prints of an Internet-enabled coyote.</description>
	<lastBuildDate>Tue, 31 Jan 2012 03:26:51 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<item>
		<title>Beware of Optional Curly Braces&#160;&#8212; They Will Bite You</title>
		<link>http://kagan.mactane.org/blog/2012/01/30/beware-of-optional-curly-braces-they-will-bite-you/</link>
		<comments>http://kagan.mactane.org/blog/2012/01/30/beware-of-optional-curly-braces-they-will-bite-you/#comments</comments>
		<pubDate>Tue, 31 Jan 2012 03:26:51 +0000</pubDate>
		<dc:creator>Kai MacTane</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[bad ideas]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[silly coding tricks]]></category>

		<guid isPermaLink="false">http://kagan.mactane.org/blog/?p=441</guid>
		<description><![CDATA[I was looking through some PHP code from a third-party vendor recently, and saw something that made my jaw drop. It&#8217;s pretty innocent-looking, at first. Here&#8217;s a somewhat anonymized and genericized version of the code, but the thing that bothered me is still intact. It&#8217;s not really a bug, per&#160;se; the code will function as [...]]]></description>
			<content:encoded><![CDATA[<p>I was looking through some PHP code from a third-party vendor recently, and saw something that made my jaw drop. It&#8217;s pretty innocent-looking, at first. Here&#8217;s a somewhat anonymized and genericized version of the code, but the thing that bothered me is still intact. It&#8217;s not really a bug, <i>per&nbsp;se</i>; the code will function as intended.&nbsp;But&#8230;</p>
<div class="code">$currentRow = 0;<br />
$itemId = &#8220;&#8221;;<br />
$index = 0;<br />
while ($row = mysql_fetch_object($result)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($currentRow == 10) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;renderHeaderRow();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$currentRow = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// takes an itemId and displays relevant columns<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;renderSummaryRow($row->itemId);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$currentRow++;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($index > 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$itemId .=  &#8220;,&#8221;;    # interpolate a comma<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$itemId .= $row->itemId;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$index++;<br />
}</p></div>
<p>See the problem? Really, there are a few ways this can go wrong. To a quick glance, the only clue that line&nbsp;14 (&#8220;interpolate a comma&#8221;) is part of a conditional is its indentation. The indentation is important to a human reader&nbsp;&mdash; but <strong>absolutely irrelevant</strong> to the PHP interpreter, which simply treats the next line after the conditional as the conditional&#8217;s block. Regardless of how it&#8217;s indented, and regardless of what else is&nbsp;around.</p>
<p><em>The way it looks to a human <strong>is not</strong> the way it looks to the&nbsp;machine.</em></p>
<p>What happens if someone wants to add some logging? What if they add it after the comma&nbsp;line?</p>
<div class="code">if ($index > 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$itemId .=  &#8220;,&#8221;;    # interpolate a comma<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writeLog(&#8220;Added a comma&#8221;);<br />
$itemId .= $row->itemId;<br />
$index++;</div>
<p>Now the log claims the code has added a comma, even when it hasn&#8217;t. But still, it could be worse! What if you decided to add your logging <em>before</em> the other&nbsp;line?</p>
<div class="code">if ($index > 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writeLog(&#8220;Adding a comma to itemId&#8230;&#8221;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$itemId .=  &#8220;,&#8221;;    # interpolate a comma<br />
$itemId .= $row->itemId;<br />
$index++;</div>
<p>Now it adds a comma no matter what&nbsp;&mdash; even the first time through the loop, when the string is empty. So instead of a string like <code>'123,124,125'</code>, $itemId will now have a leading comma: <code>',123,124,125'</code>. Since this value is getting stitched into a SQL query later on, it means your app will blow up with a SQL syntax&nbsp;error.</p>
<p>This is why Python makes whitespace significant to program flow. The way the indentation makes it <em>look like</em> the logical structure is, is how the structure <em>actually</em>&nbsp;is.</p>
<p>And this is also why Perl&nbsp;&mdash; of all languages, one that normally errs on the side of letting you leave out anything that can be inferred from context&nbsp;&mdash; <strong>Perl</strong> insists in its syntax documentation that <a href="http://perldoc.perl.org/perlsyn.html#Compound-Statements">in cases like this</a>, &#8220;the curly brackets are <em>required</em>&nbsp;&mdash; no dangling statements allowed.&#8221; (It then says, in typically Perlish fashion: &#8220;If you want to write conditionals without curly brackets there are several other ways to do it.&#8221;)</p>
<p>If you&#8217;re working in one of those languages that lets you omit curly braces around a single-statement conditional&nbsp;&mdash; <strong><em>DON&#8217;T DO IT!</em></strong> The potential maintenance and debugging problems are <em>not</em> worth the fun of saving two keystrokes (or just one, if you work in an editor that auto-closes your braces for&nbsp;you).</p>
]]></content:encoded>
			<wfw:commentRss>http://kagan.mactane.org/blog/2012/01/30/beware-of-optional-curly-braces-they-will-bite-you/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hummingbird Version 0.66 Released</title>
		<link>http://kagan.mactane.org/blog/2010/11/28/hummingbird-version-0-66-released/</link>
		<comments>http://kagan.mactane.org/blog/2010/11/28/hummingbird-version-0-66-released/#comments</comments>
		<pubDate>Sun, 28 Nov 2010 23:02:28 +0000</pubDate>
		<dc:creator>Kai MacTane</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Hummingbird]]></category>
		<category><![CDATA[my projects]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[QA]]></category>
		<category><![CDATA[release]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://kai.mactane.org/blog/?p=262</guid>
		<description><![CDATA[This is largely a bug-fix release. Tom Clift, of PaperCut print management software, kindly informed me of a few installation issues that my own tests didn&#8217;t find. The profusion of configuration options in PHP can make testing everything on a single server quite difficult. This would be a good time for me to mention that [...]]]></description>
			<content:encoded><![CDATA[<p>This is largely a bug-fix release. Tom Clift, of <a href="http://www.papercut.com/">PaperCut</a> print management software, kindly informed me of a few installation issues that my own tests didn&#8217;t find. The profusion of configuration options in PHP can make testing everything on a single server <em>quite</em> difficult.</p>
<p>This would be a good time for me to mention that I have the utmost respect for QA people. They deal with all sorts of minutiae that I am really glad not to have to handle, and I&#8217;m really glad they&#8217;re around. That said, I am <em>not</em> a QA person&#8230; and so I occasionally miss the sorts of stuff they&#8217;d catch.</p>
<ol>
<li>It turns out Hummingbird depends on <a href="http://www.php.net/manual/en/features.commandline.introduction.php">the CLI version</a> of PHP, and the CGI version will not suffice. This requirement is now listed in the appropriate section of <a href="http://kai.mactane.org/software/hummingbird/">the Hummingbird page</a>.</li>
<li>Not all PHP installations have output buffering turned on by default. The latest version of Hummingbird takes account for this.</li>
<li>Various problems that can occur with the data cache file are also now reported more gracefully.</li>
</ol>
<p>Again, my thanks to Tom Clift for some very useful patches!</p>
<p>You can get the latest version of Hummingbird from <a href="http://kai.mactane.org/software/hummingbird/">the Hummingbird page on my site</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://kagan.mactane.org/blog/2010/11/28/hummingbird-version-0-66-released/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Announcing Hummingbird</title>
		<link>http://kagan.mactane.org/blog/2009/05/27/announcing-hummingbird/</link>
		<comments>http://kagan.mactane.org/blog/2009/05/27/announcing-hummingbird/#comments</comments>
		<pubDate>Wed, 27 May 2009 20:01:06 +0000</pubDate>
		<dc:creator>Kai MacTane</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[announcements]]></category>
		<category><![CDATA[my projects]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[release]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[Twitter]]></category>

		<guid isPermaLink="false">http://kai.mactane.org/blog/?p=57</guid>
		<description><![CDATA[If you read Coyote Tracks*, you&#8217;ve probably noticed that I recently set up a thing over there in the right-hand side that says &#8220;My Latest Tweets&#8221;. At first, that was just a little PHP widget that I&#8217;d hacked together myself. But then I realized it could actually be useful to other people, because it does [...]]]></description>
			<content:encoded><![CDATA[<p>If you read <cite>Coyote Tracks</cite>*, you&#8217;ve probably noticed that I recently set up a thing over there in the right-hand side that says &#8220;My Latest Tweets&#8221;. At first, that was just a little PHP widget that I&#8217;d hacked together myself. But then I realized it could actually be useful to other people, because it does a bunch of things that many of the other &#8220;latest tweets&#8221; widgets in existence <em>don&#8217;t</em> do.</p>
<p>So I decided to get it cleaned up and make a real, distributable software package out of it. That took a few days, especially when I started banging on it, and trying to ensure that it had a prayer of working on anyone else&#8217;s server. Plus there was the time involved for writing the docs.</p>
<p>But now that all of that stuff is done, I am pleased to announce: <a href="/software/hummingbird/">Hummingbird</a>. A lightweight, pretty, and compact gizmo for displaying your latest tweets on a blog or other PHP-powered web page.</p>
<p>* And if you don&#8217;t read <cite>Coyote Tracks</cite>&#8230; what the heck is wrong with you? *g*</p>
]]></content:encoded>
			<wfw:commentRss>http://kagan.mactane.org/blog/2009/05/27/announcing-hummingbird/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Workaround for PEAR/PECL Failure with Message &#8220;ERROR: `phpize&#8217; failed&#8221;</title>
		<link>http://kagan.mactane.org/blog/2009/05/11/workaround-for-pearpecl-failure-with-message-error-phpize-failed/</link>
		<comments>http://kagan.mactane.org/blog/2009/05/11/workaround-for-pearpecl-failure-with-message-error-phpize-failed/#comments</comments>
		<pubDate>Mon, 11 May 2009 17:24:24 +0000</pubDate>
		<dc:creator>Kai MacTane</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[patch]]></category>
		<category><![CDATA[PEAR]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[release]]></category>
		<category><![CDATA[solution]]></category>

		<guid isPermaLink="false">http://kai.mactane.org/blog/?p=46</guid>
		<description><![CDATA[When you try to upgrade or install various PEAR (or PECL) packages, you may get the rather unhelpful error message &#8220;ERROR: `phpize&#8217; failed&#8221;. For example, here&#8217;s the result I get when I try to install the pecl_http package: root@finrod:~# pecl install pecl_http pecl/pecl_http can optionally use PHP extension &#34;iconv&#34; downloading pecl_http-1.6.3.tar .&#46;. Starting to download [...]]]></description>
			<content:encoded><![CDATA[<p>When you try to upgrade or install various PEAR (or PECL) packages, you may get the rather unhelpful error message &#8220;ERROR: `phpize&#8217; failed&#8221;. For example, here&#8217;s the result I get when I try to install the <code>pecl_http</code> package:</p>
<p><code>root@finrod:~# <strong>pecl install pecl_http</strong><br />
pecl/pecl_http can optionally use PHP extension &#34;iconv&#34;<br />
downloading pecl_http-1.6.3.tar .&#46;.<br />
Starting to download pecl_http-1.6.3.tar (Unknown size)<br />
.&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;.&#46;.<br />
.&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;.&#46;.<br />
.&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;..&#46;.&#46;.done: 1,015,808 bytes<br />
71 source files, building<br />
running: phpize<br />
Configuring for:<br />
PHP Api Version:         20041225<br />
Zend Module Api No:      20060613<br />
Zend Extension Api No:   220060519<br />
ERROR: `phpize&#39; failed<br />
root@finrod:~#</code></p>
<p>The error is actually caused by <a href="http://bugs.php.net/bug.php?id=29123">a bug in PHP itself (filed in PHP&#8217;s bug database as of 2004</a>, and currently marked &#8220;Won&#8217;t fix&#8221;): If your installation of PHP was compiled with the <code>--enable-sigchild</code> flag on, then the return value from a <code>pclose()</code> call can&#8217;t be trusted. One of PEAR&#8217;s components, called PEAR::Builder, uses <code>pclose()</code> as part of the package installation process, to try to determine whether a given operation succeeded or not.</p>
<p>Even though the operation succeeds, <code>pclose()</code> returns -1, signaling a failure, and the rest of PEAR then takes <code>pclose()</code> at its word.</p>
<p><strong>Is This Affecting Your Installation of PHP and PEAR?</strong></p>
<p>If you&#8217;ve gotten an &#8220;ERROR: `phpize&#8217; failed&#8221; message when trying to run a &#8220;pecl install&#8221; or &#8220;pear install&#8221; command, try running <code>phpinfo()</code>&nbsp;&mdash; if you see <code>--enable-sigchild</code> in the &#8220;Configure Command&#8221; section near the very top, then you&#8217;re most likely being bitten by this bug.</p>
<p><strong>Potential Fixes and Workarounds</strong></p>
<p>The PHP dev team recommends recompiling without the offending flag.</p>
<p>However, you may not be able to do that, for any of various reasons. (You may have installed from a binary package, for instance&nbsp;&mdash; like most people these days.) Or it may simply seem like an excessive hassle. I offer the following patch <strong>as-is, without any guarantee or support</strong>.</p>
<p>First, ensure that you have the latest version of PEAR::Builder. Look in your PEAR/Builder.php file&nbsp;&mdash; On most Linux and Unix installations, this is likely to be in <code>/usr/lib/php/PEAR/Builder.php</code>, or possibly <code>/usr/local/lib/php/PEAR/Builder.php</code>.</p>
<p>On Windows systems, PHP might be installed nearly anywhere, but supposing it&#8217;s in <code>c:\php</code>, then the file you&#8217;re looking for will be in <code>c:\php\PEAR\PEAR\Builder.php</code> (yes, that&#8217;s two PEARs in a row).</p>
<p>Check the &#8220;@version&#8221; line in the big comment block at the beginning of the file; the line you want should be around line 19 or so. If says it&#8217;s less than version 1.38 (the latest one, at the time I&#8217;m writing this post), then try upgrading. Running &#8220;pear upgrade pear&#8221; should work. Then you can install this patch file:</p>
<p><a href="http://kai.mactane.org/software/patch-pear-builder-1.38.txt">patch-pear-builder-1.38.txt</a></p>
<p>Download the patch file and place it somewhere on your machine. Log in and <code>cd</code> to the PEAR directory that contains the Builder.php file. Then run the patch command. In the following example, I&#8217;ve placed the patch file in root&#8217;s home directory:</p>
<p><code>root@finrod:~# <strong>ls</strong><br />
loadlin16c.txt  loadlin16c.zip  patch-pear-builder-1.38.txt<br />
root@finrod:~# <strong>cd /usr/lib/php/PEAR</strong><br />
root@finrod:/usr/lib/php/PEAR# <strong>cp Builder.php Builder.bak.php</strong><br />
root@finrod:/usr/lib/php/PEAR# <strong>patch -p0 < /root/patch-pear-builder-1.38.txt</strong><br />
patching file Builder.php<br />
root@finrod:/usr/lib/php/PEAR# </code></p>
<p>Naturally, if the patch file doesn&#8217;t work for some reason, or it breaks things, you can just <code>cp</code> the backup file back into place.</p>
<p>Please let me know if this patch works for you&nbsp;&mdash; or if it fails horribly, for that matter.</p>
<p>[Updated 2009-06-03: Minor edits for clarity]</p>
]]></content:encoded>
			<wfw:commentRss>http://kagan.mactane.org/blog/2009/05/11/workaround-for-pearpecl-failure-with-message-error-phpize-failed/feed/</wfw:commentRss>
		<slash:comments>24</slash:comments>
		</item>
		<item>
		<title>Grousing About PHP&#8217;s Limitations</title>
		<link>http://kagan.mactane.org/blog/2008/12/23/grousing-about-phps-limitations/</link>
		<comments>http://kagan.mactane.org/blog/2008/12/23/grousing-about-phps-limitations/#comments</comments>
		<pubDate>Wed, 24 Dec 2008 02:57:38 +0000</pubDate>
		<dc:creator>Kai MacTane</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://kai.mactane.org/blog/?p=14</guid>
		<description><![CDATA[Drat. I would like to chase back up the class hierarchy of a bunch objects, and then do something based on the second-from-the-top of that chain. (For example, when the chain goes Word&#160;> Noun&#160;> Animal&#160;> Mammal&#160;>&#160;Human, and I&#8217;ve instantiated a Human, I&#8217;d like that object to be able to tell that it&#8217;s a Noun.) Unfortunately, [...]]]></description>
			<content:encoded><![CDATA[<p>Drat. I would like to chase back up the class hierarchy of a bunch objects, and then do something based on the second-from-the-top of that chain. (For example, when the chain goes <code>Word&nbsp;> Noun&nbsp;> Animal&nbsp;> Mammal&nbsp;>&nbsp;Human</code>, and I&#8217;ve instantiated a <code>Human</code>, I&#8217;d like that object to be able to tell that it&#8217;s a <code>Noun</code>.)</p>
<p>Unfortunately, I&#8217;m doing this in PHP, and it&#8217;s not possible to get a class&#8217; parent&nbsp;&mdash; all you can do is find the parent of an instantiated object. So, in order to chase back up the class hierarchy, I&#8217;d have to instantiate one of each object type&#8230; and that would require coming up with parameters for each one, because these aren&#8217;t the sorts of things you can just create as anonymous items with no values.</p>
<p>I tried creating a static <code>getParent()</code> method in the top-level object, but then when I do the static call on a subclass (e.g., <code>Human::getParent()</code>, which should return <code>Mammal</code>), it apparently calls <code>Word::getParent()</code> anyway (and that complains that it <em>has</em> no parent class&#8230;)</p>
<p>I expect I&#8217;ll be running up against more and more of PHP&#8217;s limitations in the near future, now that I&#8217;ve gotten more accustomed to concepts like functional programming, introspection, and so on.</p>
<p>A quick glance at <a href="http://www.ruby-doc.org/core/classes/Class.html">the Ruby Class documentation</a> makes it painfully obvious how easy this would be in Ruby. While native JavaScript doesn&#8217;t support such things, Prototype.js does&nbsp;&mdash; down <a href="http://www.prototypejs.org/learn/class-inheritance">at the bottom of this page</a>, under &#8220;Special Class Properties&#8221;, it mentions the subclasses and superclass properties, and gives handy examples.</p>
]]></content:encoded>
			<wfw:commentRss>http://kagan.mactane.org/blog/2008/12/23/grousing-about-phps-limitations/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>I&#8217;m Getting Tired of Yak-Shaving</title>
		<link>http://kagan.mactane.org/blog/2008/12/18/im-getting-tired-of-yak-shaving/</link>
		<comments>http://kagan.mactane.org/blog/2008/12/18/im-getting-tired-of-yak-shaving/#comments</comments>
		<pubDate>Fri, 19 Dec 2008 03:59:42 +0000</pubDate>
		<dc:creator>Kai MacTane</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[diary]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[TDD]]></category>

		<guid isPermaLink="false">http://kai.mactane.org/blog/?p=11</guid>
		<description><![CDATA[It seems like every time I try to get around to actually writing some code, I discover yet another thing that I have to do in order to make that more possible. Today, it was: Get PHPUnit installed on L&#243;rien, so I could run my unit tests locally during development, rather than having to shove [...]]]></description>
			<content:encoded><![CDATA[<p>It seems like every time I try to get around to actually <em>writing some code</em>, I discover yet another thing that I have to do in order to make that more possible. Today, it was: Get PHPUnit installed on <span style="cursor: help; border-bottom: 1px dotted;" title="my Windows workstation">L&oacute;rien</span>, so I could run my unit tests locally during development, rather than having to shove everything back up to <span style="cursor: help; border-bottom: 1px dotted;" title="my Linux server, where I used to do such development">Finrod </span>every time I wanted to run a single test.</p>
<p>The <a href="http://en.wiktionary.org/wiki/yak_shaving">yak-shaving</a> odyssey that this necessitated involved upgrading my local copy of PHP (which originally came with InstantRails) from 4.whatever to 5.2.8, so that I could develop PHP5 code at all, then installing PEAR so that I could use it to get PHPUnit, and also resolving the weird extension-loading bugs on PHP for Windows (for example, you have to load <code>php_mbstring.dll</code> <em>before</em> <code>php_exif.dll</code>, or else both of them will fail and complain. Ditto with <code>php_pdo.dll</code> and <code>php_sqlite.dll</code>. None of this is documented in the manual; you have to Google on it and get links to the bug database. Joy.)</p>
<p>But I can now run PHPUnit test on the stuff that I&#8217;m working on, <em>locally</em> rather than remotely. So&#8230; <em>now</em> can I get some code written?</p>
]]></content:encoded>
			<wfw:commentRss>http://kagan.mactane.org/blog/2008/12/18/im-getting-tired-of-yak-shaving/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

