<?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>Dominique Stender &#187; PHP</title>
	<atom:link href="http://www.st-webdevelopment.com/tag/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.st-webdevelopment.com</link>
	<description>Good software is only the beginning...</description>
	<lastBuildDate>Wed, 14 Apr 2010 17:50:37 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=abc</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Thoughts on HipHop for PHP</title>
		<link>http://www.st-webdevelopment.com/php/2010/02/thoughts-hiphop-php/</link>
		<comments>http://www.st-webdevelopment.com/php/2010/02/thoughts-hiphop-php/#comments</comments>
		<pubDate>Mon, 15 Feb 2010 17:26:39 +0000</pubDate>
		<dc:creator>Dominique</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[accelerator]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[facebook]]></category>

		<guid isPermaLink="false">http://www.st-webdevelopment.com/?p=321</guid>
		<description><![CDATA[An overview of the PHP-to-C++ transformer HipHop for PHP that was recently announced by Facebook. I give an analysis of it's potential along with the requirements and possible limitations.]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-327" title="HipHop_logo_white" src="http://www.st-webdevelopment.com/wp-content/uploads/2010/02/HipHop_logo_white.png" alt="" width="213" height="278" />It has been almost two weeks now since Facebook announced <a title="Announcement for the HipHop for PHP code transformer" href="http://developers.facebook.com/news.php?blog=1&amp;story=358" target="_blank" onclick="pageTracker._trackPageview('/outgoing/developers.facebook.com/news.php?blog=1_amp_story=358&amp;referer=');">HipHop for PHP</a>. The source code is still not available because apparently they've ran into some compilation issues, according to <a title="HipHop for PHP on GitHub" href="http://github.com/facebook/hiphop-php" target="_blank" onclick="pageTracker._trackPageview('/outgoing/github.com/facebook/hiphop-php?referer=');">their GitHub</a> status. So in essence, not much is known about HipHop for PHP but I want to try to give my thoughts based on the small amount of information we have and my experience with similar technologies.</p>
<blockquote><p>Please note that the bits and pieces of information come from various sources and things may or may not be exactly as we think they are.</p></blockquote>
<p>In order to understand what HipHop for PHP does it is important to understand how PHP itself gets executed. In this article I will give a rough overview of the PHP execution process and make a few educated guesses in what aspect HipHop for PHP differs from there.</p>
<p>Based on the little information available online I'll discuss how HipHop for PHP is suitable for large businesses and what might turn out to be obstacles that are yet to remove.</p>
<h4><span id="more-321"></span>The PHP execution process</h4>
<p>PHP code can not be executed directly, a property it shares with all other scripting languages such as Python, Ruby and JavaScript. What makes PHP executable is the Zend Engine, and it does so in a two stage process.</p>
<ol>
<li>The scripts are parsed and analyzed, checked for syntactical and semantical errors and if all goes well the application is transformed into byte code.</li>
<li>Since the byte code is still not executable on a CPU, it is interpreted further into machine code (that is CPU dependent) and then executed.</li>
</ol>
<p>For most PHP applications the first parsing stage takes most of the total time. The second execution stage is comparatively fast. So in order to speed up a PHP application, most code optimizers hook into the Zend Engine after the first stage has been completed and save the generated byte code into a cache. In a consecutive call to the webserver the cache will be fed back into the Zend Engine, thus skipping the entire first stage of the execution process.</p>
<p>There are quite a few products on the market that behave in such a way. Zend itself offers the <a title="Zend Optimizer" href="http://www.zend.com/en/products/guard/zend-optimizer" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.zend.com/en/products/guard/zend-optimizer?referer=');">Zend Optimizer</a> (now part of Zend Guard), there is <a title="eAccelerator PHP optimizer" href="http://eaccelerator.net/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/eaccelerator.net/?referer=');">eaccelerator</a> and <a title="APC, the Alternative PHP Cache" href="http://pecl.php.net/package/APC" target="_blank" onclick="pageTracker._trackPageview('/outgoing/pecl.php.net/package/APC?referer=');">APC</a>, which comes as a PECL package.</p>
<h4>The execution process with HipHop for PHP</h4>
<p>What sets HipHop for PHP apart from these three (and no doubt other) accelerators is that it does not act as a cache. Instead, HipHop for PHP will transform your PHP application into C++ code and compile that directly into a binary which is executable.</p>
<p>In that sense, HipHop for PHP is probably very similar to <a title="Roadsend PHP" href="http://www.roadsend.com/home/index.php?pageID=compiler" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.roadsend.com/home/index.php?pageID=compiler&amp;referer=');">Roadsend PHP</a> which also generates executable code from PHP, albeit not by transforming it into C++ first.</p>
<p>In essence, HipHop for PHP will get rid not only of the first stage of the usual execution stage, but also of a big part of the second stage, namely the interpretation of byte code into machine code. Generally I believe it is safe to assume that HipHop for PHP has the potential to run an application much faster than any of the previously mentioned accelerators, simply because there is less for to be done at runtime. Time will tell.</p>
<p>For detailed information on the internals of HipHop for PHP make sure you watch the <a title="Video of the HipHop for PHP announcement" href="http://www.ustream.tv/recorded/4409735" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.ustream.tv/recorded/4409735?referer=');">Facebook Technology Tasting</a> video on ustream.</p>
<h4>Possible limitations</h4>
<p><strong>The requirements</strong><br />
The <a title="HipHop for PHP requirements" href="http://wiki.github.com/facebook/hiphop-php/building-and-installing" target="_blank" onclick="pageTracker._trackPageview('/outgoing/wiki.github.com/facebook/hiphop-php/building-and-installing?referer=');">requirements to run HipHop for PHP</a> are available online. Nothing out of the ordinary at first sight. The page claims that HipHop for PHP is tested on <a title="The CentOS Linux distribution" href="http://centos.org" target="_blank" onclick="pageTracker._trackPageview('/outgoing/centos.org?referer=');">CentOS </a>and <a title="the Fedora Linux distribution" href="http://fedoraproject.org/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/fedoraproject.org/?referer=');">Fedora</a>. Both are venerable distributions, no doubt. But both also come without vendor support which may or may not be a problem for your organization.</p>
<p>Granted, companies who's codebase can actually benefit from HipHop for PHP will no doubt have a team of excellent system administrators which maintain Linux in their sleep. But those companies might also be in the situation that their customers demand a Linux distribution with commercial support, such as SLES, RedHat etc.</p>
<p>So this is more an organizational issue rather than a technical. That being said it is not clear yet whether or not packages will be released by other Linux distribution vendors once HipHop for PHP is out. If at all, it probably won't happen soon.</p>
<p>Coming back to the requirements for HipHop for PHP, it requires customized packages of libcurl and libevent, which again may or may not be an issue for your environment. Here I see the same organizational issue, but also a possible technical issue - you might be in the situation that you need the original libcurl or libevent for some other software on the server. Only a practical test will tell.</p>
<p><strong>Unsupported language constructs</strong><br />
As with most PHP caches and compilers, a few PHP language constructs are not supported. Most commonly known is the eval() construct which is simply not available in C++. Personally I believe that eval() is a bad thing to begin with and you can get around it in almost every cases. Sadly many PHP frameworks such as <a title="TYPO3 content management system" href="http://www.typo3.org" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.typo3.org?referer=');">TYPO3</a>, many <a title="PEAR - the PHP extension and application repository" href="http://pear.php.net" target="_blank" onclick="pageTracker._trackPageview('/outgoing/pear.php.net?referer=');">PEAR</a> packages, <a title="Drupal content management system" href="http://drupal.org/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/drupal.org/?referer=');">Drupal</a> and <a title="The Joomla content management system" href="http://www.joomla.org/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.joomla.org/?referer=');">Joomla</a> make use of eval().</p>
<p>If you're intending to run one of these through HipHop for PHP you might need to wait for an update from the community, patch it yourself, or remove the code from the system if you don't need it. In any case this is a time consuming task.</p>
<p>Aside from eval() a few more language constructs may not be supported or may not benefit from the compilation in terms of performance, such as call_user_func_array() and other 'dynamic' constructs like dynamic variables, dynamic includes or built-in functions like function_exists(), class_exists(), get_declared_classes() etc.</p>
<p>HipHop for PHP is no different from other caches and compilers in these regards, so please don't make that affect your choice. Just be aware that things might not be as easy as you'd like them to be.</p>
<p><strong>No Apache?</strong><br />
This is speculative at this point but the <a title="Running HipHop [for PHP]" href="http://wiki.github.com/facebook/hiphop-php/running-hiphop" target="_blank" onclick="pageTracker._trackPageview('/outgoing/wiki.github.com/facebook/hiphop-php/running-hiphop?referer=');">Running HipHop</a> page on GitHub seems to indicate that HipHop for PHP will not make use of the Apache webserver but instead come with its own webserver. My assumption is that this means we'll have to handle HipHop for PHP through Apache, much in the same way that we frequently do with Tomcat. This is not necessarily an issue.</p>
<h4>The potential of HipHop for PHP</h4>
<p>Despite the limitations I mentioned above, I believe HipHop for PHP has the potential to take PHP much further into the enterprise environment than many of the existing solutions. If it can deliver what it promises it is definitely something we will take a very close look at to give our eCommerce framework a serious performance boost.</p>
<p>Very high on my wishlist is to run the transformation process from PHP to C++ but skip the compilation. If that's possible I see the chance to make debugging compile errors much easier.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.st-webdevelopment.com/php/2010/02/thoughts-hiphop-php/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Another reason to upgrade to PHP 5.3</title>
		<link>http://www.st-webdevelopment.com/php/2009/12/upgrade-reason-php-53/</link>
		<comments>http://www.st-webdevelopment.com/php/2009/12/upgrade-reason-php-53/#comments</comments>
		<pubDate>Tue, 29 Dec 2009 10:45:33 +0000</pubDate>
		<dc:creator>Dominique</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[object orientation]]></category>
		<category><![CDATA[OOP]]></category>
		<category><![CDATA[static property]]></category>

		<guid isPermaLink="false">http://www.st-webdevelopment.com/?p=282</guid>
		<description><![CDATA[Dominique Stender outlines why to upgrade to PHP 5.3 by showcasing an issue in the handling of static properties with PHP 5.2]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-287" title="php code" src="http://www.st-webdevelopment.de/wp-content/uploads/2009/12/static.jpg" alt="php code" width="190" height="400" />In case you haven't found any specific reason to switch to PHP 5.3, I have one: Static properties.</p>
<p>Consider the following scenario: You have a group of classes, each responsible for returning a specific statistic. All these classes implement the same API, as given by a common abstract class.</p>
<p>Now, some of these statistics are publicly accessible, others require a certain access control permission to be set.</p>
<p>The logical approach would be to implement a static property to the abstract class, denying access by default. Those classes that are indeed public will overwrite the static property with the correct setting and become accessible.</p>
<p>The property is static to gain speed: There is no need to instantiate the class, if the access control is not satisfied.</p>
<p>Stripped down to the bare essentials the whole set of classes to outline the issue looks like this:</p>
<pre name="code" class="php">abstract class StatisticBase {
    public static $acl = '0';
} // end: class StatisticBase

class PublicStatistic extends StatisticBase {
    public static $acl = '1';
} // end: class StatisticBase

class AdminStatistic extends StatisticBase {
    // default value for $acl is fine
} // end: class AdminStatistic</pre>
<p>AdminStatistic is an implemented class that is private, indicated by the $acl property being 0. PublicStatistic on the other hand is public, hence $acl is 1.</p>
<p>Now before instantiating a specific class we can check whether or not the access condition is satisfied:</p>
<pre name="code" class="php">if ($user-&gt;isAdmin == true || PublicStatistic::$acl == 1) {
    // retrieve admin statistic...
} // end: if</pre>
<p>But naturally this is cumbersome as soon as you have more than a handful of statistics - you don't want to add another condition to your if-statement whenever you add a statistic. So the logical solution is a loop:</p>
<pre name="code" class="php">$statistics = array(
    'PublicStatistic',
    'AdminStatistic'
);

foreach ($statistics as $statClassName) {

    if ($user-&gt;acl == 1 || $statClassName::$acl == 0) {
        // retrieve current statistic...
    } // end: if
} // end: foreach</pre>
<p>Here PHP 5.2 will fail with a fatal error.</p>
<p>You can't access static class properties by means of using a variable for the classname. PHP 5.3 can. There is no really elegant solution for this. (If you know one, post it in the comments!)</p>
<p>While I'm glad that PHP 5.3 has one more OOP feature covered, It leaves me with the feeling that we still have a long way to go until PHP fully supports object orientation.</p>
<p>Now, if Novel would please release a PHP 5.3 package for SLES 10 and SLES 11... thank you</p>
]]></content:encoded>
			<wfw:commentRss>http://www.st-webdevelopment.com/php/2009/12/upgrade-reason-php-53/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Improved social bookmarks for Wordpress</title>
		<link>http://www.st-webdevelopment.com/general/2009/12/changed-social-bookmarks/</link>
		<comments>http://www.st-webdevelopment.com/general/2009/12/changed-social-bookmarks/#comments</comments>
		<pubDate>Thu, 10 Dec 2009 02:26:05 +0000</pubDate>
		<dc:creator>Dominique</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Social Web]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[social bookmarks]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://www.st-webdevelopment.com/?p=230</guid>
		<description><![CDATA[A short article how I used wordpress plugins AddThis and Wp-To-Twitter to improve the options for social bookmarking in this blog.]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-233" title="statistics" src="http://www.st-webdevelopment.com/wp-content/uploads/2009/12/stats.jpg" alt="statistics" width="190" height="400" />I further enhanced the social bookmarking options in this blog by dropping the <a title="The Wordpress 'Tweet This' plugin" href="http://wordpress.org/extend/plugins/tweet-this/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/wordpress.org/extend/plugins/tweet-this/?referer=');">Tweet This</a> plugin that I mentioned in an <a title="Optimize your Wordpress Blog Performance" href="/php/2009/12/optimize-wordpress-blog-performance/" target="_self">earlier post</a> in favor of the wordpress <a title="The Wordpress plugin for AddThis" href="http://wordpress.org/extend/plugins/addthis/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/wordpress.org/extend/plugins/addthis/?referer=');">plugin </a>for <a title="AddThis Bookmarking &amp; Sharing Service" href="http://addthis.com/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/addthis.com/?referer=');">AddThis</a>. This was done because the CSS sprite hack I did on Tweet This kept bugging me although it worked just fine - I hate hacks. Besides, the many icons don't really make the blog look better.</p>
<p>The AddThis "Social Bookmarking &amp; Sharing Service" provides the possibility to share my blog to virtually all social bookmark services (currently over 200) with a single (!) button and also has an easy option to send links via email. Similar to <a title="Share This Bookmarking Service" href="http://sharethis.com/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/sharethis.com/?referer=');">ShareThis</a>, <a title="AddThis Bookmarking &amp; Sharing Service" href="http://addthis.com/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/addthis.com/?referer=');">AddThis</a> provides me with an analytics-like overview of which articles have been shared when and where. Pretty neat. The documentation on AddThis is better than the one for ShareThis though so I went for the former.</p>
<p>Since with removing the Tweet This plugin the "auto-post to Twitter" option is gone I installed <a title="The WP To Twitter Wordpress Plugin" href="http://wordpress.org/extend/plugins/wp-to-twitter/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/wordpress.org/extend/plugins/wp-to-twitter/?referer=');">WP To Twitter</a> to compensate for that. In fact WP To Twitter has more options than Tweet This, making things even more flexible for me.</p>
<p>If social bookmarking is a concern for you, check out <a title="AddThis Bookmarking &amp; Sharing Service" href="http://addthis.com/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/addthis.com/?referer=');">AddThis</a> and <a title="The WP To Twitter Wordpress Plugin" href="http://wordpress.org/extend/plugins/wp-to-twitter/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/wordpress.org/extend/plugins/wp-to-twitter/?referer=');">WP To Twitter</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.st-webdevelopment.com/general/2009/12/changed-social-bookmarks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Optimize your Wordpress Blog Performance</title>
		<link>http://www.st-webdevelopment.com/php/2009/12/optimize-wordpress-blog-performance/</link>
		<comments>http://www.st-webdevelopment.com/php/2009/12/optimize-wordpress-blog-performance/#comments</comments>
		<pubDate>Thu, 03 Dec 2009 13:36:02 +0000</pubDate>
		<dc:creator>Dominique</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[CSS sprites]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://www.st-webdevelopment.com/?p=195</guid>
		<description><![CDATA[A handful of worthy tips how to improve your Wordpress blog performance while keeping W3C compliance. I talk about how to reduce both the required bandwidth as well as pushing down the number of requests to a minimum.]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-196" title="snowflake" src="http://www.st-webdevelopment.com/wp-content/uploads/2009/12/snowflake.jpg" alt="snowflake" width="190" height="400" />The famous blogging software <a title="The Wordpress blogging software" href="http://wordpress.org/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/wordpress.org/?referer=');">Wordpress </a>has always been my tool of choice when setting up a blog-like website. The usability of the backend and the number of available themes and plugins make it ideal if you want to see quick results.</p>
<p>However, when it comes to SEO and bandwidth optimization and standard compliance many of the plugins fall short and require some additional attention. The good news is that usually many plugins are available to scratch a single itch. Picking the right one often avoids many glitches.</p>
<h4>Social network plugins and social bookmarks</h4>
<p>I want to reach out to people with this blog. This includes enabling my honored readers to quickly share my articles with their community through the various social networks.</p>
<p><a title="The TweetMeMe Wordpress Plugin" href="http://wordpress.org/extend/plugins/tweetmeme/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/wordpress.org/extend/plugins/tweetmeme/?referer=');">TweetMeMe Button</a> and <a title="The Facebook Share Wordpress plugin" href="http://wordpress.org/extend/plugins/facebook-share-new/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/wordpress.org/extend/plugins/facebook-share-new/?referer=');">Facebook Share</a> are two plugins that put nifty buttons in your blog that include counters to boast about how many people shared your content. Both are really great and work perfectly, but I encountered some issues due to which I removed both from this website after a test period of a couple of days.</p>
<p>I had to remove the <a href="http://wordpress.org/extend/plugins/tweetmeme/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/wordpress.org/extend/plugins/tweetmeme/?referer=');">TweetMeMe Button</a> simply because it loads content from the tweetmeme.com server which is currently very slow, thus slowing down my website as well. There is nothing the author of this plugin can do about it I guess.</p>
<p><a title="The Facebook Share Wordpress plugin" href="http://wordpress.org/extend/plugins/facebook-share-new/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/wordpress.org/extend/plugins/facebook-share-new/?referer=');">Facebook Share</a> on the other hand was removed because it uses an id="" attribute for the button it displays, even if the button is on the page multiple times. Since this is violating W3C compliance this plugin had to go, too.</p>
<p>In addition to that, both plugins cause my layout to look a little bit messy and 'cheap', which I try to avoid. Again, that is nothing that can be fixed by the plugin authors since it is just my personal opinion. I really liked both plugins but these minor glitches made me move on to...</p>
<h4>Tweet This - CSS sprites</h4>
<p>I found another nice extension for social bookmarks called <a href="http://wordpress.org/extend/plugins/tweet-this/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/wordpress.org/extend/plugins/tweet-this/?referer=');">Tweet This</a>. The author <a title="Richard Thripp (author of the Tweet This Wordpress plugin) on Twitter" href="http://twitter.com/richardxthripp" target="_blank" onclick="pageTracker._trackPageview('/outgoing/twitter.com/richardxthripp?referer=');">Richard X. Thripp</a> did a really great job on this, offering bookmark icons for not one but many social networks. That covers my bases.</p>
<p>However I enhanced this plugin slightly in order to utilize CSS sprites for the social bookmark icons. My friend Chris recently talked about <a title="Chris about CSS sprites." href="http://www.swift-lizard.com/2009/11/20/nice-article-about-using-css-sprites/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.swift-lizard.com/2009/11/20/nice-article-about-using-css-sprites/?referer=');">CSS sprites</a> on <a title="SwiftLizard.com - Design &amp; Development" href="http://www.swift-lizard.com/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.swift-lizard.com/?referer=');">his blog SwiftLizard.com</a>. Here is the concept in a nutshell:</p>
<p>If you display ten icons on your website the traditional way the browser has to request ten files from the server - one for each icon. Since usually browsers do only a handful of requests at a time this slows down your website. With CSS sprites however, you can utilize CSS and one single graphic containing all icons to achieve the same effect with only one image being requested. This results in website response times that are much lower, thus enabling a smoother surfing experience.</p>
<h4>Further optimization of Social bookmarks [added]</h4>
<p>Since I posted this article I further enhanced <a title="Improved Social Bookmark handling in Wordpress" href="/general/2009/12/changed-social-bookmarks/" target="_self">the way I handle social bookmarks</a> in this blog, you might want to check that out.</p>
<h4>WP Super Cache</h4>
<p>The plugin <a title="The WP Super Cache Wordpress plugin" href="http://wordpress.org/extend/plugins/wp-super-cache/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/wordpress.org/extend/plugins/wp-super-cache/?referer=');">WP Super Cache</a> almost needs no introduction. Written by Donncha O. Caoimh it enables us to circumvent PHP completely and serve static content in many cases. Naturally, this is much faster. The plugin is a must for anyone taking performance seriously. WP Super Cache alone reduced the initial response of my blog (time-to-first-byte) by 80%.</p>
<h4>iPhone and mobile browsers</h4>
<p>As the owner of a technology related website I believe it is reasonable (and my access statistics seem to agree) to believe that some of my visitors will visit the website from a mobile device such as the iPhone or a Blackberry. While technically the layout I chose for this blog looks ok in my iPhone, there is a lot of clutter that I don't want to wait for on my mobile device.</p>
<p>Thankfully there is a plugin called <a title="The WPTouch Wordpress plugin" href="http://wordpress.org/extend/plugins/wptouch/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/wordpress.org/extend/plugins/wptouch/?referer=');">WPtouch </a>which displays the blog in a highly stripped down but yet good looking manner when viewed with a recognized mobile browser. Not only do mobile visitors get their content faster by removing clutter, the usability is also highly increased. Perfect.</p>
<h4>Combining JavaScript and CSS files</h4>
<p>Similar to what I said earlier about many images slowing down a website, the same is true for many JavaScript or CSS files. Regardless of the file type you should keep your number of requests as low as possible. With Wordpress and its many plugins that is next to impossible though, unless you want to rewrite every plugin you install.</p>
<p>But there is hope. What CSS sprites achieve for icons, the <a title="The head Cleaner Wordpress plugin" href="http://wordpress.org/extend/plugins/head-cleaner/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/wordpress.org/extend/plugins/head-cleaner/?referer=');">Head Cleaner</a> plugin does for JavaScript and CSS files. It can combine all JavaScript files into one and do the same for CSS. Further, JavaScript can be minimized and both file types can be compressed, reducing not the number of requests but the bandwidth as well.</p>
<h4>Image size</h4>
<p>This is a classic. Double check the images you have on your website for size - the size measured in bytes, not pixels. If you're not sure how to reduce images byte-wise, there are online services like the one on <a title="Online image optimizer on dynamicdrive.com" href="http://tools.dynamicdrive.com/imageoptimizer/ " target="_blank" onclick="pageTracker._trackPageview('/outgoing/tools.dynamicdrive.com/imageoptimizer/?referer=');">dynamic drive</a> which can guide you (and save you lots of manual trial-and-error time).</p>
<p>General rule of thumb is that a png will be smaller than a gif and images with only a few colors should never be stored in a jpg. For example the ScrumMaster badge you see on the upper right was initially a jpg of 25kB. My all means the png I use now looks identical and is only 13kB.</p>
<h4>Results</h4>
<p>Given all the measures above, I was able to save over 50% of bandwidth and 75% of requests on the frontpage of my blog. No matter how fast your broadband connection is, you feel the difference. Even better, the website is still W3C compliant.</p>
<p>When in doubt what else you can do, I can recommend registering for Google Webmaster Tools and install their Page Speed Firefox plugin. It will hook into the famous Firebug plugin and provide you with an additional tab that gives very useful hints how to improve your website speed.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.st-webdevelopment.com/php/2009/12/optimize-wordpress-blog-performance/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HOWTO: Continuous integration for PHP, pt. 4</title>
		<link>http://www.st-webdevelopment.com/test-automation/2009/11/howto-continuous-integration-php-pt-4/</link>
		<comments>http://www.st-webdevelopment.com/test-automation/2009/11/howto-continuous-integration-php-pt-4/#comments</comments>
		<pubDate>Mon, 30 Nov 2009 02:51:14 +0000</pubDate>
		<dc:creator>Dominique</dc:creator>
				<category><![CDATA[Agile]]></category>
		<category><![CDATA[Test Automation]]></category>
		<category><![CDATA[continuous integration]]></category>
		<category><![CDATA[deployment]]></category>
		<category><![CDATA[phing]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[software build]]></category>
		<category><![CDATA[subversion]]></category>

		<guid isPermaLink="false">http://www.st-webdevelopment.com/?p=136</guid>
		<description><![CDATA[In the fourth article in the series on continuous integration for PHP Dominique Stender showcases how to run Subversion updates automatically from phing and run a set of tests if a new revision was retrieved from Subversion. ]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-137" title="clouds" src="http://www.st-webdevelopment.com/wp-content/uploads/2009/11/clouds.jpg" alt="clouds" width="190" height="400" />This is the fourth article in my series about continuous integration for PHP. You might want to read the <a title="First article in my continuous integration series, covering basic understanding" href="/test-automation/2009/11/howto-setting-continous-integration-php/" target="_self">first</a>, <a title="Second article in my continuous integration series, covering the server installation" href="/test-automation/2009/11/howto-continuous-integration-php-pt-2/" target="_self">second</a> and <a title="Third article in my series on continuous integration for PHP" href="/test-automation/2009/11/howto-continuous-integration-php-pt-3/" target="_self">third article</a> prior to this.</p>
<p>We're getting closer and closer to full test automation and continuous integration. The last article introduced you to how to write <a title="PHPUnit - unittesting for PHP" href="http://www.phpunit.de" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.phpunit.de?referer=');">PHPUnit </a>tests for <a title="Selenium RC - automated frontend testing" href="http://seleniumhq.org/projects/remote-control/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/seleniumhq.org/projects/remote-control/?referer=');">SeleniumRC </a>so that we can test website frontends through PHPUnit. After that we wrote our own phing build script that ran our backend as well as the frontend tests automatically, generated an code coverage report based on Xdebug as well as an comprehensive APIDoc based on PHPDoc comments.</p>
<p>The phing build script we used for this - test.xml - was executed manually by calling</p>
<pre>phing -f test.xml</pre>
<p>on the command line. Everything happened on the development virtual host.</p>
<p>The next logical step is to automate this and perform the additional tasks required to run continuous integration.</p>
<p>The first step is to do a manual svn checkout on the integration virtual host, so we have setup that is identical to the development virtual host.</p>
<p>Now, what the automation will have to do is a Subversion update of the integration virtual host in order to retrieve the latest copy. If the revision changes in that process (that is, if we indeed fetched newer files from Subversion) we again run the tests and generate the reports. If all tests succeed we can safely assume that we have a running system, and we can decide to create a tarball from it or update the staging system for our project manager / client to check it out. On the other hand, if a test fails we'd like to be notified by email.</p>
<p>This is exactly what a second phing build script will do.</p>
<p><span id="more-136"></span></p>
<h4>Introducing more flexibility</h4>
<p>Before we can do all that, we need to make a small but very important change to the Selenium RC test case. The setUp() method of out tests/TestForm.php file configures SeleniumRC so that it points to http://integration.local which is our development environment. This means that no matter where we run the frontend tests, this test would always test our development environment! Clearly not what we want.</p>
<p>If the developer runs the test manually (by executing phing -f test.xml on the commandline), the development environment has to be used. For the automation, the integration host http://integrate.integration.local has to be used.</p>
<p>We accomplish this by changing the setUp() method to this:</p>
<pre class="php">function setUp() {
  // determine hostname based on phing property
  $startDir = Phing::getProperty('application.startdir');
  preg_match('/\/(default|integration|demo)/', $startDir, $vhostMainDir);

  switch($vhostMainDir[1]) {
    case 'default':
      $browserUrl = 'http://integration.local/';
      break;

    case 'integration':
      $browserUrl = 'http://integrate.integration.local/';
      break;

    case 'demo':
      $browserUrl = 'http://demo.integration.local/';
      break;

    default:
  } // end: switch

  $this-&gt;screenshotUrl    = $browserUrl . 'reports/selenium';
  $this-&gt;screenshotPath    = $_ENV['PWD'] . '/../reports/selenium';
  $this-&gt;setBrowser('*firefox');
  $this-&gt;setBrowserUrl($browserUrl);
} // end: function setUp()</pre>
<p>We retrieve the application.startdir property and with this information we can decide in which environment we run to set the browser URL and the screenshot path correctly.</p>
<h4>Committing and retrieve everything to Subversion.</h4>
<p>With that flexibility issue in the test out of the way we can commit the whole development environment /var/www/vhosts/default to Subversion:</p>
<pre>svn import /var/www/vhosts/default https://your.subversion.server/repository/path/trunk
svn checkout --force https://your.subversion.server/repository/path/trunk /var/www/vhosts/default</pre>
<p>Your development environment now is connected to the subversion repository.</p>
<p>Next, you have to do another svn checkout from the same repository URL, this time to the integration environment.</p>
<pre>svn checkout --force https://your.subversion.server/repository/path/trunk /var/www/vhosts/integration</pre>
<p>Now the integration environment is identical to the development environment.</p>
<blockquote><p>Note that the virtual host configuration file for apache will not be overwritten, since the filenames are different. However the integration environment now contains two .conf files for apache. Since only the correct one is linked to /etc/apache2/sites-available, no harm is done though.</p></blockquote>
<h4>The continuous integration build script.</h4>
<p>The single addition between our manual tests from the test.xml phing build file and the continuous integration is another phing build file that you will find at buildScripts/updateAndBuild.xml. If you open it in an editor it will look like this.</p>
<pre class="xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;project basedir="." default="runTests" name="updateWorkingCopy"&gt;
  &lt;property name="demoDir"      value="/var/www/vhosts/demo" /&gt;
  &lt;property name="baseDir"      value="/var/www/vhosts/integration" /&gt;
  &lt;property name="htdocsDir"    value="${baseDir}/htdocs" /&gt;
  &lt;property name="testDir"      value="${baseDir}/tests/" /&gt;
  &lt;property name="reportDir"    value="${htdocsDir}/reports" /&gt;
  &lt;property name="seleniumDir"  value="${reportDir}/selenium" /&gt;
  &lt;property name="masterFile"   value="updateAndBuild" /&gt;
  &lt;property name="buildVersion" value="1.6.1" /&gt;
  &lt;property name="srcDir"       value="/var/www/vhosts/integration/htdocs" /&gt;
  &lt;property name="svnUser"      value="your_svn_user" /&gt;
  &lt;property name="svnPass"      value="your_svn_password" /&gt;

  &lt;!--fetch current revision of working copy --&gt;
  &lt;target name="getOriginalRevision"&gt;
    &lt;svnlastrevision workingcopy="${baseDir}" propertyname="svnOriginalRevision" /&gt;
    &lt;echo msg="Current revision of this working copy: ${svnOriginalRevision}" /&gt;
  &lt;/target&gt;

  &lt;!-- update local working copy --&gt;
  &lt;target name="svnUpdate"&gt;
    &lt;svnupdate username="${svnUser}" password="${svnPass}" nocache="true" todir="${baseDir}" /&gt;
  &lt;/target&gt;

  &lt;!-- fetch revision of working copy again --&gt;
  &lt;target name="getCurrentRevision" depends="svnUpdate"&gt;
    &lt;svnlastrevision workingcopy="${baseDir}" propertyname="svnCurrentRevision" /&gt;
    &lt;echo msg="Revision of this working copy after svn update: ${svnCurrentRevision}" /&gt;
  &lt;/target&gt;

  &lt;!-- create the tarball from the integration VHost--&gt;
  &lt;target name="tar"&gt;
    &lt;echo msg="Creating archive..." /&gt;
    &lt;tar destfile="${baseDir}/builds/build-${buildVersion}.r${svnCurrentRevision}.tar.gz" compression="gzip"&gt;
      &lt;fileset dir="${htdocsDir}"&gt;
        &lt;include name="**" /&gt;
        &lt;exclude name="reports/**" /&gt;
      &lt;/fileset&gt;
    &lt;/tar&gt;
    &lt;echo msg="Build copied and compressed into directory!" /&gt;
  &lt;/target&gt;

  &lt;!-- updates the demo VHost after all tests have succeeded --&gt;
  &lt;target name="updateDemo"&gt;
    &lt;!-- change baseDir to demoDir --&gt;
    &lt;property name="baseDir" value="${demoDir}" override="true" /&gt;
    &lt;phingcall target="svnUpdate" /&gt;
  &lt;/target&gt;

  &lt;!-- compare original and current working copy revisions --&gt;
  &lt;target name="runTests"  depends="getOriginalRevision,getCurrentRevision"&gt;
    &lt;if&gt;
      &lt;equals arg1="${svnOriginalRevision}" arg2="${svnCurrentRevision}" /&gt;
      &lt;then&gt;
        &lt;echo msg="Working copy is up to date." /&gt;
      &lt;/then&gt;
      &lt;else&gt;
        &lt;echo msg="Updated working copy from SVN, starting integration tests." /&gt;
        &lt;phing phingfile="test.xml" haltonfailure="true" /&gt;
        &lt;phingcall target="tar" /&gt;
        &lt;phingcall target="updateDemo" /&gt;
      &lt;/else&gt;
    &lt;/if&gt;
  &lt;/target&gt;
&lt;/project&gt;</pre>
<p>Let's go through this script step by step.</p>
<ol>
<li>The target &lt;getOriginalRevision&gt; gets called first.<br />
Thankfully phing provides a ready-made task to retrieve the Subversion revision of a given path. We store that revision in the property ${svnOriginalRevision}.</li>
<li>Next, the &lt;svnUpdate&gt; target performs a Subversion update on the whole integration environment, ensuring we get any updates that have been committed since the last run. Since this environment will never be edited there will never be any merge conflicts.</li>
<li>Then the&lt; svnCurrentRevision&gt; target fetches the Subversion revision number of the integration environment again and stores it in a property, this time in ${svnCurrentRevision}. Note that this target is identical to &lt;getOriginalRevision&gt;, except for the property used.</li>
<li>After we have ensured that the integration environment is up to date, the main target &lt;runTests&gt; compares the ${svnOriginalRevision} with ${svnCurrentRevision} to check if a newer version has arrived. If not, this continuous integration loop stops. No need to test again what was already tested.</li>
<li>If the execution did not stop - that is, if a newer source code version has arrived - we use the &lt;phing&gt; task to execute the test.xml build file we introduced in the <a title="Third article in my series on continuous integration for PHP" href="/test-automation/2009/11/howto-continuous-integration-php-pt-3/" target="_self">third part of this series</a>.<br />
The buildAndUpdate.xml uses the same properties as the test.xml and because of that the latter will now run in the integration environment.</li>
<li>In case the test.xml script runs through without error a tarball is created automatically, containing everything in the htdocs directory.</li>
<li>Last not least we perform a SVN update on the demo environment.</li>
</ol>
<blockquote><p>Note that the test.xml build file will now send an email if one of the tests fails!</p>
<p>This is due to the fact that the updateAndBuild.xml sets the ${masterFile} property to a value that causes an &lt;if&gt; task in test.xml (line 112) to pass. This way the developers will automatically be alerted if the current revision in the integration environment is broken. If the test.xml is executed manually the if-condition will not apply and no mail is sent.</p></blockquote>
<h4>Testing the phing script.</h4>
<p>You can direct your SSH shell to /var/www/vhosts/integration and execute</p>
<pre>phing -f buildScripts/updateAndBuild.xml</pre>
<p>but this will not do much good since the integration environment is up to date.</p>
<p>What I would recommend is to create a new file in the development environment /var/www/vhosts/default and fill it with some arbitrary text, only to add and commit that file to Subversion. Then return to the integration environment and run the same command.</p>
<p>Voila! The phing script updated the integration environment, recognized the update and started all tests (this time in the integration environment). Once more, a reports folder has been created (again in the integration environment) and filled. A new folder /var/www/vhosts/integration/builds will have been created, containing a .tar.gz file with the latest build.</p>
<blockquote><p>Note that this folder may get huge very fast, depending on project complexity. It is probably advisable to deactivate the automatic tarball generation task for a real life environment.</p></blockquote>
<p>If you add an error to one of the tests, you should get an email. Double check the ${errorMail} property in test.xml and make sure the server can successfully sent mails if you don't.</p>
<p>The last step for you to do is to set up a cronjob to run the phing command periodically. Make sure the cron environment is forwarding the X server display and otherwise is as close as your shell environment as possible, because otherwise you will run into all sorts of issues. This is the nature of cron...</p>
<h4>This concludes my tutorial on continuous integration for PHP.</h4>
<p>Leave me a comment if you liked the series, if you have questions or suggestions for improvements. I will work on a fifth and last article about my own thoughts for possible improvements, to be published in a bit.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.st-webdevelopment.com/test-automation/2009/11/howto-continuous-integration-php-pt-4/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>HOWTO: Continuous Integration for PHP, pt. 1</title>
		<link>http://www.st-webdevelopment.com/test-automation/2009/11/howto-setting-continous-integration-php/</link>
		<comments>http://www.st-webdevelopment.com/test-automation/2009/11/howto-setting-continous-integration-php/#comments</comments>
		<pubDate>Fri, 20 Nov 2009 18:13:31 +0000</pubDate>
		<dc:creator>Dominique</dc:creator>
				<category><![CDATA[Agile]]></category>
		<category><![CDATA[Test Automation]]></category>
		<category><![CDATA[continuous integration]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[phing]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[phpunit]]></category>
		<category><![CDATA[selenium]]></category>

		<guid isPermaLink="false">http://www.st-webdevelopment.de/?p=58</guid>
		<description><![CDATA[The first in a series of articles on how to set up an continuous integration environment for PHP.]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-59" title="bubbles" src="http://www.st-webdevelopment.de/wp-content/uploads/2009/11/bubbles1.jpg" alt="bubbles" width="190" height="400" />After my <a title="My post on setting up a new VHost" href="http://www.st-webdevelopment.de/test-automation/2009/11/new-vm-first-tests-with-phing/" target="_self" onclick="pageTracker._trackPageview('/outgoing/www.st-webdevelopment.de/test-automation/2009/11/new-vm-first-tests-with-phing/?referer=');">initial post</a> which gave only a rough outline on how to install all the various components for a continuous integration environment for PHP I had to struggle quite a bit to get everything to work. There doesn't seem to be a tutorial or howto online that goes to the level of depth required. Hence I decided to make my own.</p>
<p>This will be a series of several posts where I will try to cover all basic aspects of continuous integration for PHP:</p>
<p>An informational article about what continuous integration is all about.</p>
<p>After that I'll give you a <a title="Second article on continuous integration with PHP: Installing a Linux test server" href="/test-automation/2009/11/howto-continuous-integration-php-pt-2/" target="_self">step-by-step guide</a> on how to set up a continuous integration environment using a virtual environment.</p>
<p>I will provide you with an example build script for <a title="Third article in my series on continuous integration for PHP" href="/test-automation/2009/11/howto-continuous-integration-php-pt-3/" target="_self">automated local tests</a> in the third article.</p>
<p>The fourth article will put all things together and <a title="My fourth article in the series on continuous integration for PHP" href="/test-automation/2009/11/howto-continuous-integration-php-pt-4/" target="_self">establish continuous integration</a>.</p>
<h4>This article will cover the first topic "What is continuous integration all about?".</h4>
<p>Continuous integration is an important aspect in agile development methodologies and test driven development.</p>
<p>The whole idea behind continuous integration is to have a process running in the background that integrates and tests the various pieces of source code that you generated continuously and automatically. In a nutshell, that's it.</p>
<p>Why would we want to automate our testing? Well I believe that is obvious:</p>
<ol>
<li>Testing is hard.</li>
<li>Testing is boring.</li>
<li>Testing is time consuming.</li>
</ol>
<p><span id="more-58"></span>All three aspects - and there might be more - make it impractical to achieve complete test coverage manually even in a medium sized project. It becomes much more feasible to invest the effort of setting up an automated test environment and writing the tests once which from then on will run day after day after day.</p>
<h4>Which components are required for continuous integration with PHP?</h4>
<p>There are a few alternatives to what I'm going to discuss here (I give some of them in parenthesis) but roughly you'll want:</p>
<ul>
<li>Unittest scripts that will cover your regression tests. <a title="PHPUnit Website" href="http://www.phpunit.de" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.phpunit.de?referer=');">PHPUnit</a> is the tool of choice here (<a title="SimpleTest Homepage" href="http://www.simpletest.org/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.simpletest.org/?referer=');">SimpleTest</a> also does a good job)</li>
<li>A build tool such as <a title="phing website - A build tool for PHP" href="http://phing.info/trac/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/phing.info/trac/?referer=');">phing</a>. It will automate the building of your test environment.</li>
<li>For the continuity aspect a cronjob is enough. (<a title="CruiseControl home" href="http://cruisecontrol.sourceforge.net/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/cruisecontrol.sourceforge.net/?referer=');">CruiseControl</a> &amp; <a href="http://phpundercontrol.org/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/phpundercontrol.org/?referer=');">phpUnderControl </a>are much more sophisticated. Check them out if a cronjob is not cutting it for you)</li>
<li>You will need some sort of revision control. My tool of choice is <a title="Subversion homepage" href="http://subversion.tigris.org/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/subversion.tigris.org/?referer=');">Subversion</a>. (<a title="CVS homepage" href="http://www.nongnu.org/cvs/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.nongnu.org/cvs/?referer=');">CVS</a>, and <a title="the Wikipedia on Revision Control" href="http://en.wikipedia.org/wiki/Revision_control" target="_blank" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Revision_control?referer=');">many others</a> are available)</li>
<li>I strongly recommend using your own integration environment over testing on your development machine. <a title="VMWare homepage" href="http://www.vmware.com/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.vmware.com/?referer=');">VMWare </a>is a great free virtualizer.</li>
</ul>
<h4>Is there more that we can do with continuous integration?</h4>
<p>Hell yes! Here are a few examples:</p>
<ul>
<li>Frontend testing (yes, automated) with <a title="Selenium IDE homepage - automated frontend testing for websites" href="http://seleniumhq.org/projects/ide/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/seleniumhq.org/projects/ide/?referer=');">Selenium IDE</a> and <a title="Selenium RC homepage" href="http://seleniumhq.org/projects/remote-control/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/seleniumhq.org/projects/remote-control/?referer=');">Selenium Remote Control</a>. Note that you will also need some sort of graphical environment for that. <a title="Wikipedia on Xvfb, a headless graphical environment." href="http://en.wikipedia.org/wiki/Xvfb" target="_blank" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Xvfb?referer=');">Xvfb </a>is usually good enough.</li>
<li>You could generate your API doc for PHP with <a title="phpDocumentor" href="http://www.phpdoc.org/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.phpdoc.org/?referer=');">phpDocumentor</a>.</li>
<li>You certainly can generate an API doc for <a title="JsDoc Toolkit - API doc for JavaScript" href="http://code.google.com/p/jsdoc-toolkit/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/code.google.com/p/jsdoc-toolkit/?referer=');">JavaScript </a>as well.</li>
<li>You could perform unittests for <a title="JavaScript unittest frameworks" href="http://www.google.com/search?q=javascript+unittest" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.google.com/search?q=javascript+unittest&amp;referer=');">JavaScript </a>or your <a title="QUnit - Unittesting for jQuery" href="http://docs.jquery.com/QUnit" target="_blank" onclick="pageTracker._trackPageview('/outgoing/docs.jquery.com/QUnit?referer=');">jQuery plugins</a>.</li>
<li>and last not least why don't you push everything on a staging system for your client to see when everything goes well?</li>
</ul>
<p>Now that we have that covered...</p>
<h4>How does an environment with continuous integration look like?<br />
How do we have to work in order to get the most out of it?</h4>
<p>As usual, there are many ways to do this. My personal approach consists of two, better three environments:</p>
<p>First, the development machine(s). That is where we develop our code.<br />
Second, the integration machine, where the continuous integration is happening.<br />
Third, optionally a system for staging. This gives you constant feedback from the client.</p>
<p>Overall the workflow looks like this:</p>
<div id="attachment_62" class="wp-caption aligncenter" style="width: 447px"><img class="size-full wp-image-62" title="environment" src="http://www.st-webdevelopment.de/wp-content/uploads/2009/11/environment.png" alt="My continuous integration environment" width="437" height="273" /><p class="wp-caption-text">My continuous integration environment</p></div>
<p>The 'devel' environment is local on the developers' machine. A virtual machine as I pointed out earlier but that is not relevant at this moment. If there is more than one developer, each will have his own 'devel' environment. The development (1) is done locally. All developers commit to and update  from a central Subversion repository (2).</p>
<p>The 'int' (integration) environment usually sits on a different piece of hardware. I prefer the 'int' and the 'stage' system to be on two different virtual hosts on one machine. However your setup might be, on the 'int' environment a cronjob is running continuously and pulls the latest revision of the product out of Subversion (3). If a new revision is found, the integration (4) starts, running all tests, generating all reports, writing API docs and so on.</p>
<p>If an error occurs during the integration test, a mail is being sent to all developers. I've heard of teams who change the color of an ambient orb to red in this case, or switch on a lava lamp. Do as you please. A mail is a good start, however. The team can then utilize all reports on 'int' (available thru the apache virtual host) to inspect the problem and fix it.</p>
<p>Because the integration is continuous, the feedback about a failing test is fast.<strong> </strong></p>
<p>Not much code has to be revised in order to find and fix the bug.</p>
<p>Only when the integration runs without errors, the step (5) starts: Deploying that revision to the 'stage' environment where the client can test it. If you think that might probably not be a good idea in your case / with your client, you might be right. Releasing every other week, at the end of a sprint works just as well. This last step (5) is optional.</p>
<p>That concludes the first part in my series on setting up continuous integration for PHP. Continue with the second part: <a title="Second article on continuous integration with PHP: Installing a Linux test server" href="/test-automation/2009/11/howto-continuous-integration-php-pt-2/" target="_self">A installation howto</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.st-webdevelopment.com/test-automation/2009/11/howto-setting-continous-integration-php/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
