<?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>sixohthree.com &#187; PHP</title>
	<atom:link href="http://sixohthree.com/tag/php/feed" rel="self" type="application/rss+xml" />
	<link>http://sixohthree.com</link>
	<description>The Weblog of Adam Backstrom</description>
	<lastBuildDate>Sat, 04 Feb 2012 12:27:51 +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>PHP 5.4 Changes</title>
		<link>http://sixohthree.com/1756/php-5-4-changes</link>
		<comments>http://sixohthree.com/1756/php-5-4-changes#comments</comments>
		<pubDate>Wed, 16 Nov 2011 15:32:47 +0000</pubDate>
		<dc:creator>Adam Backstrom</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://mu.sixohthree.com/sixohthree/?p=1756</guid>
		<description><![CDATA[From the PHP 5.4.0 RC1 "NEWS" file. Traits, array dereferencing, CLI built-in web server, and more.]]></description>
			<content:encoded><![CDATA[<p>From the PHP 5.4.0 RC1 <a href="http://www.php.net/releases/NEWS_5_4_0_RC1.txt">&#8220;NEWS&#8221; file</a>.</p>
<ul>
<li><a href="http://us2.php.net/traits">Traits</a></li>
<li>Class member access on instantiation: <code>(new Foo)-&gt;bar()</code></li>
<li>Short array syntax: <code>['blue', 'red']</code></li>
<li>ext/mysql, mysqli and pdo_mysql now use mysqlnd by default</li>
<li>New typehint: <code>function( callable $callback )</code></li>
<li><a href="http://us2.php.net/manual/en/closure.bind.php"><code>Closure::bind()</code></a> and <a href="http://us2.php.net/manual/en/closure.bindto.php"><code>Closure::bindTo()</code></a></li>
<li><code>Class::{"foo$bar"}()</code></li>
<li>Method call through array: <code>$cb = array($obj, 'method'); $cb( $args );</code></li>
<li>Built-in web server: <code>php -S localhost:8080</code></li>
<li><code>&lt;?=</code> is now always available regardless of the short_open_tag setting (pure PHP templates ftw)</li>
</ul>
<p>In addition to safe mode being removed, there&#8217;s also this:</p>
<blockquote><p>
  Removed magic_quotes_gpc, magic_quotes_runtime and magic_quotes_sybase ini options. get_magic_quotes_gpc, get_magic_quotes_runtime are kept but always return false, set_magic_quotes_runtime raises an E_CORE_ERROR. (Pierrick, Pierre)
</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://sixohthree.com/1756/php-5-4-changes/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Filesystem Caching without Cruft in PHP</title>
		<link>http://sixohthree.com/1578/filesystem-caching-without-cruft-in-php</link>
		<comments>http://sixohthree.com/1578/filesystem-caching-without-cruft-in-php#comments</comments>
		<pubDate>Sun, 04 Sep 2011 05:58:28 +0000</pubDate>
		<dc:creator>Adam Backstrom</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[caching]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://mu.sixohthree.com/sixohthree/?p=1578</guid>
		<description><![CDATA[Cleanup your file caches while you're still using them.]]></description>
			<content:encoded><![CDATA[<p>In PHP on a Unix system, you can <code>unlink()</code> files after <code>fopen()</code> to keep <code>/tmp</code> free of cruft. I&#8217;m currently using this in a file caching setup, where the cache exists only for the lifetime of the request.</p>
<pre>// cache the file on the filesystem
$path = tempnam('/tmp', 'foo');
$fp = fopen($path, 'w');
fwrite($fp, $sweet_data);
fclose($fp);

// file has contents; now store a read-only pointer to the file
$cache[$key] = fopen($path, 'r');
unlink($path);</pre>
<p>The file is unlinked as the last step, removing it from <code>/tmp</code>, but it's still available for <code>fseek()</code> and <code>fread()</code> through the cached file pointer (in a static, singleton, or other non-persistent store of choice). When the request ends, the pointer is closed, and the filesystem will free the space used by that file.</p>
<p>No keeping track of files for cleanup, no registering a shutdown function, and we don't have to retain the file contents in memory.</p>
]]></content:encoded>
			<wfw:commentRss>http://sixohthree.com/1578/filesystem-caching-without-cruft-in-php/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python and PHP: Giving a Rat&#8217;s Ass</title>
		<link>http://sixohthree.com/1526/python-and-php-giving-a-rats-ass</link>
		<comments>http://sixohthree.com/1526/python-and-php-giving-a-rats-ass#comments</comments>
		<pubDate>Wed, 01 Jun 2011 10:59:15 +0000</pubDate>
		<dc:creator>Adam Backstrom</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://mu.sixohthree.com/sixohthree/?p=1526</guid>
		<description><![CDATA[Should you give a rat's ass about being competitive with PHP?]]></description>
			<content:encoded><![CDATA[<p>So this happened:</p>
<p><a href="https://twitter.com/#!/alex_gaynor/status/75730453201555456"><img class="size-full wp-image-1528 alignone" title="alex_gaynor-tweet" src="http://sixohthree.com/files/2011/06/alex_gaynor-tweet.jpg" alt="A tweet by @alex_gaynor" longdesc="I frankly couldn't give a rat's ass if Python was never competitive in the god awful space PHP is." /></a></p>
<p>I&#8217;m not going to stand up in a very strong defense of PHP. There is <a href="http://www.phpsadness.com/">plenty wrong with it</a>, but its popularity is due to its low barrier to entry:</p>
<ul>
<li>It&#8217;s ubiquitous in cheap shared hosting environments</li>
<li>It&#8217;s easy to create your first script (create a .php file in the web directory)</li>
<li>There are a plethora of tutorials</li>
</ul>
<p>This attracts a pretty scary demographic: the non-programmer. Just look at the <a href="http://stackoverflow.com/questions/tagged/php">PHP questions</a> on <a href="http://stackoverflow.com/">Stack Overflow</a>. On any given day it&#8217;s a <a href="http://stackoverflow.com/questions/6198830/php-problem-with-variables">complete mess</a>, a land where HTML is intermingled with PHP and everyone is using the <a href="http://www.php.net/manual/en/book.mysql.php">old-school MySQL API</a>. Separation of concerns, escaping data, MVC, OOP, and any number of other concepts are above these users, for now. They&#8217;re just trying to get something on the page in the way their language seems to encourage.</p>
<p>The crux, then: if your language has a high barrier to entry, you effectively lock out some portion of unskilled users. Saying you don&#8217;t want to &#8220;compete&#8221; with PHP means retaining your high barrier to entry. Is it better to attract programmers who already have some ability, or to encourage a wider installed base? Would you rather tell a newbie, &#8220;Write your app with PHP, it&#8217;s easy&#8221; or &#8220;Write your app with Python, it&#8217;s good?&#8221; I prefer the latter.</p>
]]></content:encoded>
			<wfw:commentRss>http://sixohthree.com/1526/python-and-php-giving-a-rats-ass/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>PHP, symlinks, and the realpath cache</title>
		<link>http://sixohthree.com/1517/php-and-the-realpath-cache</link>
		<comments>http://sixohthree.com/1517/php-and-the-realpath-cache#comments</comments>
		<pubDate>Fri, 06 May 2011 15:01:47 +0000</pubDate>
		<dc:creator>Adam Backstrom</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://mu.sixohthree.com/sixohthree/?p=1517</guid>
		<description><![CDATA[I've had issues in the past where symlinked web directories don't point to the correct file after the symlink target is changed.]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve had issues in the past where modifying symlinks seems to break my web apps: I change the symlink target, but PHP still loads the old target for seconds or minutes. Yesterday I realized this was happening because of the PHP <a href="http://php.net/manual/en/ini.core.php#ini.sect.performance">realpath cache</a>. This cache can be emptied using <a href="http://us3.php.net/clearstatcache"><tt>clearstatcache()</tt></a>, but the cache is maintained per-thread, so it&#8217;s not a silver bullet. Only the active thread will have its cache cleared, where you may have dozens of threads in total (e.g. instances of php-fpm, or httpd children in prefork mode).</p>
<p>So, from now on I&#8217;ll just consider symlinks harmful, I suppose.</p>
]]></content:encoded>
			<wfw:commentRss>http://sixohthree.com/1517/php-and-the-realpath-cache/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Migrating to PHP 5.3: call_user_func_array()</title>
		<link>http://sixohthree.com/1486/migrating-to-php-5-3-call_user_func_array</link>
		<comments>http://sixohthree.com/1486/migrating-to-php-5-3-call_user_func_array#comments</comments>
		<pubDate>Fri, 11 Mar 2011 15:37:22 +0000</pubDate>
		<dc:creator>Adam Backstrom</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[php 5.3]]></category>

		<guid isPermaLink="false">http://mu.sixohthree.com/sixohthree/?p=1486</guid>
		<description><![CDATA[I've been updating various old pieces of code after our PHP 5.3 upgrade yesterday afternoon. Today, <code>call_user_func_array()</code> has been a recurring theme.]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been updating various old pieces of code after our PHP 5.3 upgrade yesterday afternoon. Today, <a href="http://php.net/call-user-func-array"><code>call_user_func_array()</code></a> has been a recurring theme. Notably, some older WordPress plugins have been causing issues, as the WordPress plugin API is heavily dependent on <code>call_user_func_array()</code>.</p>
<h2>Passing non-arrays</h2>
<p>Let&#8217;s first look what happens when we pass a non-array as the second argument to <code>call_user_func_array()</code>:</p>
<pre>
function foo() {
    var_dump( func_get_args() );
    return 7;
}

var_dump( call_user_func_array( 'foo', 3 ) );
</pre>
<p>Here&#8217;s the output in PHP 5.2.17:</p>
<pre>
array(1) {
  [0]=>
  int(3)
}
int(7)
</pre>
<p>And here&#8217;s PHP 5.3.5:</p>
<pre>
PHP Warning:  call_user_func_array() expects parameter 2 to be array, integer given in /tmp/call_user_func_array.php on line 9
NULL
</pre>
<p>In my definition a &#8220;warning&#8221; wouldn&#8217;t refuse to run a specific command (the callback) and then continue with program execution, but c&#8217;est la vie. One fix is to typecast as <code>array</code>, which turns a scalar into a single-element array:</p>
<pre>
call_user_func_array( 'foo', (array)3 ); // array( 0 => 3 )
</pre>
<p>However, typecasting would turn an object into an array. An object with three properties would become an array with three elements, so the callback would get three arguments (the properties) rather than one argument (the object). The best solution is to check <code>is_array()</code>:</p>
<pre>
call_user_func_array( 'foo', is_array($args) ? $args : array($args) ); // $args, or array( 0 => $args )
</pre>
<h2>Passing by reference</h2>
<p>Let&#8217;s try a callback that expects to get parameters by reference:</p>
<pre>
function foo( &#038;$input ) {
    var_dump( $input );
    return 'goodbye';
}

$args = array( 'hello' );
var_dump( call_user_func_array( 'foo', $args ) );
</pre>
<p>The old PHP 5.2.17 behavior:</p>
<pre>
string(5) "hello"
string(7) "goodbye"
</pre>
<p>And now, in PHP 5.3.5:</p>
<pre>
PHP Warning:  Parameter 1 to foo() expected to be a reference, value given in /tmp/call_user_func_array.php on line 9
NULL
</pre>
<p>Same deal as before: things basically fall of the tracks, with the callback never executing and the function returning null. One fix is to pass <code>$args</code> by reference, and remove the <code>&#038;</code> from the function definition:</p>
<pre>
function foo( $input ) {
    var_dump( $input );
    return 'goodbye';
}

$args = array( 'hello' );
var_dump( call_user_func_array( 'foo', &#038;$args ) );
</pre>
<p>Or if you don&#8217;t really require pass by reference (you&#8217;re not modifying the input) just remove the <code>&#038;</code> from the function definition and be done with it.</p>
]]></content:encoded>
			<wfw:commentRss>http://sixohthree.com/1486/migrating-to-php-5-3-call_user_func_array/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>On Frameworks</title>
		<link>http://sixohthree.com/1477/on-frameworks</link>
		<comments>http://sixohthree.com/1477/on-frameworks#comments</comments>
		<pubDate>Sun, 06 Mar 2011 23:38:10 +0000</pubDate>
		<dc:creator>Adam Backstrom</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[object oriented programming]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://mu.sixohthree.com/sixohthree/?p=1477</guid>
		<description><![CDATA[Everyone wants what they don't have.]]></description>
			<content:encoded><![CDATA[<p>Martin Fowler, <em>Patterns of Enterprise Application Architecture</em>:</p>
<blockquote><p>I&#8217;m assuming that most of my readers will fall into two groups: those with modest needs who are looking to build their own software and readers with more demanding needs who will be using a tool. … There is a third category; those with demanding needs who want to build their own software. The first thing I&#8217;d say here is to look carefully at using tools. I&#8217;ve seen more than one project get sucked into a long exercise at building frameworks, which wasn&#8217;t what the project was really about.</p></blockquote>
<p>I have been acutely aware of this, lately. The specific sorts of patterns I&#8217;m looking for (e.g. <a href="http://en.wikipedia.org/wiki/Active_record_pattern">active record)</a> could be done for me, were I to use a framework. There&#8217;s a lot to weigh:</p>
<ul>
<li>Increased difficulty of maintenance as we complement our own set of home-grown, evolved tools with third-party tools. All the old code doesn&#8217;t just go away.</li>
<li>Training new and existing developers in a specific toolset (though in theory this would offset some of our own documentation requirements)</li>
<li>Finding a tool that actually fits our needs (<a href="http://www.zend.com/">Zend</a>, <a href="http://lithify.me/">Lithium</a>, <a href="http://www.doctrine-project.org/">Doctrine</a>, <a href="http://codeigniter.com/">CodeIgniter</a>, <a href="http://kohanaframework.org/">Kohana</a>,  <a href="http://www.phpframeworks.com/">etc</a>.)</li>
</ul>
<p>My impression is that Zend would most easily fit into our existing development. We could cherry-pick components, increasing our dependence as we grow in comfort and retire old home-grown tools. Maybe the same is true for other projects. I&#8217;d love to build a simple project using each of these tools, to really get a feel for their ins and outs.</p>
<p>At some level, I&#8217;m just tired of writing simple SQL statements.</p>
]]></content:encoded>
			<wfw:commentRss>http://sixohthree.com/1477/on-frameworks/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Testable Factories</title>
		<link>http://sixohthree.com/1418/testable-factories</link>
		<comments>http://sixohthree.com/1418/testable-factories#comments</comments>
		<pubDate>Sat, 01 Jan 2011 22:19:55 +0000</pubDate>
		<dc:creator>Adam Backstrom</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[unit testing]]></category>

		<guid isPermaLink="false">http://mu.sixohthree.com/sixohthree/?p=1418</guid>
		<description><![CDATA[So I wrote a post about testable classes in PHP, and before I even hit "Publish" I read something on StackOverflow that challenged some of my opinions. I wrote that I didn't need testable factories, but what if I did?]]></description>
			<content:encoded><![CDATA[<p>So I wrote a post about <a href="http://sixohthree.com/1412/thinking-about-testability">testable classes in PHP</a>, and before I even hit &#8220;Publish&#8221; <a href="http://stackoverflow.com/questions/1061552/unit-testing-factory-methods-which-have-a-concrete-class-as-a-return-type/1061601#1061601">I read something on Stack Overflow</a> that challenged some of my opinions. I wrote that I didn&#8217;t need testable factories, but what if I did?</p>
<p>For me, the main appeal of a factory is one-line instantiation of classes. This allows for clean, clear dependency injection in object instantiation, but quick access to an object without a lot of duplicated code, and also has the potential to reduce overhead when creating an interface to a data store. (In my previous example, the factory method cached a reference to the database object using a static.)</p>
<p>But what if the factory itself were its own class?</p>
<pre>class UserFactory {
    public static function userstore( $new_store = null ) {
        static $userstore;

        if( $new_store !== null ) {
            $userstore = $new_store;
        }

        // default userstore if one wasn't provided
        if( $userstore === null ) {
            $userstore = new UserStore_Database( DB_USER, DB_PASS );
        }

        return $userstore;
    }

    public static function load_by_id( $id ) {
        $user = new User( self::userstore() );
        $user-&gt;load( $id );

        return $user;
    }
}

$dbstore = new UserStore_Database( DB_USER, DB_PASS );
UserFactory::userstore( $dbstore );
$user = UserFactory::load_by_id( 12 );</pre>
<p>Or maybe it&#8217;s better to have the factory as an object rather than a collection of static methods:</p>
<pre>class UserFactory {
    public $userstore;

    public function __construct( $userstore ) {
        $this-&gt;userstore = $userstore;
    }

    public function load_by_id( $id ) {
        $user = new User( $this-&gt;userstore );
        $user-&gt;load( $id );

        return $user;
    }
}

$dbstore = new UserStore_Database( DB_USER, DB_PASS );
$uf = new UserFactory( $dbstore );
$user = $uf-&gt;load_by_id( 12 );</pre>
<p>I&#8217;m not sure if one implementation is better than the other. The former seems testable, and it can be used in any scope without instantiation or prior setup, allowing for one-liners.</p>
]]></content:encoded>
			<wfw:commentRss>http://sixohthree.com/1418/testable-factories/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Thinking About Testability</title>
		<link>http://sixohthree.com/1412/thinking-about-testability</link>
		<comments>http://sixohthree.com/1412/thinking-about-testability#comments</comments>
		<pubDate>Sat, 01 Jan 2011 22:01:43 +0000</pubDate>
		<dc:creator>Adam Backstrom</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[unit testing]]></category>

		<guid isPermaLink="false">http://mu.sixohthree.com/sixohthree/?p=1412</guid>
		<description><![CDATA[I've been thinking a lot about unit tests, lately. In the Bad Old Days I could var_dump() my way through a problem and deal with the consequences, but that isn't good enough any more. Today, I want my tests to run themselves, and that's forcing me change the way I structure my code.]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been thinking a lot about unit tests, lately. In the Bad Old Days I could <code>var_dump()</code> my way through a problem and deal with the consequences, but that isn&#8217;t good enough any more. Today, I want my tests to run themselves, and that&#8217;s forcing me to change the way I structure my code.</p>
<p>In the past I may have written a user class which was very tightly coupled with a database:</p>
<pre>class User {
    public function __construct( $id ) {
         global $db;

         $sql = "SELECT * FROM users WHERE id = ?";
         $user = $db-&gt;get( $sql, $id );

         $this-&gt;id = $user-&gt;id;
         $this-&gt;name = $user-&gt;name;
    }
}</pre>
<p>It&#8217;s easy to identify why this is hard to test: you need a database with predictable data beneath to have any confidence that the code is working as it should. A testable alterative would use <strong>Dependency Injection</strong>:</p>
<pre>class User {
    public function __construct( $userstore ) {
        $this-&gt;userstore = $userstore;
    }

    public function load( $id ) {
        $userdata = $this-&gt;userstore-&gt;load( $id );

        $this-&gt;id = $userdata-&gt;id;
        $this-&gt;name = $userdata-&gt;name;
    }
}</pre>
<p>Rather than instantiating a user with <code>new User(12)</code>, I would instead say:</p>
<pre>$userstore = new UserStore_Database( DB_USER, DB_PASS ); // create db interface
$user = new User( $userstore ); // create user object, connecting to db
$user-&gt;load( 12 ); // load user #12</pre>
<p>This is way more verbose, but factories can automatic the common use cases:</p>
<pre>class User {
    // __construct(), load(), plus:

    public static function load_by_id( $id ) {
        static $userstore = null;

        // cache the database interface
        if( $userstore === null ) {
            $userstore = new UserStore_Database( DB_USER, DB_PASS );
        }

        $user = new User( $userstore );
        $user-&gt;load( $id );

        return $user;
    }
}</pre>
<p>Our object is testable, but day-to-day code in production can still use a one-liner:</p>
<pre>$user = User::load_by_id( 12 );</pre>
<p>When I write my unit tests, I can create a custom <code>UserStore</code> class that returns data from an array. The <code>User::load_by_id()</code> method is not testable, but honestly I don&#8217;t care. I want to test the core functionality of the user class, and if <code>User</code> works, then my factory works.</p>
<p>Most of the information I find is very specific to other languages (e.g. Java), recommending programming constructs that aren&#8217;t in PHP. My challenge is to apply this to PHP, and not get sidetracked by hard line stances like &#8220;never use statics&#8221; but rather understand those opinions in context of how they hurt testability.</p>
]]></content:encoded>
			<wfw:commentRss>http://sixohthree.com/1412/thinking-about-testability/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP 5.3.0 Changes</title>
		<link>http://sixohthree.com/748/php-530-changes</link>
		<comments>http://sixohthree.com/748/php-530-changes#comments</comments>
		<pubDate>Thu, 19 Mar 2009 15:19:52 +0000</pubDate>
		<dc:creator>Adam Backstrom</dc:creator>
				<category><![CDATA[Personal]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://blogs.bwerp.net/?p=748</guid>
		<description><![CDATA[PHP 5.3.0 looks promising.]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify">PHP 5.3.0 looks promising. So far:</p>
<ul>
<li><a href="http://www.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.methods">__callStatic()</a></li>
<li><a href="http://bugs.php.net/bug.php?id=33595">Circular reference garbage collection</a></li>
<li><a href="http://php.net/manual/en/function.get-called-class.php">get_called_class()</a></li>
<li><a href="http://wiki.php.net/rfc/closures">Closures</a></li>
<li><a href="http://www.php.net/manual/en/datetime.gettimestamp.php">DateTime::getTimestamp()</a></li>
<li><a href="http://us.php.net/manual/en/language.namespaces.php">Namespaces</a></li>
<li><a href="http://us.php.net/lsb">Late Static Binding</a></li>
<li><a href="http://docs.php.net/manual/en/book.phar.php">Phar</a> as part of the default install</li>
<li><var>__DIR__</var> — no more <code>dirname(__FILE__)</code>!</li>
</ul>
<p>PHP 5.3.0 was <a href="http://www.php.net/archive/2009.php#id2009-06-30-1">released</a> on 23 June, 2009! A <a href="http://docs.php.net/migration53">migration guide</a> is available.</p>
]]></content:encoded>
			<wfw:commentRss>http://sixohthree.com/748/php-530-changes/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Local Documentation: PHP, Django, jQuery</title>
		<link>http://sixohthree.com/730/local-documentation-php-django-jquery</link>
		<comments>http://sixohthree.com/730/local-documentation-php-django-jquery#comments</comments>
		<pubDate>Tue, 10 Feb 2009 10:46:02 +0000</pubDate>
		<dc:creator>Adam Backstrom</dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[documentation]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blogs.bwerp.net/?p=730</guid>
		<description><![CDATA[Here's how I created local mirrors of the online documentation for several projects under Mac OS X 10.5.6.]]></description>
			<content:encoded><![CDATA[<p>As ubiquitous as wifi is these days, I still feel better with a local copy of the documentation around. Here&#8217;s how I created local copies of the <a href="http://www.php.net/">PHP</a>, <a href="http://www.djangoproject.com/">Django</a>, and <a href="http://jquery.com/">jQuery</a> docs on my MacBook running Mac OS X 10.5.6.</p>
<h3>Django</h3>
<p><a href="http://docs.djangoproject.com/en/dev/">Django&#8217;s documentation files</a> are flat HTML, so the only <em>real</em> step is to build the docs using <a href="http://sphinx.pocoo.org/">Sphinx</a>. I&#8217;ll do this in <code>~/Sites/django-docs/</code> for consistency with my PHP setup, but strictly speaking you can access these docs without the overhead of a web server.</p>
<pre><code>sudo easy_install sphinx
cd ~/Sites/
svn co http://code.djangoproject.com/svn/django/trunk/docs/ django-docs
cd django-docs
make html</code></pre>
<p>The final step took several minutes to complete on my MacBook. Script output notes that the new documentation is stored in <code>build/_html/</code>. Open the index.html file in your browser. <a href="http://www.youtube.com/watch?v=YHzM4avGrKI">There&#8217;s no step 3</a>!</p>
<h3>PHP</h3>
<p>The PHP setup is slightly more complicated since the docs themselves rely on PHP. (On the upside, this provides quick access to function reference with URLs like <a href="http://php.net/explode">php.net/explode</a>.) Luckily the process is <a href="http://www.php.net/mirroring.php">well documented</a>. I won&#8217;t duplicate their steps here, but I will share some tips.</p>
<p>Here is <a href="http://blogs.bwerp.net/~adam/2009/02/10/php.localhost.conf">my Apache 2 configuration file</a>. I saved this to <code>/private/etc/apache2/other/php.localhost.conf</code> where it&#8217;s automatically included by <code>/private/etc/apache2/httpd.conf</code>. Open up <code>httpd.conf</code> add the directive <code>NameVirtualHost *</code>.</p>
<p>Mac OS X 10.5 honors <code>/etc/hosts</code>, so appending something to the standard localhost line gives you a quick-and-easy local domain name. I used <code>php.localhost</code>:</p>
<pre><code>127.0.0.1       localhost php.localhost</code></pre>
<p>The initial takes a few minutes. I highly recommend using the suggested flags to ignore non-English language files and the documentation tarballs.</p>
<p>Finally, I had to disable the inclusion of <code>httpd-manual.conf</code> in <code>httpd.conf</code>, which was overriding <code>http://php.localhost/manual/</code>.</p>
<h3>jQuery</h3>
<p><span style="color: #ff0000">Unfortunately, this results in a broken API browser for reasons unknown to me. I&#8217;ll leave it here in case others figure out where I went wrong.</span></p>
<p>This one is pretty straightforward, but requires another <code>VirtualHost</code> as the URLs are all relative to <code>/</code>.  Personally I like <a href="http://docs.jquery.com/">docs.jquery.com</a> better than the API browser, but those docs run off a MediaWiki install. First, download the docs. (These are also available as an Adobe AIR application, linked from <a href="http://api.jquery.com/">api.jquery.com</a>.)</p>
<p>First, add a new alias to <code>/etc/hosts</code>:</p>
<pre><code>127.0.0.1       localhost php.localhost jquery.localhost</code></pre>
<p>Now download the API browser using Subversion. For some reason, jquery-1.3.1.js is missing from trunk, so we&#8217;ll download that as well.</p>
<pre><code>cd ~/Sites/
svn co http://jqueryjs.googlecode.com/svn/trunk/tools/jquery-api-browser/ jquery-docs
curl -o jquery-docs/lib/jquery/jquery-1.3.1.js http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js</code></pre>
<p>A very simple Apache configuration file is needed. I created <code>other/jquery.localhost.conf</code>, just like I did for the PHP docs:</p>
<pre><code>&lt;VirtualHost *&gt;
ServerName jquery.localhost
DocumentRoot /Users/adam/Sites/jquery-docs
DirectoryIndex index.php
&lt;/VirtualHost&gt;</code></pre>
<p>Restart Apache (<code>sudo apachectl restart</code>) and browse to <code>http://jquery.localhost/</code>. Docs!</p>
]]></content:encoded>
			<wfw:commentRss>http://sixohthree.com/730/local-documentation-php-django-jquery/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

