<?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>Matthew Turland &#187; PHP</title>
	<atom:link href="http://matthewturland.com/category/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://matthewturland.com</link>
	<description></description>
	<lastBuildDate>Sun, 18 Jul 2010 14:29:09 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>An Update on &#8220;Web Scraping with PHP&#8221;</title>
		<link>http://matthewturland.com/2010/07/17/an-update-on-web-scraping-with-php/</link>
		<comments>http://matthewturland.com/2010/07/17/an-update-on-web-scraping-with-php/#comments</comments>
		<pubDate>Sun, 18 Jul 2010 02:51:46 +0000</pubDate>
		<dc:creator>Matthew Turland</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://matthewturland.com/?p=385</guid>
		<description><![CDATA[Several people have asked me the same question recently, so I decided to take a blog post to provide an answer. The question is, &#8220;When will &#8216;Web Scraping with PHP&#8216; be available in print?&#8221; Answering requires a bit of background to paint a full picture of where things are now. I turned in the manuscript [...]]]></description>
			<content:encoded><![CDATA[<p>Several people have asked me the same question recently, so I decided to take a blog post to provide an answer. The question is, &#8220;When will &#8216;<a title="php|architect’s Guide to Web Scraping with PHP | php|architect" href="http://www.phparch.com/books/phparchitects-guide-to-web-scraping-with-php/">Web Scraping with PHP</a>&#8216; be available in print?&#8221; Answering requires a bit of background to paint a full picture of where things are now.</p>
<p>I turned in the manuscript for the book, which had already gone through technical editing, back in April 2009. That&#8217;s right, 14 months ago. After going through proofreading and layout, having a cover designed, getting an ISBN, and so forth, the digital version of the book finally went up for sale <a title="Matthew Turland  » Blog Archive » “Web Scraping with PHP” Now Available!" href="http://matthewturland.com/2010/04/20/web-scraping-with-php-now-available/">about three months ago</a>.</p>
<p>At that point, I asked if print copies would be available at <a title="PHP Conference — Chicago IL May 18-22 2010 — PHP, MySQL, Linux, Windows, Drupal, WordPress" href="http://tek.phparch.com/">php|tek</a>. The publisher sounded unsure, but told me that they would see what they could do. I was later told that the book had gone through printing and that arrangements had been made for a box to be shipped to the hotel on the Monday prior to the conference starting. It didn&#8217;t arrive at any point before or during the conference.</p>
<p>After the conference was over (now about two months ago), I was told that the box had finally arrived at the hotel the following Wednesday. I&#8217;m not sure how this was known, because the box was never recovered from the hotel to be shipped elsewhere.</p>
<p>The publisher then resolved to request another box from the printer. This box would have to be shipped to someone to proof the printed copies for quality assurance, then the books would go on sale. I was told about this resolution in early June, about five or six weeks ago. I&#8217;ve been in touch with the person responsible for proofing the books; they haven&#8217;t been received yet.</p>
<p>I have no direct contact with the printer, so all I&#8217;ve been able to do is e-mail the publisher repeatedly (six times and counting) since then asking for an update. Through an instant messenger conversation, I was told that a call was supposed to be placed to the printer early last week to determine what the status of things was. So far as I know, that call was never made, or at least I was never told of the result.</p>
<p>I&#8217;m as frustrated with this situation as anyone. I want the book to be available to people who want to read it in the format they prefer. If you are in this audience, please contact the publisher to voice your opinion. You can do so by using <a title="Contact php|architect | php|architect" href="http://www.phparch.com/policies/contact-us/">this contact form</a> on their web site or by <a title="php|architect (phparch) on Twitter" href="http://twitter.com/phparch">sending them a tweet</a> on Twitter. Thank you all very much for your continued support.</p>
]]></content:encoded>
			<wfw:commentRss>http://matthewturland.com/2010/07/17/an-update-on-web-scraping-with-php/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Webscrapers Mailing List</title>
		<link>http://matthewturland.com/2010/07/03/webscrapers-mailing-list/</link>
		<comments>http://matthewturland.com/2010/07/03/webscrapers-mailing-list/#comments</comments>
		<pubDate>Sat, 03 Jul 2010 12:25:57 +0000</pubDate>
		<dc:creator>Matthew Turland</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[cURL]]></category>
		<category><![CDATA[Web Scraping]]></category>

		<guid isPermaLink="false">http://matthewturland.com/?p=377</guid>
		<description><![CDATA[Daniel Stenberg, one of the primary authors of the libcurl library on which the PHP cURL extension is based, was kind enough to comment on and clarify a recent blog post of mine regarding web scraping using the PHP and cURL. He later sent me a tweet to invite me to a new mailing list for [...]]]></description>
			<content:encoded><![CDATA[<p><a title="daniel.haxx.se" href="http://daniel.haxx.se">Daniel Stenberg</a>, one of the primary authors of the <a title="cURL and libcurl" href="http://curl.haxx.se">libcurl library</a> on which the <a title="PHP: cURL - Manual" href="http://php.net/curl">PHP cURL extension</a> is based, was kind enough to <a title="Matthew Turland » Blog Archive » Gotcha on Scraping .NET Applications with PHP and cURL" href="http://matthewturland.com/2010/06/30/gotcha-on-scraping-net-applications-with-php-and-curl/comment-page-1/#comment-5202">comment on</a> and clarify a <a title="Matthew Turland » Blog Archive » Gotcha on Scraping .NET Applications with PHP and cURL" href="http://matthewturland.com/2010/06/30/gotcha-on-scraping-net-applications-with-php-and-curl">recent blog post</a> of mine regarding web scraping using the PHP and cURL. He later sent me <a title="Twitter / Daniel Stenberg: @elazar Allow me to invite ..." href="http://twitter.com/bagder/status/17590025600">a tweet</a> to invite me to a new <a title="Webscrapers - The Community" href="http://webscrapers.haxx.se">mailing list</a> for web scraping enthusiasts just before <a title="Twitter / Daniel Stenberg: Everyone is welcome to joi ..." href="http://twitter.com/bagder/status/17590320446">tweeting a public invitation</a>. In addition to the mailing list itself, the web site also has links to books (including <a title="php|architect’s Guide to Web Scraping with PHP | php|architect" href="http://www.phparch.com/books/phparchitects-guide-to-web-scraping-with-php/">my book</a>) and popular tools related to the subject. I think this is awesome and I encourage anyone with an interest in web scraping, professional or recreational, to join.</p>
]]></content:encoded>
			<wfw:commentRss>http://matthewturland.com/2010/07/03/webscrapers-mailing-list/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Gotcha on Scraping .NET Applications with PHP and cURL</title>
		<link>http://matthewturland.com/2010/06/30/gotcha-on-scraping-net-applications-with-php-and-curl/</link>
		<comments>http://matthewturland.com/2010/06/30/gotcha-on-scraping-net-applications-with-php-and-curl/#comments</comments>
		<pubDate>Thu, 01 Jul 2010 02:27:09 +0000</pubDate>
		<dc:creator>Matthew Turland</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[cURL]]></category>
		<category><![CDATA[Web Scraping]]></category>

		<guid isPermaLink="false">http://matthewturland.com/?p=365</guid>
		<description><![CDATA[Obligatory pitch: Many other useful tidbits like this can be yours by purchasing my book, php&#124;architect&#8217;s Guide to Web Scraping with PHP. I recently wrote a PHP script to scrape data from a .NET application. In the process of developing this script, I noticed something interesting that I thought I&#8217;d share. In this case, I [...]]]></description>
			<content:encoded><![CDATA[<p><em>Obligatory pitch: Many other useful tidbits like this can be yours by purchasing my book, </em><a title="php|architect&amp;#8217;s Guide to Web Scraping with PHP | php|architect" href="http://www.phparch.com/books/phparchitects-guide-to-web-scraping-with-php/"><em>php|architect&#8217;s Guide to Web Scraping with PHP</em></a><em>.</em></p>
<p>I recently wrote a PHP script to scrape data from a .NET application. In the process of developing this script, I noticed something interesting that I thought I&#8217;d share. In this case, I was using the <a title="PHP: cURL - Manual" href="http://php.net/manual/en/book.curl.php">cURL extension</a>, but the tip isn&#8217;t necessarily specific to that. One thing my script did was submit a <a title="POST (HTTP) - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/POST_(HTTP)">POST request</a> to simulate a form submission. The code looked something like the sample below.</p>
<pre class="brush: php;">$ch = curl_init();
curl_setopt_array($ch, array(
    CURLOPT_URL =&gt; 'http://...',
    CURLOPT_POST =&gt; true,
    CURLOPT_POSTFIELDS =&gt; array(
        'field1' =&gt; 'value1',
        // ...
    ),
    // ...
));</pre>
<p>The issue I ran into had to do with a behavior of the <code>CURLOPT_POSTFIELDS</code> setting that&#8217;s easy to overlook. This is a segment of its description from the <a title="PHP: curl_setopt - Manual" href="http://php.net/curl_setopt">PHP manual page</a> for the <code>curl_setopt()</code> function.</p>
<blockquote><p>If <em>value</em> is an array, the <em>Content-Type</em> header will be set to <em>multipart/form-data</em>.</p></blockquote>
<p>If the form being submitted is not set to have an <code>enctype</code> attribute value of <code>multipart/form-data</code> in the form&#8217;s markup, .NET returns a 500-level HTTP response with no further information on what causes the error (for security purposes). This presumably happens because it&#8217;s expecting one value for the <code>Content-Type</code> request header and getting another.</p>
<p>Setting <code>CURLOPT_HEADER</code> and <code>CURLOPT_VERBOSE</code> to <code>true</code> helped to reveal that this was the issue. The fix is pretty simple: instead of passing the array itself for <code>CURLOPT_POSTFIELDS</code>, pass the result of wrapping it in a call to the  <code>http_build_query()</code> function (see its <a title="PHP: http_build_query - Manual" href="http://php.net/http_build_query">PHP manual page</a>). This converts it to a properly formatted query string, which causes cURL to use the default <code>Content-Type</code> header value of <code>application/x-www-form-urlencoded</code> instead.</p>
<p>Tools like <a title="Firebug" href="http://getfirebug.com">Firebug</a> can help you to examine requests made by a browser. Together with these settings for cURL, you can modify your script&#8217;s requests to match those of your browser as closely as possible, making gotchas like this less likely to trip you up.</p>
]]></content:encoded>
			<wfw:commentRss>http://matthewturland.com/2010/06/30/gotcha-on-scraping-net-applications-with-php-and-curl/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>New SPL Features in PHP 5.3</title>
		<link>http://matthewturland.com/2010/05/20/new-spl-features-in-php-5-3/</link>
		<comments>http://matthewturland.com/2010/05/20/new-spl-features-in-php-5-3/#comments</comments>
		<pubDate>Thu, 20 May 2010 15:00:53 +0000</pubDate>
		<dc:creator>Matthew Turland</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[SPL]]></category>

		<guid isPermaLink="false">http://matthewturland.com/?p=107</guid>
		<description><![CDATA[Note: I&#8217;ve written on this topic before, but thought the subject warranted further more detailed discussion and a more comprehensive and up-to-date set of benchmarks. Hence, this post and this presentation. Enjoy. The SPL, or Standard PHP Library, is an often overlooked extension in the PHP core. It first came on the scene in PHP [...]]]></description>
			<content:encoded><![CDATA[<p><em>Note: I&#8217;ve <a title="The SPL Deserves Some Reiteration | Blue Parabola, LLC" href="http://blueparabola.com/blog/spl-deserves-some-reiteration">written on this topic before</a>, but thought the subject warranted further more detailed discussion and a more comprehensive and up-to-date set of benchmarks. Hence, this post and <a title="New SPL Features in PHP 5.3" href="http://www.slideshare.net/tobias382/new-spl-features-in-php-53">this presentation</a>. Enjoy.</em></p>
<p>The <a title="PHP: SPL - Manual" href="http://php.net/spl">SPL</a>, or Standard PHP Library, is an often overlooked extension in the PHP core. It first came on the scene in PHP 5 and a variety of <a title="PHP: Iterators - Manual" href="http://php.net/manual/en/spl.iterators.php">iterators</a> constituted the majority of its initial offerings. Though the <a title="PHP: New Classes - Manual" href="http://www.php.net/manual/en/migration53.classes.php">iterator offerings were expanded in PHP 5.3</a>, the particularly interesting additions to the SPL were several specialized <a title="Data structure - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Data_structures">data structure</a> <a title="PHP: Datastructures - Manual" href="http://php.net/manual/en/spl.datastructures.php">classes</a>, the foundational concepts for which originate in the field of <a title="Computer science - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Computer_science">computer science</a>. In this post, I will provide an overview of these new classes and explain why and when they should be used.</p>
<h3>Arrays</h3>
<p>While PHP has several data types, the ones that likely see the most frequent and varied use are <a title="PHP: Strings - Manual" href="http://php.net/manual/en/language.types.string.php">strings</a> and <a title="PHP: Arrays - Manual" href="http://php.net/manual/en/language.types.array.php">arrays</a>. They are the proverbial <a title="Duct tape - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Duct_tape#Common_uses">duct tape</a> and <a title="WD-40 - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/WD-40#Function">WD-40</a> of PHP, respectively. Like arrays, SPL data structure classes are used to store composite (i.e. non-<a title="Scalar (computing) - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Scalar_(computing)">scalar</a>) data.</p>
<p>Now, that&#8217;s not to say that every instance of an array in existing codebases should be replaced with an SPL container object. There are cases where it&#8217;s appropriate to use one over the other. Knowing the difference requires an understanding of how arrays work.</p>
<p>Within the C code that makes up the PHP interpreter, arrays are implemented as a data structure called a <a title="Hash table - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Hash_table">hash table or hash map</a>. When a value contained within an array is referenced by its index, PHP uses a <a title="[svn] Contents of /php/php-src/trunk/Zend/zend_hash.h" href="http://svn.php.net/viewvc/php/php-src/trunk/Zend/zend_hash.h?revision=298204&amp;view=markup#l228">hashing function</a> to convert that index into a unique hash representing the location of the corresponding value within the array.</p>
<p>This hash map implementation enables arrays to store an arbitrary number of elements and provide access to all of those elements simultaneously using either numeric or string keys. Arrays are extremely fast for the capabilities they provide and are an excellent general purpose data structure.</p>
<h3>Fixed Arrays</h3>
<p>In contrast to arrays, <a title="PHP: SplFixedArray - Manual" href="http://php.net/manual/en/class.splfixedarray.php"><code>SplFixedArray</code></a> functions more like <a title="Arrays" href="http://www.cplusplcom/doc/tutorial/arrays/">C arrays</a> or <a title="Arrays (The Java™ Tutorials &gt; Learning the Java Language &gt; Language Basics)" href="http://java.sun.com/docs/books/tutorial/java/nutsandbolts/arrays.html">Java arrays</a> than <a title="PHP: Arrays - Manual" href="http://php.net/manual/en/language.types.array.php">PHP arrays</a>. The maximum number of elements that it may contain is specified upon instantiation. While it is possible to change it later via the <code>setSize()</code> method, this negates the performance advantages of using it: because its size is fixed, it doesn&#8217;t need to use a hashing function to resolve the position of elements within the array. <strong>It makes sense to use fixed arrays when the number of elements to be stored is known in advance and the elements only need to be accessed by sequential position.</strong></p>
<p><code>SplFixedArray</code> implements the <a title="SPL-StandardPHPLibrary: Iterator Interface Reference" href="http://www.php.net/~helly/php/ext/spl/interfaceIterator.html"><code>Iterator</code></a>, <a title="SPL-StandardPHPLibrary: ArrayAccess Interface Reference" href="http://www.php.net/~helly/php/ext/spl/interfaceArrayAccess.html"><code>ArrayAccess</code></a>, and <a title="SPL-StandardPHPLibrary: Countable Interface Reference" href="http://www.php.net/~helly/php/ext/spl/interfaceCountable.html"><code>Countable</code></a> interfaces. <code>Iterator</code> allows it to be iterated using a <a title="PHP: foreach - Manual" href="http://php.net/manual/en/control-structures.foreach.php"><code>foreach</code></a> loop. <code>ArrayAccess</code> provides access to its elements using <a title="PHP: Arrays - Manual" href="http://php.net/manual/en/language.types.array.php#language.types.array.syntax.modifying">array syntax</a> where elements are referred to using integer positions beginning at 0 as with enumerated arrays. <code>Countable</code> enables a list to be passed to the <a title="PHP: count - Manual" href="http://php.net/count"><code>count()</code></a> function like an array.</p>
<p>Aside from the inability to use it in place of arrays with <a title="PHP: Array Functions - Manual" href="http://php.net/manual/en/ref.array.php">array functions</a>, instances of <code>SplFixedArray</code> function just like arrays for all intents and purposes. It&#8217;s even possible to convert them to and from arrays using the <a title="PHP: SplFixedArray::toArray - Manual" href="http://php.net/manual/en/splfixedarray.toarray.php"><code>toArray()</code></a> and <a title="PHP: SplFixedArray::fromArray - Manual" href="http://php.net/manual/en/splfixedarray.fromarray.php"><code>fromArray()</code></a> methods respectively. However, it generally makes more sense to use <code>SplFixedArray</code> exclusively for each individual use case.</p>
<h3>Lists</h3>
<p>In <a title="Computer science - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Computer_science">computer science</a>, a <a title="List (computing) - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/List_(computing)">list</a> is defined as an ordered collection of values. A <a title="Linked list - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Linked_list">linked list</a> is a data structure in which each element in the list includes a reference to one or both of the elements on either side of it within the list. The term &#8220;<a title="Doubly-linked list - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Doubly-linked_list">doubly-linked list</a>&#8221; is used to refer to the latter case. In the SPL, this takes the form of the class <a title="PHP: SplDoublyLinkedList - Manual" href="http://php.net/manual/en/class.spldoublylinkedlist.php"><code>SplDoublyLinkedList</code></a>.</p>
<p>Like <code>SplFixedArray</code>, <code>SplDoublyLinkedList</code> also implements the <a title="SPL-StandardPHPLibrary: Iterator Interface Reference" href="http://www.php.net/~helly/php/ext/spl/interfaceIterator.html"><code>Iterator</code></a>, <a title="SPL-StandardPHPLibrary: ArrayAccess Interface Reference" href="http://www.php.net/~helly/php/ext/spl/interfaceArrayAccess.html"><code>ArrayAccess</code></a>, and <a title="SPL-StandardPHPLibrary: Countable Interface Reference" href="http://www.php.net/~helly/php/ext/spl/interfaceCountable.html"><code>Countable</code></a> interfaces. In addition to the methods that come with these interface implementations, elements can be added to or removed from the start or end of the list using its <a title="PHP: SplDoublyLinkedList::push - Manual" href="http://php.net/manual/en/spldoublylinkedlist.push.php"><code>push()</code></a>, <a title="PHP: SplDoublyLinkedList::pop - Manual" href="http://php.net/manual/en/spldoublylinkedlist.pop.php"><code>pop()</code></a>, <a title="PHP: SplDoublyLinkedList::shift - Manual" href="http://php.net/manual/en/spldoublylinkedlist.shift.php"><code>shift()</code></a> and <a title="PHP: SplDoublyLinkedList::unshift - Manual" href="http://php.net/manual/en/spldoublylinkedlist.unshift.php"><code>unshift()</code></a> methods, which correspond to the <a title="PHP: array_push - Manual" href="http://php.net/array_push"><code>array_push()</code></a>, <a title="PHP: array_pop - Manual" href="http://php.net/array_pop"><code>array_pop()</code></a>, <a title="PHP: array_shift - Manual" href="http://php.net/array_shift"><code>array_shift()</code></a>, and <a title="PHP: array_unshift - Manual" href="http://php.net/array_unshift"><code>array_unshift()</code></a> functions respectively. Unfortunately, as of PHP 5.3.2, there&#8217;s no way to insert an element anywhere in the list other than at the beginning or the end. A <a title="PHP Bugs: #48358: SplDoublyLinkedList needs an insertAfterIterator() method or something similar" href="http://bugs.php.net/bug.php?id=48358">feature request</a> has been filed for this. Add a comment or vote to show support for its addition.</p>
<p>The elements at the start and end of the list are accessible via its <a title="PHP: SplDoublyLinkedList::top - Manual" href="http://php.net/manual/en/spldoublylinkedlist.top.php"><code>top()</code></a> and <a title="PHP: SplDoublyLinkedList::bottom - Manual" href="http://php.net/manual/en/spldoublylinkedlist.bottom.php"><code>bottom()</code></a> methods respectively, which correspond to the <a title="PHP: reset - Manual" href="http://php.net/manual/en/function.reset.php"><code>reset()</code></a> and <a title="PHP: end - Manual" href="http://php.net/manual/en/function.end.php"><code>end()</code></a> functions. Like <code>SplFixedArray</code>, elements can also be accessed arbitrarily by positional index using the array syntax granted by <code>ArrayAccess</code>. <strong>It makes sense to use lists when the number of elements to be stored is not known in advance and the elements only need to be accessed by sequential position.</strong></p>
<h3>Stacks</h3>
<p><a title="Stack (data structure) - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Stack_(data_structure)">Stacks</a> are similar to lists with two major differences. First, elements can only be added to the top of the stack. Second, an element can only be accessed by taking it off the top of the stack. Because of these differences, the stack is often referred to as a Last-In-First-Out or <a title="LIFO (computing) - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/LIFO_(computing)">LIFO</a> data structure. <a title="PHP: SplStack - Manual" href="http://php.net/manual/en/class.splstack.php"><code>SplStack</code></a> is the SPL stack implementation.</p>
<p><code>SplStack</code> is a bit removed from the traditional definition of a stack. It extends <code>SplDoublyLinkedList</code> and inherits its abilities, some of which don&#8217;t really apply to stacks. In order to enforce its restriction on how elements are accessed, <code>SplStack</code> overrides the <a title="PHP: SplDoublyLinkedList::setIteratorMode - Manual" href="http://php.net/manual/en/spldoublylinkedlist.setiteratormode.php"><code>setIteratorMode()</code></a> method of its parent class and implements <a title="PHP: SplStack::setIteratorMode - Manual" href="http://php.net/manual/en/splstack.setiteratormode.php">its own</a> to prevent modification of the iteration direction. Both methods allow elements to be retained or removed as they are iterated.</p>
<p><strong>Use of stacks makes sense when the number of elements to be stored is not known in advance and the only element that must be accessible is the last one stored.</strong> However, as of PHP 5.3.2, the performance of <code>SplStack</code> leaves something to be desired. Benchmarks included later in this provide an objective illustration of this, though the cause of the behavior remains unknown.</p>
<h3>Queues</h3>
<p><a title="Queue (data structure) - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Queue_(data_structure)">Queues</a> are also similar to lists, again with two major differences. First, elements can only be added (or &#8220;enqueued&#8221;) to the end of the queue. Second, an element can only be accessed by removing (or &#8220;dequeueing&#8221;) it from the beginning of the queue. For these reasons the queue is referred to as a First-In-First-Out or <a title="FIFO - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/FIFO">FIFO</a> data structure. The <a title="PHP: SplQueue - Manual" href="http://php.net/manual/en/class.splqueue.php"><code>SplQueue</code></a> class implements this data structure in the SPL.</p>
<p><code>SplQueue</code> follows suit with <code>SplStack</code> in extending <code>SplDoublyLinkedList</code>. Just as <code>SplStack</code> resultingly inherits some operations with at least questionable applicability, so too does <code>SplQueue</code>. Likewise, it overrides <code>setIteratorMode()</code> with <a title="PHP: SplQueue::setIteratorMode - Manual" href="http://php.net/manual/en/splqueue.setiteratormode.php">its own version</a> to restrict how elements are accessed. <strong>Use of queues makes sense when the number of elements to be stored is not known in advance and the only element that must be accessible is the remaining element that was stored earliest.</strong></p>
<p>One minor difference between <code>SplQueue</code> and <code>SplStack</code> is that the former contains two method aliases named after conceptual queue operations: <a title="PHP: SplQueue::dequeue - Manual" href="http://php.net/manual/en/splqueue.dequeue.php"><code>dequeue()</code></a> aliases <a title="PHP: SplDoublyLinkedList::shift - Manual" href="http://php.net/manual/en/spldoublylinkedlist.shift.php"><code>SplDoublyLinkedList::shift()</code></a> and <a title="PHP: SplQueue::enqueue - Manual" href="http://php.net/manual/en/splqueue.enqueue.php"><code>enqueue()</code></a> aliases <a title="PHP: SplDoublyLinkedList::push - Manual" href="http://php.net/manual/en/spldoublylinkedlist.push.php"><code>SplDoublyLinkedList::push()</code></a>. This makes sense because while <code>push()</code> and <code>pop()</code> share similar applicability to conceptual stack operations, they are already present in its parent class.</p>
<p>Despite their common ancestry, <code>SplQueue</code> appears to have better performance than <code>SplStack</code> as of PHP 5.3.2. Benchmarks included later in this post review this in more detail.</p>
<h3>Heaps</h3>
<p>Up to this point, the data structures discussed have resembled lists insofar as they contain elements in the order in which they were added. By contrast, when an element is added to a <a title="Heap (data structure) - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Heap_(data_structure)">heap</a>, a comparison function is used to compare the new element to other elements already in the heap and element is placed appropriately within the heap based on that function&#8217;s return value. The beauty of heaps is that their underlying algorithm does this with minimal element comparisons, so it&#8217;s extremely efficient. <strong>Using heaps makes sense when the number of elements to be stored is not known in advance and elements must be accessed in an order based on how they compare to each other.</strong></p>
<p><a title="PHP: SplHeap - Manual" href="http://php.net/manual/en/class.splheap.php"><code>SplHeap</code></a> is an abstract class used to create a heap by extending it and providing a comparison function in the form of its <a title="PHP: SplHeap::compare - Manual" href="http://php.net/manual/en/splheap.compare.php"><code>compare()</code></a> method. Only the root element of a heap, the one yielding the highest comparison function return value, may be accessed or removed from the heap at any given time. This is done using the <a title="PHP: SplHeap::extract - Manual" href="http://php.net/manual/en/splheap.extract.php"><code>extract()</code></a> method of <code>SplHeap</code>. <code>SplHeap</code> implements the <a title="SPL-StandardPHPLibrary: Iterator Interface Reference" href="http://www.php.net/~helly/php/ext/spl/interfaceIterator.html"><code>Iterator</code></a> and <a title="SPL-StandardPHPLibrary: Countable Interface Reference" href="http://www.php.net/~helly/php/ext/spl/interfaceCountable.html"><code>Countable</code></a> interfaces but, because only the root element can be extracted, it does not implement the <a title="SPL-StandardPHPLibrary: ArrayAccess Interface Reference" href="http://www.php.net/~helly/php/ext/spl/interfaceArrayAccess.html"><code>ArrayAccess</code></a> interface like the previously discussed data structure classes.</p>
<p>In addition to the abstract <code>SplHeap</code> class, two concrete implementations are also included in the SPL, namely <a title="PHP: SplMinHeap - Manual" href="http://php.net/manual/en/class.splminheap.php"><code>SplMinHeap</code></a> and <a title="PHP: SplMaxHeap - Manual" href="http://php.net/manual/en/class.splmaxheap.php"><code>SplMaxHeap</code></a>. The <a title="PHP: SplMinHeap::compare - Manual" href="http://php.net/manual/en/splminheap.compare.php"><code>compare()</code></a> method of <code>SplMinHeap</code> returns a value such that the smallest element in the heap is the root element. Likewise, the <a title="PHP: SplMaxHeap::compare - Manual" href="http://php.net/manual/en/splmaxheap.compare.php"><code>compare()</code></a> method of <code>SplMaxHeap</code> returns a value such that the largest element in the heap is the root element.</p>
<p>At first glance, using a subclass of <code>SplHeap</code> may seem equivalent to calling <a title="PHP: sort - Manual" href="http://php.net/sort"><code>sort()</code></a> or a similar function on an array and accessing the elements in sequence. This is indeed the case if all elements are added to the array prior to it being sorted. However, situations such as elements arriving over time or inadequate memory to store all elements simultaneously may preclude this approach. Use of arrays in such situations would require repeated resorting of the entire array as new elements are added, which is inefficient. This is why using the corresponding heap class makes a lot more sense in that situation than repeated calls to <a title="PHP: sort - Manual" href="http://php.net/sort"><code>sort()</code></a>, <a title="PHP: min - Manual" href="http://php.net/manual/en/function.min.php"><code>min()</code></a> or <a title="PHP: max - Manual" href="http://php.net/manual/en/function.max.php"><code>max()</code></a>. Additionally, <code>SplHeap</code> can be used to implement the <a title="Heapsort - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Heapsort">heapsort algorithm</a>, which has better worst case performance versus the <a title="Quicksort - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Quicksort">quicksort algorithm</a> <a title="[svn] Contents of /php/php-src/trunk/Zend/zend_qsort.c" href="http://svn.php.net/viewvc/php/php-src/trunk/Zend/zend_qsort.c?revision=296679&amp;view=markup#l56">implementation</a> <a title="[svn] Contents of /php/php-src/trunk/ext/standard/array.c" href="http://svn.php.net/viewvc/php/php-src/trunk/ext/standard/array.c?revision=298204&amp;view=markup#l541">used by arrays</a>.</p>
<h3>Priority Queues</h3>
<p><a title="Priority queue - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Priority_queue">Priority queues</a> are somewhat similar to heaps. In fact, while it doesn&#8217;t extend <code>SplHeap</code>, <a title="PHP: SplPriorityQueue - Manual" href="http://php.net/manual/en/class.splpriorityqueue.php"><code>SplPriorityQueue</code></a> does make use of a heap structure internally to implement its functionality. The difference is that the <a title="PHP: SplPriorityQueue::insert - Manual" href="http://www.php.net/manual/en/splpriorityqueue.insert.php"><code>insert()</code></a> method of <code>SplPriorityQueue</code> queue accepts both a value and an associated priority, removing the need to use an array or object to store both of these and define an appropriate comparison function in an <code>SplHeap</code> instance. Elements with the highest priority, like those in <code>SplMaxHeap</code> with the highest value, are the ones that come out first when <a title="PHP: SplPriorityQueue::extract - Manual" href="http://php.net/manual/en/splpriorityqueue.extract.php"><code>extract()</code></a> is called. Note that elements with equal priority are returned in no particular order.</p>
<p>For reasons similar to those of <code>SplHeap</code>, <code>SplPriorityQueue</code> implements both <a title="SPL-StandardPHPLibrary: Iterator Interface Reference" href="http://www.php.net/~helly/php/ext/spl/interfaceIterator.html"><code>Iterator</code></a> and <a title="SPL-StandardPHPLibrary: Countable Interface Reference" href="http://www.php.net/~helly/php/ext/spl/interfaceCountable.html"><code>Countable</code></a> interfaces and does not implement the <a title="SPL-StandardPHPLibrary: ArrayAccess Interface Reference" href="http://www.php.net/~helly/php/ext/spl/interfaceArrayAccess.html"><code>ArrayAccess</code></a> interface. Because it stores a value and priority per element, <code>SplPriorityQueue</code> includes a <a title="PHP: SplPriorityQueue::setExtractFlags - Manual" href="http://php.net/manual/en/splpriorityqueue.setextractflags.php"><code>setExtractFlags()</code></a> method that modifies the behavior of <code>extract()</code> to return the stored value, the stored priority, or an array containing both. Priorities are not bound to a particular data type: strings, integers, or even composite data types can be used. <code>SplPriorityQueue</code> can be extended and its <a title="PHP: SplPriorityQueue::compare - Manual" href="http://www.php.net/manual/en/splpriorityqueue.compare.php"><code>compare()</code></a> method overridden to customize the comparison logic.</p>
<p><strong>It makes sense to use a priority queue when the number of elements to be stored is not known in advance and elements must be accessed in an order based on how a value associated with each element (versus the element value itself) compares to the same associated values of other elements.</strong></p>
<h3>Sets and Composite Hash Maps</h3>
<p><a title="PHP: SplObjectStorage - Manual" href="http://php.net/manual/en/class.splobjectstorage.php"><code>SplObjectStorage</code></a> combines some of the properties of two different data structures. First, it provides the same functionality of a <a title="Hash table - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Hash_table">hash table</a> that a normal array has, but without its associated inability to use objects as keys unless the <a title="PHP: spl_object_hash - Manual" href="http://php.net/spl_object_hash"><code>spl_object_hash()</code></a> function is used. In other words, it implements a composite hash map. Second, it can be used as a <a title="Set (computer science) - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Set_(computer_science)">set</a> to store objects as data without a meaningful corresponding key or concept of sequential order.</p>
<p>Its <a title="PHP: SplObjectStorage::attach - Manual" href="http://php.net/manual/en/splobjectstorage.attach.php"><code>attach()</code></a> method accepts an object key and the data to associate with it and its <a title="PHP: SplObjectStorage::detach - Manual" href="http://php.net/manual/en/splobjectstorage.detach.php"><code>detach()</code></a> method allows data to be removed using its associated object key. To use the object as a set, simply exclude the <code>$data</code> parameter for <code>attach()</code> as it&#8217;s optional. The <a title="Set (computer science) - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Set_(computer_science)#Operations">set operations</a> implemented by <code>SplObjectStorage</code> all have array function counterparts. For example, the <a title="PHP: SplObjectStorage::addAll - Manual" href="http://php.net/manual/en/splobjectstorage.addall.php"><code>addAll()</code></a> method and <a title="PHP: array_merge - Manual" href="http://php.net/manual/en/function.array-merge.php"><code>array_merge()</code></a> function both correspond to the union set operation. The difference operation is available using the <a title="PHP: SplObjectStorage::removeAll - Manual" href="http://php.net/manual/en/splobjectstorage.removeall.php"><code>removeAll()</code></a> method and <a title="PHP: array_diff - Manual" href="http://php.net/manual/en/function.array-diff.php"><code>array_diff()</code></a> function and its variants. The <a title="PHP: SplObjectStorage::contains - Manual" href="http://php.net/manual/en/splobjectstorage.contains.php"><code>contains()</code></a> method and <a title="PHP: in_array - Manual" href="http://php.net/manual/en/function.in-array.php"><code>in_array()</code></a> function both implement the element_of operation. Sadly, only arrays have an implementation of the intersection operation in the form of <a title="PHP: array_intersect - Manual" href="http://php.net/manual/en/function.array-intersect.php"><code>array_intersect()</code></a> and its variants. Tobias Schlitt has a <a title="Python. Good, bad, evil -2-: Native sets - Blog - Open Source - schlitt.info" href="http://schlitt.info/opensource/blog/0722_python_good_bad_evil_02_native_sets.html">more in-depth analysis</a> of this data structure that includes implementations of the set operations lacking in the SPL itself.</p>
<p>Like some of the other data structures in the SPL, <code>SplObjectStorage</code> implements the <a title="SPL-StandardPHPLibrary: Iterator Interface Reference" href="http://www.php.net/~helly/php/ext/spl/interfaceIterator.html"><code>Iterator</code></a>, <a title="SPL-StandardPHPLibrary: Countable Interface Reference" href="http://www.php.net/~helly/php/ext/spl/interfaceCountable.html"><code>Countable</code></a>, and <a title="SPL-StandardPHPLibrary: ArrayAccess Interface Reference" href="http://www.php.net/~helly/php/ext/spl/interfaceArrayAccess.html"><code>ArrayAccess</code></a> interfaces. Oddly, it also implements the <a title="PHP: Traversable - Manual" href="http://php.net/manual/en/class.traversable.php"><code>Traversable</code></a> interface (which is limited to internally defined classes and negates the need for implementation of the <code>Iterator</code> interface) and the <a title="PHP: Serializable - Manual" href="http://php.net/manual/en/class.serializable.php"><code>Serializable</code></a> interface (and it is the only SPL data structure class to do so).</p>
<p><strong>Using this class makes sense when data must be stored using composite keys or the ability to access data using set operations is more important than accessing data in a specific order.</strong></p>
<h3>Benchmarks</h3>
<p><em>Standard disclaimer: There are <a title="Lies, damned lies, and statistics - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Lies,_damned_lies,_and_statistics">lies, damned lies, and benchmarks</a>. <a title="your mileage may vary - Wiktionary" href="http://en.wiktionary.org/wiki/your_mileage_may_vary"><acronym title="Your Mileage May Vary">YMMV</acronym></a>.</em></p>
<h4>Platform</h4>
<ul>
<li>System: <a title="VGN-NR298E/S | VAIO® NR Series Notebook PC | Sony | SonyStyle USA" href="http://www.sonystyle.com/webapp/wcs/stores/servlet/ProductDisplay?storeId=10151&amp;catalogId=10551&amp;langId=-1&amp;productId=8198552921665293693#specifications">Sony Vaio VGN-NR298E</a></li>
<li>CPU: <a title="Intel® Core™2 Duo Processor T5550 (2M Cache, 1.83 GHz, 667 MHz FSB) with SPEC Code(s) SLA4E" href="http://ark.intel.com/Product.aspx?id=32427&amp;processor=T5550&amp;spec-codes=SLA4E">Intel Core2Duo 1.83GHz</a></li>
<li>RAM: 4 GB DDR2</li>
<li>OS: <a title="Ubuntu Home Page | Ubuntu" href="http://www.ubuntu.com/">Ubuntu</a> 9.10 Karmic Koala Desktop Edition 64-bit</li>
<li>PHP: Custom build of <a title="PHP: Downloads" href="http://www.php.net/downloads.php#v5.3.2">5.3.2</a> (<a title="PHP 5.3 on Ubuntu — Third Party Code" href="http://thirdpartycode.com/2009/08/building-php-5-3-packages-on-ubuntu-9-04-jaunty-for-apache-2/">here&#8217;s how to create one</a>) using this configuration: <code>--without-pear --without-sqlite --without-sqlite3 --without-pdo-sqlite</code></li>
</ul>
<h4>Process</h4>
<p>Code used is located in <a title="elazar's spl-benchmarks at master - GitHub" href="http://github.com/elazar/spl-benchmarks">this GitHub repository</a>.</p>
<ol>
<li>Modify constant declarations at the top of runner.php as appropriate (50 executions per test were used to get the results below), then execute it from the command line. It will in turn execute each of the scripts in the tests directory, measuring execution time and memory usage. Results will be recorded in results/raw.csv.</li>
<li>To generate graphs, run graphs.php. This uses the <a title="eZ Components - Documentation - Tutorials" href="http://ezcomponents.org/docs/tutorials/Graph">Graph component</a> from the <a title="eZ Components" href="http://ezcomponents.org/">ezComponents library</a>. Resulting images will be written to the results directory in PNG format.</li>
</ol>
<h4>Results</h4>
<table>
<tbody>
<tr>
<td><img src="http://github.com/elazar/spl-benchmarks/raw/master/results/splfixedarray_eps.png" alt="SplFixedArray - Executions Per Second" width="400" height="225" /></td>
<td><img src="http://github.com/elazar/spl-benchmarks/raw/master/results/splfixedarray_memory.png" alt="SplFixedArray - Memory" width="400" height="225" /></td>
<td><strong>Code</strong><br />
<a title="tests/splfixedarray-array.php at master from elazar's spl-benchmarks - GitHub" href="http://github.com/elazar/spl-benchmarks/blob/master/tests/splfixedarray-array.php">Array</a><br />
<a title="tests/splfixedarray-spl.php at master from elazar's spl-benchmarks - GitHub" href="http://github.com/elazar/spl-benchmarks/blob/master/tests/splfixedarray-spl.php">SPL</a></td>
</tr>
<tr>
<td><img src="http://github.com/elazar/spl-benchmarks/raw/master/results/spldoublylinkedlist_eps.png" alt="SplDoublyLinkedList - Executions Per Second" width="400" height="225" /></td>
<td><img src="http://github.com/elazar/spl-benchmarks/raw/master/results/spldoublylinkedlist_memory.png" alt="SplDoublyLinkedList - Memory" width="400" height="225" /></td>
<td><strong>Code</strong><br />
<a title="tests/spldoublylinkedlist-array.php at master from elazar's spl-benchmarks - GitHub" href="http://github.com/elazar/spl-benchmarks/blob/master/tests/spldoublylinkedlist-array.php">Array</a><br />
<a title="tests/spldoublylinkedlist-spl.php at master from elazar's spl-benchmarks - GitHub" href="http://github.com/elazar/spl-benchmarks/blob/master/tests/spldoublylinkedlist-spl.php">SPL</a></td>
</tr>
<tr>
<td><img src="http://github.com/elazar/spl-benchmarks/raw/master/results/splstack_eps.png" alt="SplStack - Executions Per Second" width="400" height="225" /></td>
<td><img src="http://github.com/elazar/spl-benchmarks/raw/master/results/splstack_memory.png" alt="SplStack - Memory" width="400" height="225" /></td>
<td><strong>Code</strong><br />
<a title="tests/splstack-array.php at master from elazar's spl-benchmarks - GitHub" href="http://github.com/elazar/spl-benchmarks/blob/master/tests/splstack-array.php">Array</a><br />
<a title="tests/splstack-spl.php at master from elazar's spl-benchmarks - GitHub" href="http://github.com/elazar/spl-benchmarks/blob/master/tests/splstack-spl.php">SPL</a></td>
</tr>
<tr>
<td><img src="http://github.com/elazar/spl-benchmarks/raw/master/results/splqueue_eps.png" alt="SplQueue - Executions Per Second" width="400" height="225" /></td>
<td><img src="http://github.com/elazar/spl-benchmarks/raw/master/results/splqueue_memory.png" alt="SplQueue - Memory" width="400" height="225" /></td>
<td><strong>Code</strong><br />
<a title="tests/splqueue-array.php at master from elazar's spl-benchmarks - GitHub" href="http://github.com/elazar/spl-benchmarks/blob/master/tests/splqueue-array.php">Array</a><br />
<a title="tests/splqueue-spl.php at master from elazar's spl-benchmarks - GitHub" href="http://github.com/elazar/spl-benchmarks/blob/master/tests/splqueue-spl.php">SPL</a></td>
</tr>
<tr>
<td><img src="http://github.com/elazar/spl-benchmarks/raw/master/results/splminheap_eps.png" alt="SplMinHeap - Executions Per Second" width="400" height="225" /></td>
<td><img src="http://github.com/elazar/spl-benchmarks/raw/master/results/splminheap_memory.png" alt="SplMinHeap - Memory" width="400" height="225" /></td>
<td><strong>Code</strong><br />
<a title="tests/splminheap-array.php at master from elazar's spl-benchmarks - GitHub" href="http://github.com/elazar/spl-benchmarks/blob/master/tests/splminheap-array.php">Array</a><br />
<a title="tests/splminheap-spl.php at master from elazar's spl-benchmarks - GitHub" href="http://github.com/elazar/spl-benchmarks/blob/master/tests/splminheap-spl.php">SPL</a></td>
</tr>
<tr>
<td><img src="http://github.com/elazar/spl-benchmarks/raw/master/results/splpriorityqueue_eps.png" alt="SplPriorityQueue - Executions Per Second" width="400" height="225" /></td>
<td><img src="http://github.com/elazar/spl-benchmarks/raw/master/results/splpriorityqueue_memory.png" alt="SplPriorityQueue - Memory" width="400" height="225" /></td>
<td><strong>Code</strong><br />
<a title="tests/splpriorityqueue-array.php at master from elazar's spl-benchmarks - GitHub" href="http://github.com/elazar/spl-benchmarks/blob/master/tests/splpriorityqueue-array.php">Array</a><br />
<a title="tests/splpriorityqueue-spl.php at master from elazar's spl-benchmarks - GitHub" href="http://github.com/elazar/spl-benchmarks/blob/master/tests/splpriorityqueue-spl.php">SPL</a></td>
</tr>
<tr>
<td><img src="http://github.com/elazar/spl-benchmarks/raw/master/results/splobjectstorage_eps.png" alt="SplObjectStorage - Executions Per Second" width="400" height="225" /></td>
<td><img src="http://github.com/elazar/spl-benchmarks/raw/master/results/splobjectstorage_memory.png" alt="SplObjectStorage - Memory" width="400" height="225" /></td>
<td><strong>Code</strong><br />
<a title="tests/splobjectstorage-array.php at master from elazar's spl-benchmarks - GitHub" href="http://github.com/elazar/spl-benchmarks/blob/master/tests/splobjectstorage-array.php">Array</a><br />
<a title="tests/splobjectstorage-spl.php at master from elazar's spl-benchmarks - GitHub" href="http://github.com/elazar/spl-benchmarks/blob/master/tests/splobjectstorage-spl.php">SPL</a></td>
</tr>
</tbody>
</table>
<h3>Other Data Structures</h3>
<p>If you have an interest in other data structure implementations for PHP outside of SPL offerings, check out the <a title="PECL :: Package :: bloomy" href="http://pecl.php.net/package/bloomy">bloomy</a> <a title="PECL :: The PHP Extension Community Library" href="http://pecl.php.net/">PECL</a> extension, which is an implementation of a <a title="Bloom filter - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Bloom_filter">bloom filter</a> created by <a title="Bloom Filters Quickie - Andrei Zmievski" href="http://zmievski.org/2009/04/bloom-filters-quickie">Andrei Zmievski</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://matthewturland.com/2010/05/20/new-spl-features-in-php-5-3/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>&#8220;Web Scraping with PHP&#8221; Now Available!</title>
		<link>http://matthewturland.com/2010/04/20/web-scraping-with-php-now-available/</link>
		<comments>http://matthewturland.com/2010/04/20/web-scraping-with-php-now-available/#comments</comments>
		<pubDate>Tue, 20 Apr 2010 13:00:58 +0000</pubDate>
		<dc:creator>Matthew Turland</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://matthewturland.com/?p=275</guid>
		<description><![CDATA[What I&#8217;m announcing in this blog post has been in the works since early 2008 when I first pitched the idea. It was rejected by several major publishers who basically said the same thing: the idea was in too small of a niche or simply wasn&#8217;t marketable. php&#124;architect Press respectfully disagreed with them and decided [...]]]></description>
			<content:encoded><![CDATA[<p>What I&#8217;m announcing in this blog post has been in the works since early 2008 when I first pitched the idea. It was rejected by several major publishers who basically said the same thing: the idea was in too small of a niche or simply wasn&#8217;t marketable. <a title="books | php|architect" href="http://www.phparch.com/books/">php|architect Press</a> respectfully disagreed with them and decided to publish what is now <a title="php|architect’s Guide to Web Scraping with PHP | php|architect" href="http://www.phparch.com/books/phparchitects-guide-to-web-scraping-with-php/">a book</a> written by me that you can purchase.</p>
<p>It&#8217;s currently only available in PDF format due to a delay with the printer; a dead tree version should become available within the next few weeks. To my knowledge, there are plans to offer the paper and PDF bundle as has been done in the past with their other books.</p>
<p>Many of you reading this post probably have a personal to-do list of goals that you want to accomplish within your lifetime.  Becoming the published author of a book has been an item on my own list for some time, one that seeing this accomplishment through to its completion has helped me to cross out. I think anyone who has achieved a similar victory can relate to its significance, if only to oneself.</p>
<p>I do of course encourage you to purchase the book. I have no naïve notions that this will result in any substantial monetary return. Even if it did, that was not my reason for writing the book. I did it because I have knowledge that I believe is worth knowing and sharing with you. There were a number of people who contributed to this and I encourage you to read about them in the pages of the book that credit them.</p>
<p>It is also worth restating here that I have many family members, friends, and colleagues who helped to make this possible. There are too many to name, but I would like to thank each and every one of you from the bottom of my heart. I consider this a milestone in my life and my only hope is that it has as profound an effect on your life as it has on my own.</p>
]]></content:encoded>
			<wfw:commentRss>http://matthewturland.com/2010/04/20/web-scraping-with-php-now-available/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Models in Zend Framework</title>
		<link>http://matthewturland.com/2010/03/26/models-in-zend-framework/</link>
		<comments>http://matthewturland.com/2010/03/26/models-in-zend-framework/#comments</comments>
		<pubDate>Sat, 27 Mar 2010 00:00:25 +0000</pubDate>
		<dc:creator>Matthew Turland</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://matthewturland.com/?p=249</guid>
		<description><![CDATA[A question that frequently comes up in my interactions with other developers about Zend Framework is how to approach designing models. There&#8217;s a small collection of resources and advice that I generally give on the subject, so I thought I&#8217;d write up a blog post to give people an easy place to access it all. [...]]]></description>
			<content:encoded><![CDATA[<p>A question that frequently comes up in my interactions with other developers about <a title="Zend Framework" href="http://framework.zend.com/">Zend Framework</a> is <a title="Chapter 3. The Model - Zend Framework Book: Surviving The Deep End" href="http://www.survivethedeepend.com/zendframeworkbook/en/1.0/the.model">how to approach designing models</a>. There&#8217;s a small collection of resources and advice that I generally give on the subject, so I thought I&#8217;d write up a blog post to give people an easy place to access it all.</p>
<h3>More than one way to skin a cat</h3>
<p>First, there is no one &#8220;correct&#8221; way to design a model. If there were, the framework would probably have an actual model component. It doesn&#8217;t, and as Bill Karwin — former Project Manager for Zend Framework — has said, the reason for this because <a title="Keeping it Simple: ActiveRecord does not suck" href="http://karwin.blogspot.com/2008/05/activerecord-does-not-suck.html">designing the model is your job</a>. There are pros and cons to any approach. It&#8217;s all about finding a method that works for you, is appropriate for the situation at hand, and mitigates difficulty in long-term application maintenance.</p>
<p>The <a title="Zend Framework: Documentation: Create a Model and Database Table - Zend Framework Manual" href="http://framework.zend.com/manual/en/learning.quickstart.create-model.html">Model section</a> of the <a title="Zend Framework: Documentation: Zend Framework &amp; MVC Introduction - Zend Framework Manual" href="http://framework.zend.com/manual/en/learning.quickstart.intro.html">Quick Start Guide</a> and <a title="DragonBe's PHP blog: Zend Framework data models" href="http://www.dragonbe.com/2010/01/zend-framework-data-models.html">this blog post</a> by Michelangelo van Dam includes examples of a <a title="P of EAA: Data Mapper" href="http://martinfowler.com/eaaCatalog/dataMapper.html">Data Mapper</a> approach. <a title="Zend Framework: Documentation: Zend_Db - Zend Framework Manual" href="http://framework.zend.com/manual/en/zend.db.html"><code>Zend_Db</code></a> uses a <a title="P of EAA: Table Data Gateway" href="http://martinfowler.com/eaaCatalog/tableDataGateway.html">Table Data Gateway</a> and <a title="P of EAA: Row Data Gateway" href="http://martinfowler.com/eaaCatalog/rowDataGateway.html">Row Data Gateway</a> approach. <a title="Doctrine - PHP Object Relational Mapper" href="http://www.doctrine-project.org/">Doctrine</a>, a popular <acronym title="Object Relational Mapper">ORM</acronym> library that is <a title="Autoloading Doctrine and Doctrine entities from Zend Framework - phly, boy, phly" href="http://weierophinney.net/matthew/archives/220-Autoloading-Doctrine-and-Doctrine-entities-from-Zend-Framework.html">gaining</a> <a title="Doctrine Integration Todo - Zend Framework Wiki" href="http://framework.zend.com/wiki/display/ZFDEV/Doctrine+Integration+Todo">traction</a> in the ZF community, uses an <a title="Doctrine ORM for PHP" href="http://www.doctrine-project.org/documentation/manual/1_0/en/one-page#introduction:doctrine-explained">Active Record</a> approach. And available approaches don&#8217;t stop there. As a general rule of thumb when designing models and components in general, I recommend favoring <a title="Object composition - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Object_composition">composition</a> over <a title="Inheritance (object-oriented programming) - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Inheritance_(computer_science)">inheritance</a>. You&#8217;ll get a better sense of what I mean by that later in the post.</p>
<h3>Defining the model</h3>
<p>The <a title="Model–view–controller - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Model-view-controller">Wikipedia article</a> on the <acronym title="Model-View-Controller">MVC</acronym> architectural pattern isn&#8217;t all-encompassing, but isn&#8217;t a bad place to start either. In particular, it drives home a few important points about the model that you should bear in mind.</p>
<blockquote><p>The model is a &#8220;domain-specific representation of the data upon which the application operates.&#8221;</p></blockquote>
<p>In a nutshell, the model handles data: storing it, retrieving it, <a title="Using Zend_Form in Your Models - phly, boy, phly" href="http://weierophinney.net/matthew/archives/200-Using-Zend_Form-in-Your-Models.html">filtering and validating it</a>, and providing access to it.</p>
<blockquote><p>The model contains &#8220;<a title="Business logic - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Domain_logic">domain logic</a>&#8221; that &#8220;adds meaning to raw data.&#8221;</p></blockquote>
<p>In other words, it handles the conversion from raw data in a data source to semantically meaningful <a title="PHP: Hypertext Preprocessor" href="http://php.net/">PHP</a> objects and back again.</p>
<blockquote><p>&#8220;MVC does not specifically mention the data access layer because it is understood to be underneath or <a title="Information hiding - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Encapsulation_(computer_science)#Encapsulation">encapsulated</a> by the model.&#8221;</p></blockquote>
<p>The shorter version: <code>$model != $database</code>. This is one point that trips a lot of people up. The model and your database are not congruent, synonymous, or in any way equivalent. Yes, 99% of the time, your model will <em>use</em> a database for its data source. However, <a title="Model Infrastructure - phly, boy, phly" href="http://weierophinney.net/matthew/archives/202-Model-Infrastructure.html">models can be more complex than that</a>: they can serve as clients to web services, limit access to data <a title="Applying ACLs to Models - phly, boy, phly" href="http://weierophinney.net/matthew/archives/201-Applying-ACLs-to-Models.html">using an ACL</a>, access data caching resources like <a title="memcached - a distributed memory object caching system" href="http://memcached.org/">memcached</a> or <a title="PECL :: Package :: APC" href="http://pecl.php.net/package/apc">APC</a>, and so forth.</p>
<h3>Designing the model</h3>
<blockquote><p>&#8220;So which approach do you use?&#8221;</p></blockquote>
<p>Generally, the answer is none of the above. My personal preference is to keep data, in the form of plain old PHP arrays and <a title="PHP: Objects - Manual" href="http://php.net/manual/en/language.types.object.php#language.types.object.casting">objects</a>, separate from logic to handle that data. Many common PHP tasks result in data already being present in either of these forms such as in its <a title="PHP: Superglobals - Manual" href="http://www.php.net/manual/en/language.variables.superglobals.php">superglobal arrays</a>, so it seems natural to just take it in the form in which it&#8217;s provided.</p>
<p>I define a model class that composes some other object to access the data I need, generally a <a title="Zend Framework: Documentation: Zend_Db_Adapter - Zend Framework Manual" href="http://framework.zend.com/manual/en/zend.db.adapter.html"><code>Zend_Db_Adapter</code></a> instance. Any methods of that model class return data using <a title="PHP: Introduction - Manual" href="http://php.net/manual/en/language.types.intro.php">scalar types</a> or classes that PHP supports natively. What&#8217;s great about this is that it&#8217;s fairly easy to convert data to and from these forms using <a title="PHP: Type Juggling - Manual" href="http://php.net/manual/en/language.types.type-juggling.php">type juggling</a> regardless of the data&#8217;s origin.</p>
<blockquote><p>&#8220;But wait, how can I encapsulate the data source within my model if I need a dependency like a <code>Zend_Db_Adapter</code> instance for it to be able to interact with that data source?&#8221;</p></blockquote>
<p>This is another major question that people tend to ask. If any code calling your model first has to handle injecting its dependencies, that muddies up <a title="Separation of concerns - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Separation_of_concerns">separation of concerns</a> because calling code then must have some knowledge of how your model operates internally. This is a problem because, if the data source of the model needs to change in the future, all calling code needs to change as well versus only model code. There are a few ways to approach this problem in Zend Framework.</p>
<p>The first method involves storing your dependencies in <a title="The Registry Pattern Reexamined | BrandonSavage.net" href="http://www.brandonsavage.net/the-registry-pattern-reexamined/"><code>Zend_Registry</code></a>. Declare <a title="Mutator method - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Mutator_method">accessor methods</a> in the model for dependencies that retrieve them from the registry only if they are not explicitly injected from calling code. This bypasses the need for dependency injection from application code, thus preserving separation of concerns, but still allows injection to be performed for <a title="Testing Code That Uses Singletons » Sebastian Bergmann" href="http://sebastian-bergmann.de/archives/882-Testing-Code-That-Uses-Singletons.html#content">unit testing</a> purposes.</p>
<p>The second method is a variation of the first and is specific to the case of <code>Zend_Db_Adapter</code> instances. This approach involves setting your adapter as the default adapter to use for <code>Zend_Db_Table</code> instances in lieu of using the registry to store it. Note that this doesn&#8217;t require actually using <code>Zend_Db_Table</code> in order to work. This can be set from the <a title="Zend Framework: Documentation: Zend_Db_Table - Zend Framework Manual" href="http://framework.zend.com/manual/en/zend.db.table.html#zend.db.table.constructing.default-adapter">bootstrap</a> or <a title="Zend Framework: Documentation: Available Resource Plugins - Zend Framework Manual" href="http://framework.zend.com/manual/en/zend.application.available-resources.html#zend.application.available-resources.db">application configuration file</a>, then retrieved using the <a title="Docs For Class Zend_Db_Table_Abstract" href="http://framework.zend.com/apidoc/core/Zend_Db/Table/Zend_Db_Table_Abstract.html#getDefaultAdapter"><code>getDefaultAdapter()</code></a> method of the <code>Zend_Db_Table_Abstract</code> class. Again, don&#8217;t forget your accessor methods so dependencies can be injected from unit tests.</p>
<p>Another method might be to use a <a title="Inversion of Control Containers and the Dependency Injection pattern" href="http://martinfowler.com/articles/injection.html#UsingAServiceLocator">service locator</a> as a dependency in models. This serves as a layer of abstraction between models and their dependencies when it comes to controllers dealing with both. To my knowledge, the closest thing to an implementation of this in ZF is the <a title="Zend Framework: Documentation: Theory of Operation - Zend Framework Manual" href="http://framework.zend.com/manual/en/zend.application.theory-of-operation.html#zend.application.theory-of-operation.bootstrap">Zend_Application_Bootstrap</a> classes. From a controller, the bootstrap instance can be accessed as in the code example below.</p>
<pre class="brush: php;">$bootstrap = $this-&gt;getInvokeArg('bootstrap');</pre>
<h3>Where to go from here</h3>
<p><a title="My Zend Framework Model Layer: Part Service, Part ORM « Zend Framework &amp;Laquo; Php Programming &amp;Laquo; Web Development « rvdavid: A Web Developer's Blog" href="http://www.rvdavid.net/my-zend-framework-model-layer-part-service-part-orm/">Service layers</a> are another frequent topic related to models. Those aside, I mainly suggest picking a simple model that you can prototype and try several approaches to see which you prefer. If you&#8217;ve got some ZF experience under your belt, I&#8217;d be interested in hearing about your own modeling approaches and experiences and encourage you to leave a comment on this post.</p>
]]></content:encoded>
			<wfw:commentRss>http://matthewturland.com/2010/03/26/models-in-zend-framework/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Renaming a DOMNode in PHP</title>
		<link>http://matthewturland.com/2010/02/09/renaming-a-domnode-in-php/</link>
		<comments>http://matthewturland.com/2010/02/09/renaming-a-domnode-in-php/#comments</comments>
		<pubDate>Wed, 10 Feb 2010 01:07:14 +0000</pubDate>
		<dc:creator>Matthew Turland</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[DOM]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[Web Scraping]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://matthewturland.com/?p=218</guid>
		<description><![CDATA[A recent work assignment had me using PHP to pull HTML data into a DOMDocument instance and renaming some elements, such as b to strong or i to em. As it turns out, renaming elements using the DOM extension is rather tedious. Version 3 of the DOM standard introduces a renameNode() method, but the PHP [...]]]></description>
			<content:encoded><![CDATA[<p>A recent work assignment had me using PHP to pull HTML data into a <code><a title="PHP: DOMDocument - Manual" href="http://php.net/manual/en/class.domdocument.php">DOMDocument</a></code> instance and renaming some elements, such as <a title="HTML element - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/HTML_element#Presentation">b to strong or i to em</a>. As it turns out, renaming elements using the DOM extension is rather tedious.</p>
<p>Version 3 of the DOM standard introduces a <code><a title="Document Object Model Core" href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#Document3-renameNode">renameNode()</a></code> method, but the PHP DOM extension doesn&#8217;t currently support it.</p>
<p>The <code><a title="PHP: DOMNode - Manual" href="http://php.net/manual/en/class.domnode.php#domnode.props.nodename">$nodeName</a></code> property of the <code><a title="PHP: DOMNode - Manual" href="http://php.net/manual/en/class.domnode.php">DOMNode</a></code> class is read-only, so it can&#8217;t be changed that way.</p>
<p>A node can be created with a different name in the same document, but if you specify a value to go along with it, any entities in that value are automatically encoded, so it&#8217;s not possible to pass in the intended inner content of a node if it contains other nodes.</p>
<p>The only method I&#8217;ve found that works is to replicate the attributes and child nodes of the original node. Attributes are fairly easy, but I ran into an issue replicating children where only the first child of any given node was replicated within its intended replacement and the remaining children were omitted. Here&#8217;s the original code that was exhibiting this behavior.</p>
<pre class="brush: php;">foreach ($oldNode-&gt;childNodes as $childNode) {
    $newNode-&gt;appendChild($childNode);
}</pre>
<p>The reason for this behavior is that the <code><a title="PHP: DOMNode - Manual" href="http://php.net/manual/en/class.domnode.php#domnode.props.childnodes">$childNodes</a></code> property of <code>$oldNode</code> is implicitly modified when <code>$childNode</code> is transferred from it to <code>$newNode</code>, so the internal pointer of <code>$childNodes</code> to the next child in the list is no longer accurate.</p>
<p>To get around this, I took advantage of the fact that any node with any child nodes will always have a <code><a title="PHP: DOMNode - Manual" href="http://php.net/manual/en/class.domnode.php#domnode.props.firstchild">$firstChild</a></code> property pointing to the first one. The modified code that takes this approach is below and has the behavior I originally set out to implement.</p>
<pre class="brush: php;">while ($oldNode-&gt;firstChild) {
    $newNode-&gt;appendChild($oldNode-&gt;firstChild);
}</pre>
<p>If you&#8217;re curious, below is the full code segment for renaming a node.</p>
<pre class="brush: php;">$newNode = $oldNode-&gt;ownerDocument-&gt;createElement('new_element_name');
if ($oldNode-&gt;attributes-&gt;length) {
    foreach ($oldNode-&gt;attributes as $attribute) {
        $newNode-&gt;setAttribute($attribute-&gt;nodeName, $attribute-&gt;nodeValue);
    }
}
while ($oldNode-&gt;firstChild) {
    $newNode-&gt;appendChild($oldNode-&gt;firstChild);
}
$oldNode-&gt;ownerDocument-&gt;replaceChild($newNode, $oldNode);</pre>
<p>Another potential &#8220;gotcha&#8221; is the argument order of the <code><a title="PHP: DOMNode::replaceChild - Manual" href="http://php.net/manual/en/domnode.replacechild.php">replaceChild()</a></code> method, which is the new node followed by the old node rather than the reverse that most people might expect. Thanks to <a title="joshua may (notjosh) on Twitter" href="http://twitter.com/notjosh">Joshua May</a> for pointing that one out to me; I might never have understood why I was getting a <a title="PHP: DOMNode::appendChild - Manual" href="http://php.net/manual/en/domnode.appendchild.php#domnode.appendchild.errors">&#8220;Not Found Error&#8221;</a> <code><a title="PHP: DOMException - Manual" href="http://php.net/manual/en/class.domexception.php">DOMException</a></code> otherwise.</p>
]]></content:encoded>
			<wfw:commentRss>http://matthewturland.com/2010/02/09/renaming-a-domnode-in-php/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Splitting PHP Class Files</title>
		<link>http://matthewturland.com/2010/01/22/splitting-php-class-files/</link>
		<comments>http://matthewturland.com/2010/01/22/splitting-php-class-files/#comments</comments>
		<pubDate>Fri, 22 Jan 2010 23:26:29 +0000</pubDate>
		<dc:creator>Matthew Turland</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Github]]></category>
		<category><![CDATA[SOAP]]></category>
		<category><![CDATA[Tokenizer]]></category>
		<category><![CDATA[WSDL]]></category>

		<guid isPermaLink="false">http://matthewturland.com/?p=94</guid>
		<description><![CDATA[A recent work project required me to write a PHP script to interact with a remote SOAP service. Part of the service provider&#8217;s recommended practices entailed using a slightly dated software package called wsdl2php, which generates a single PHP file containing classes corresponding to all user-defined types from a specified WSDL file. The issue I ran into [...]]]></description>
			<content:encoded><![CDATA[<p>A recent work project required me to write a PHP script to interact with a remote <a title="SOAP - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/SOAP_(protocol)">SOAP</a> service. Part of the service provider&#8217;s recommended practices entailed using a slightly dated software package called <a title="wsdl2php | Get wsdl2php at SourceForge.net" href="http://sourceforge.net/projects/wsdl2php/">wsdl2php</a>, which generates a single PHP file containing classes corresponding to all user-defined types from a specified <a title="Web Services Description Language - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Web_Services_Description_Language">WSDL</a> file.</p>
<p>The issue I ran into was due to all the generated PHP classes being housed in a single file. I had to process two WSDL files that had several identical user-defined types in common. As a result, I couldn&#8217;t simply include the two PHP files generated from them because PHP doesn&#8217;t allow you to define two classes with the same name.</p>
<p>Looking at its source code, modifying wsdl2php to change this behavior was not a very appealing option. Attempting to consolidate the two WSDL files into one with no redundant user-defined type declarations seemed futile as well. Instead, I resolved to split the generated PHP files such that each class was contained in its own file. This would also allow me to use an autoloader to determine which of the classes I actually needed for the particular service call I was making.</p>
<p>Due to the number of classes, splitting the classes into separate files by hand would have been tedious and time-consuming. I decided to tap into my <a title="Coding Standard Analysis using PHP_CodeSniffer | Blue Parabola, LLC" href="http://blueparabola.com/blog/coding-standard-analysis-ing-phpcodesniffer">previous experience</a> with the <a title="PHP: Tokenizer - Manual" href="http://php.net/tokenizer">tokenizer extension</a> to throw together a CLI script that would handle this for me. Once I got it working, it clocked in at just over 50 <acronym title="Lines of Code">LOC</acronym> with comments and whitespace. You simply call it from a shell and pass it the PHP file you want to split and the destination for the split class files.</p>
<p>I thought it might be useful for others needed to process similarly formatted source code, so I threw it into a <a title="php-class-splitter.php at master from elazar's php-class-splitter - GitHub" href="http://github.com/elazar/php-class-splitter/blob/master/php-class-splitter.php">github repository</a> for anyone who might like to take a look. I&#8217;m open to suggestions for improvements to implement if enough people find it useful. Feel free to file an issue on the repository if you happen to find a bug.</p>
]]></content:encoded>
			<wfw:commentRss>http://matthewturland.com/2010/01/22/splitting-php-class-files/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>So Long, Blue Parabola</title>
		<link>http://matthewturland.com/2010/01/21/so-long-blue-parabola/</link>
		<comments>http://matthewturland.com/2010/01/21/so-long-blue-parabola/#comments</comments>
		<pubDate>Thu, 21 Jan 2010 15:43:22 +0000</pubDate>
		<dc:creator>Matthew Turland</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Career]]></category>

		<guid isPermaLink="false">http://matthewturland.com/?p=80</guid>
		<description><![CDATA[I&#8217;ve decided to leave Blue Parabola. My last day there will be Tuesday February 16. I&#8217;d like to thank Keith Casey and Marco Tabini for choosing me to be part of the team. It&#8217;s been a privilege to work with them and I&#8217;ve learned a great deal. As for what&#8217;s next, I&#8217;ll be starting at K-fx2. (Nope, no [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve decided to leave <a title="Blogs | Blue Parabola, LLC" href="http://blueparabola.com/">Blue Parabola</a>. My last day there will be Tuesday February 16. I&#8217;d like to thank <a title="Home | CaseySoftware, LLC - Supporters &amp; Developers of web2project" href="http://caseysoftware.com/">Keith Casey</a> and <a title="The Accidental Businessman" href="http://blog.tabini.ca/">Marco Tabini</a> for choosing me to be part of the team. It&#8217;s been a privilege to work with them and I&#8217;ve learned a great deal.</p>
<p>As for what&#8217;s next, I&#8217;ll be starting at <a title="Baton Rouge Web Design, Graphic Design, SEO, Software, Print/Video - Kfx² Incorporated - Design in Motion" href="http://www.kfx2.com/">K-fx</a><sup><a title="Baton Rouge Web Design, Graphic Design, SEO, Software, Print/Video - Kfx² Incorporated - Design in Motion" href="http://www.kfx2.com/">2</a></sup>. (Nope, no <a title="For the 'funemployed,' unemployment's welcomed - Los Angeles Times" href="http://articles.latimes.com/2009/jun/04/local/me-funemployment4">funemployment</a> for me.) There, I&#8217;ll be developing <a title="Zend Framework" href="http://framework.zend.com/">Zend Framework</a> applications and helping to streamline development processes and infrastructure.</p>
<p>Thanks to all my friends and family who&#8217;ve provided support during this transition. I&#8217;m looking forward to what the next year holds.</p>
]]></content:encoded>
			<wfw:commentRss>http://matthewturland.com/2010/01/21/so-long-blue-parabola/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Speaking at a Conference</title>
		<link>http://matthewturland.com/2010/01/20/speaking-at-a-conference/</link>
		<comments>http://matthewturland.com/2010/01/20/speaking-at-a-conference/#comments</comments>
		<pubDate>Wed, 20 Jan 2010 16:57:27 +0000</pubDate>
		<dc:creator>Matthew Turland</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Conferences]]></category>

		<guid isPermaLink="false">http://matthewturland.com/?p=83</guid>
		<description><![CDATA[I can&#8217;t make any claim to the title of veteran conference speaker. Not yet, at least. However, I have done it once before at ZendCon in 2008 and I&#8217;ll be doing it again at php&#124;tek this year. I thought I&#8217;d take a blog post to give out a few tips to any prospective first-time speakers [...]]]></description>
			<content:encoded><![CDATA[<p>I can&#8217;t make any claim to the title of veteran conference speaker. Not yet, at least. However, I have done it once before at <a title="ZendCon 2010 ::" href="http://www.zendcon.com/">ZendCon</a> in 2008 and I&#8217;ll be doing it again at <a title="PHP Conference — Chicago IL May 18-22 2010 — PHP, MySQL, Linux, Windows, Drupal, WordPress" href="http://tek.phparch.com/">php|tek</a> this year. I thought I&#8217;d take a blog post to give out a few tips to any prospective first-time speakers based on my first speaking experience. I&#8217;m assuming there that you&#8217;ve already decided on a particular conference that you <a title="Why Should I Attend a Conference? | CaseySoftware, LLC - Supporters &amp; Developers of web2project" href="http://caseysoftware.com/blog/why-should-i-attend-a-conference">want to attend</a>, you&#8217;ve <a title="How to Submit a Conference Talk - LornaJane" href="http://www.lornajane.net/posts/2008/How-to-Submit-a-Conference-Talk">submitted a session proposal</a>, and you&#8217;ve been accepted.</p>
<p>First, in addition to the <a title="Conference Travel Tips | CaseySoftware, LLC - Supporters &amp; Developers of web2project" href="http://caseysoftware.com/blog/conference-travel-tips">other things you should do</a> before attending, <strong>be ready to give your presentation before you get on the plane</strong>. You should start on your slides as far in advance as possible. Don&#8217;t put it off or wait until the last minute, because it will likely be more work than you anticipate. This includes making sure that any live demos you intend to give will run as expected. Syntax errors and crashing web servers look very bad to the audience.</p>
<p>One of the reasons for this is that you&#8217;ll want to <strong>practice your talk out loud</strong>. It&#8217;s one thing to put the material onto slides, but it may sound different when it&#8217;s actually coming out of your mouth and going into the crowd. You may find stumbling points, places where you stutter or get caught off-guard when transitioning from one topic to another. Try to organize the presentation such that it matches your natural flow when talking about the topic without any slides at all.</p>
<p>Which reminds me, <strong>learn from the masters</strong>. People like Marco Tabini have spoken before and have a <a title="Some tips for great presentations « The Accidental Businessman" href="http://blog.tabini.ca/2009/11/some-tips-for-great-presentations/">wealth of knowledge</a> that they&#8217;ll share fairly freely most of the time, especially if alcohol (or, in Marco&#8217;s case, an espresso) is involved. Look at books like <a title="Amazon.com: Presentation Zen: Simple Ideas on Presentation Design and Delivery (9780321525659): Garr Reynolds: Books" href="http://www.amazon.com/Presentation-Zen-Simple-Design-Delivery/dp/0321525655/ref=sr_1_2?ie=UTF8&amp;s=books&amp;qid=1263860360&amp;sr=8-2">Presentation Zen</a> by Garr Reynolds. Take the time to hone your presentation skills before you have to make your delivery.</p>
<p>If you&#8217;ve been to a conference before, you&#8217;ve probably already learned about my next point the hard way. <strong>Don&#8217;t depend on wifi internet access availability</strong>. Why not? Because the vast majority of the time, <a title="Wifi at conferences: why it sucks « The Accidental Businessman" href="http://blog.tabini.ca/2009/10/wifi-at-conferences-why-it-sucks/">it will suck</a>. There won&#8217;t be enough IP addresses, someone will do something to hog bandwidth and make latency skyrocket, it will find some way to refuse to work. Save local copies of files, write a minimal daemon to simulate a remote server, do whatever you need to do to avoid it.</p>
<p>That point goes hand in hand with this one: <strong>test your equipment early and have a Plan B</strong>. In particular, hook your laptop up to the projector in the room in which you&#8217;ll be speaking (or to a test projector, if the conference hosts provide one and prefer you use that) to make sure it can display your slides. <a title="Ben Ramsey" href="http://benramsey.com/">Ben Ramsey</a> was gracious enough to loan me his Macbook at ZendCon because my Sony Vaio refused to work with the projector and the time-sensitive situation did nothing but add to my speaking nerves. Make sure you don&#8217;t end up in the same spot.</p>
<p>Lastly, <strong>don&#8217;t let critical reception deter you from speaking again</strong>. I got pretty negative feedback the first time around, but I took it in stride. While I know I have plenty of room for improvement, I&#8217;m still going to give it another shot. Do your very best, then strive to be better.</p>
<p>Hope you enjoyed this blog post and gleaned something useful from it. If you&#8217;ve got any of your own speaking tips, please feel free to add a comment on this post. If you&#8217;ll be attending php|tek, I look forward to seeing you there!</p>
]]></content:encoded>
			<wfw:commentRss>http://matthewturland.com/2010/01/20/speaking-at-a-conference/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
	</channel>
</rss>
