<?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>Redpill Linpro PHP Competence Group</title>
	<atom:link href="http://elephpants.blog.redpill-linpro.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://elephpants.blog.redpill-linpro.com</link>
	<description>Monkeys and elephpants take on the world</description>
	<lastBuildDate>Sun, 18 Dec 2011 12:01:03 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1</generator>
		<item>
		<title>Fake php time on your ubuntu server</title>
		<link>http://elephpants.blog.redpill-linpro.com/2011/12/18/fake-php-time-on-your-ubuntu-server/</link>
		<comments>http://elephpants.blog.redpill-linpro.com/2011/12/18/fake-php-time-on-your-ubuntu-server/#comments</comments>
		<pubDate>Sun, 18 Dec 2011 11:47:48 +0000</pubDate>
		<dc:creator>strind</dc:creator>
				<category><![CDATA[Howto]]></category>

		<guid isPermaLink="false">http://elephpants.blog.redpill-linpro.com/2011/12/18/</guid>
		<description><![CDATA[Some time it is necessary to fool your PHP application to test functionality related to a &#8220;current date&#8221;. Fooling php cli is simple using faketime: Say you have this PHP script: #!/usr/bin/env php &#60;?php print date( 'F j. Y [H:i]' ).&#34;\n&#34;; Rendering this script with php through faketime will give you results like this: $ <a href='http://elephpants.blog.redpill-linpro.com/2011/12/18/fake-php-time-on-your-ubuntu-server/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p>Some time it is necessary to fool your PHP application to test functionality related to a &#8220;current date&#8221;.</p>
<p>Fooling php cli is simple using <a href="http://packages.ubuntu.com/search?keywords=faketime">faketime</a>:</p>
<p>Say you have this PHP script:</p>
<pre class="brush: php; title: ;">
#!/usr/bin/env php
&lt;?php
print date( 'F j. Y [H:i]' ).&quot;\n&quot;;
</pre>
<p>Rendering this script with php through faketime will give you results like this:</p>
<pre class="brush: bash; title: ;">
$ faketime 'last Friday 5 pm' ./time.php
December 9. 2011 [17:00]
</pre>
<p>The same can be achieved using the <a href="http://packages.ubuntu.com/lucid/datefudge">datefudge</a> command:</p>
<pre class="brush: bash; title: ;">
$ datefudge &quot;2007-04-01 10:23&quot; ./time.php
April 1. 2007 [10:23]
</pre>
<p><strong>Faking time for a webapplication</strong></p>
<p>Faking time for a web application is not that simple since apache will fork a process for each request and thus create a new php processes.<br />
In this post I will show you how to use <a href="http://freecode.com/projects/libfaketime">FakeTime Preload Library</a> to fake time system wide while running tests on a web application.</p>
<p>First I need to install faketimelib as described on the librarys <a href="http://www.code-wizards.com/projects/libfaketime/">homepage</a>.<br />
In short:</p>
<pre class="brush: bash; title: ;">
wget http://www.code-wizards.com/projects/libfaketime/libfaketime-0.8.1.tar.gz
tar -xvzf libfaketime-0.8.1.tar.gz
cd libfaketime-0.8.1
vim README
make
sudo make install
export LD_PRELOAD=/usr/local/lib/faketime/libfaketime.so.1
</pre>
<p>For the demonstration I will use a php script like this:</p>
<pre class="brush: php; title: ;">
&lt;?php
printf( &quot;The current time of the server is: %s\n&quot;, date('l F j. Y [H:i:s]') );
</pre>
<p>Running this script should yield something like:</p>
<pre class="brush: bash; title: ;">
$ php time.php
The current time of the server is: Friday December 16. 2011 [08:02:43]
</pre>
<p>Now I create a file in my home folder, faketimerc, with a new future time. I will use this file in different ways to show how I can manipulate the time.</p>
<pre class="brush: bash; title: ;">
echo &quot;@2012-12-21 12:12:12&quot; &gt; faketimerc
</pre>
<p>If you now create an environment variable, FAKETIME, give it a future time, and running the same script would yield something like this:</p>
<pre class="brush: bash; title: ;">
$ php time.php
The current time of the server is: Friday December 16. 2011 [08:19:39]
$ export FAKETIME=$(cat faketimerc)
$ php time.php
The current time of the server is: Friday December 21. 2012 [12:12:12]
$ unset FAKETIME
$ php time.php
The current time of the server is: Friday December 16. 2011 [08:19:56]
</pre>
<p>As you can see, the processes you run while the environment variable is set to a future time will get a fake time. Once the variable is unset new processes will get normal time.</p>
<p>This can be achieved also by creating a file. &#8220;.faketimerc&#8221; in your home folder:</p>
<pre class="brush: bash; title: ;">
$ php time.php
The current time of the server is: Friday December 16. 2011 [08:23:12]
$ cp faketimerc .faketimerc
$ php time.php
The current time of the server is: Friday December 21. 2012 [12:12:12]
$ rm -f .faketimerc
$ php time.php
The current time of the server is: Friday December 16. 2011 [08:23:36]
</pre>
<p>If you want to change time for a php application that runs though apache you may want to set the fake time system wide so that the php processes spowned use the faked time. To do this you need to create a file, /etc/.faketimerc, just the same as the one I created in my home folder.</p>
<p>I will use w3m for this demonstration. I assume a normal ubuntu server with apache2 installed.</p>
<pre class="brush: bash; title: ;">
sudo cp time.php /var/www
sudo cp faketimerc /etc/
$ sudo /etc/init.d/apache2 restart
 * Restarting web server apache2                                                                                                                                                                                                                                                   ... waiting
$ php /var/www/time.php
The current time of the server is: Friday December 21. 2012 [12:12:12]
$ date
fr. 21. des. 12:12:12 +0100 2012
$ w3m -dump localhost/time.php
The current time of the server is: Friday December 16. 2011 [11:16:24]
</pre>
<p>As you can see, the date command and when rendering the script with php, gives me the fake time, but when rendering the script through apache I loose the fake time. This is because the environment variable LD_PRELOAD is not set for the apache process.</p>
<p>To fix this I need to set LD_PRELOAD for apache by editing /etc/apache/envvars. Lets test it again:</p>
<pre class="brush: bash; title: ;">
$ sudo bash -c &quot;echo \&quot;export LD_PRELOAD='/usr/local/lib/faketime/libfaketime.so.1'\&quot; &gt;&gt; /etc/apache2/envvars&quot;
$ sudo /etc/init.d/apache2 restart
 * Restarting web server apache2                                                                                                                                                                                                                                                   ... waiting
$ w3m -dump localhost/time.php
The current time of the server is: Friday December 21. 2012 [12:12:16]
</pre>
<p>Fake time! <img src='http://elephpants.blog.redpill-linpro.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>PS! If you also want your PostgreSQL server to use fake time:</p>
<pre class="brush: bash; title: ;">
$ sudo bash -c &quot;echo \&quot;LD_PRELOAD='/usr/local/lib/faketime/libfaketime.so.1'\&quot; &gt;&gt; /etc/postgresql/8.4/main/environment&quot;
$ sudo /etc/init.d/postgresql-8.4 restart
</pre>
]]></content:encoded>
			<wfw:commentRss>http://elephpants.blog.redpill-linpro.com/2011/12/18/fake-php-time-on-your-ubuntu-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Practising the fundamentals: Function of the week/month</title>
		<link>http://elephpants.blog.redpill-linpro.com/2011/11/01/tip/</link>
		<comments>http://elephpants.blog.redpill-linpro.com/2011/11/01/tip/#comments</comments>
		<pubDate>Tue, 01 Nov 2011 19:35:06 +0000</pubDate>
		<dc:creator>bjori</dc:creator>
				<category><![CDATA[Fundamentals]]></category>
		<category><![CDATA[PHP Functions]]></category>
		<category><![CDATA[series]]></category>

		<guid isPermaLink="false">http://elephpants.blog.redpill-linpro.com/2011/11/01/</guid>
		<description><![CDATA[When you need to see if any of the chars in $chars is in another string.. Whats the simplest way to search for them? Hopefully none of the libraries have such functionality, so you need to go &#8220;a bit lower&#8221;. The answer is, ofcourse, trivial: $chars = &#34;xy&#34;; $string = &#34;the quick brown fox jumps <a href='http://elephpants.blog.redpill-linpro.com/2011/11/01/tip/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p>When you need to see if any of the chars in $chars is in another string.. Whats the simplest way to search for them?<br />
Hopefully none of the libraries have such functionality, so you need to go &#8220;a bit lower&#8221;.<br />
The answer is, ofcourse, trivial:</p>
<pre class="brush: php; title: ;">
$chars = &quot;xy&quot;;
$string = &quot;the quick brown fox jumps over the lazy dog&quot;;

$found = false;
for($l = 0; $l &lt; strlen($chars); $l++) {
        if (strpos($string, $chars[$l]) !== false) {
                $found = true;
                break;
        }
}
if ($found) {
        /* Do stuff */
}
</pre>
<p>But hang on. This feels a bit weird. Surely PHP must have a better way of doing this?<br />
Browsing through the<a href="http://php.net/strings"> string section in the PHP manual</a> you&#8217;ll notice PHP has bucketloads of native string functions. If you have a background from other languages, you could even just try and see if PHP has a function of the same name (which quite often it does) that solves the problem.</p>
<p>And sure enough, it does: <a title="String Pointer Break / Search a string for any of a set of characters" href="http://php.net/strpbrk">strpbrk</a>!</p>
<pre class="brush: php; title: ;">
$chars = &quot;xy&quot;;
$string = &quot;the quick brown fox jumps over the lazy dog&quot;;
if (strpbrk($string, $chars)) {
        /* do stuff */
}
</pre>
<p>Just give the &#8220;problem&#8221; a second thought before going crazy with your coding, and keep in mind you aren&#8217;t just working with Symfony, Drupal, SugarCRM, WordPress, &#8230; Your good old pal, PHP, is there too.</p>
]]></content:encoded>
			<wfw:commentRss>http://elephpants.blog.redpill-linpro.com/2011/11/01/tip/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Responsive Web Design</title>
		<link>http://elephpants.blog.redpill-linpro.com/2011/10/22/responsive_web_design/</link>
		<comments>http://elephpants.blog.redpill-linpro.com/2011/10/22/responsive_web_design/#comments</comments>
		<pubDate>Sat, 22 Oct 2011 18:47:22 +0000</pubDate>
		<dc:creator>wojak</dc:creator>
				<category><![CDATA[Howto]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[introduction]]></category>
		<category><![CDATA[responsive web]]></category>
		<category><![CDATA[ui]]></category>

		<guid isPermaLink="false">http://elephpants.blog.redpill-linpro.com/2011/10/22/</guid>
		<description><![CDATA[Which resolution web application should be optimized to, is a question with different answer mainly depended on time when asked. The average screen size and resolution have been growing as a result of technology evolution and falling prices of electronic equipment. Resolution usage, Source: http://www.w3counter.com/ At the same time mobile devices, like pads and cell <a href='http://elephpants.blog.redpill-linpro.com/2011/10/22/responsive_web_design/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p>Which resolution web application should be optimized to, is a question with different answer mainly depended on time when asked. The average screen size and resolution have been growing as a result of technology evolution and falling prices of electronic equipment.<br />
<img src="http://wojak.u.bitbit.net/rwd_data/resolution_diagram.png" alt="Resolution usage, Source: http://www.w3counter.com/" /><br />
<em>Resolution usage, Source: http://www.w3counter.com/</em></p>
<p>At the same time mobile devices, like pads and cell phones, with small screens and low resolution, became capable to browse Internet in a more effective way.<br />
<img src="http://wojak.u.bitbit.net/rwd_data/mobile_browsing.png" alt="Mobile browsing, Source: http://gs.statcounter.com" /><br />
<em>Mobile browsing, Source: http://gs.statcounter.com</em></p>
<p>So, what to do if I have in my requirements support for IPhone 3GS 3,5” 320&#215;480 and PC screen with high resolution 1920&#215;1080. Somehow I must optimize my application to these two resolutions.</p>
<p>One of the common solutions is to split the application on view level by implementing two versions of templates. One optimized for high and the other for low resolution devices. It is going to work, but is that really a good solution from design point of view. The main disadvantage is that the application is still not supporting all possible resolutions, is just optimized to high and low one. And of course another issue is maintainability and future compatibility.</p>
<p>What if instead of optimizing application to a specific resolution, I could support all of them. It is actually not a new idea. It has been ages since I could use size=”100%” attribute in some html tags. By doing this html element is always scaled to the maximum available size. It gives some flexibility. However scaling has limitations, sooner or later I will reach a stress point where scaling is not effective anymore and I would need to change layout by relocation some elements of interface.</p>
<p>So, to optimize web application to any resolution I would need to:</p>
<ul>
<li>scale html objects</li>
<li>dynamically change layout</li>
<li>scale images</li>
</ul>
<p>Generally speaking, I need an ability to alter my application, in order to continually reflect the environmental conditions.</p>
<p>This is what<strong> “Responsive Web Design” </strong>stands for.</p>
<p>In practice responsive web design is an intelligent use of flexible grids, layouts, images and CSS media queries.</p>
<h1>Media Queries</h1>
<p>With media queries I&#8217;m able to resolve the first two first problems, I can scale html elements and change layout.</p>
<p>Since CSS 2.1 there is a possibility to define custom style sheets for different media types.<br />
<code><br />
@media print {<br />
/* style sheet for print goes here */<br />
}</code></p>
<p><code> </code></p>
<p><code>@media screen {<br />
/* style sheet for screen goes here */<br />
}<br />
</code></p>
<p>CSS 3 offers an extension called media query, which allows to specify conditions when the specified style sheet will affect user interface.<br />
<code><br />
@media screen and (max-width: 640px) {<br />
/* Window size &lt; 640px */<br />
}</code></p>
<p><code>@media screen and (max-width: 800px) and (min-width: 640px) {<br />
/* Window size between 640px and 800px */<br />
}</p>
<p></code></p>
<p><code>@media screen and (max-width: 1024px) and (min-width: 800px),  (max-width: 640px){<br />
/* Window size between 1024px and 800px or less than 640px */<br />
}<br />
</code></p>
<p>Here is an example of valid media query definitions:<br />
<code><br />
&lt;link rel="stylesheet" type="text/css" media="screen and (max-width: 640px)"  href="shetland.css" /&gt;</code></p>
<p><code>@media screen and (max-width: 640px) {<br />
/* Window size &lt; 640px */<br />
}</p>
<p></code></p>
<p><code>@import url("style.css") screen and (max-width: 640px);<br />
</code></p>
<p>If a web browser does not support media queries css is loaded always without any conditions, this is unwanted behavior. If you want to prevent loading css with media queries on not supported web browsers you can add word “only” before media type:<br />
<code><br />
/* add word «only» to be ignored on web browsers with out support */<br />
@media only screen and (max-width: 640px) {<br />
/* Window size &lt; 640px */<br />
}<br />
</code></p>
<p>There is quite many criterias available in CSS3, however the two first on the below list are the most usable.</p>
<ul>
<li>max-width / min-width</li>
<li>max-device-width / min-device-width</li>
<li>orientation (portrait/landscape)</li>
<li>device-aspect-ratio</li>
<li>min-resolution / max-resolution</li>
<li>monochrome</li>
<li>Min-color-index</li>
</ul>
<p>See <a href="http://www.w3.org/TR/css3-mediaqueries">http://www.w3.org/TR/css3-mediaqueries</a> for more</p>
<p>CSS Media queries are supported by the following web browsers:</p>
<ul>
<li>Firefox 3.5+</li>
<li>Chrome</li>
<li>Safari</li>
<li>Opera 9.5+</li>
<li>Opera Mini</li>
<li>Android Browser</li>
<li>Opera Mobile</li>
<li>IE9+</li>
</ul>
<p>CSS media queries are quite useful if the goal is to affecting mobile devices, it is supported by most of the web browsers used on mobile devices.<br />
But if the goal is to support older web browsers Java Script comes with help.</p>
<p>Here is an example of loadCss() and removeCss() methods that can be used to dynamically load and remove css files.</p>
<p><code><br />
/**<br />
* Load CSS file<br />
*/<br />
function loadCss(filename){<br />
var links = document.getElementsByTagName("link");<br />
for (var i=0; i &lt; links.length; i++) {<br />
if(links[i].getAttribute("href") == filename) return;<br />
}<br />
var fr=document.createElement("link")<br />
fr.setAttribute("rel", "stylesheet")<br />
fr.setAttribute("type", "text/css")<br />
fr.setAttribute("id", filename)<br />
fr.setAttribute("href", filename)<br />
document.getElementsByTagName("head")[0].appendChild(fr)<br />
}</code></p>
<p><code>/**<br />
* Remove CSS file<br />
*/<br />
function removeCss(filename) {<br />
var links = document.getElementsByTagName("link");<br />
var parent = document.getElementsByTagName("head")[0];<br />
for (var i=0; i &lt; links.length; i++) {<br />
if(links[i].getAttribute("href") == filename) {<br />
parent.removeChild(links[i]);<br />
}<br />
}<br />
}</p>
<p></code></p>
<p>&nbsp;</p>
<p>Adding below code to onResize event will be equal to:  @import url(&#8220;mini.css&#8221;) screen and (max-width: 400px);<br />
<code><br />
/* Activate mini.css file if window size is less than 400px */<br />
if(windowWidth&lt;400) {<br />
loadCss('mini.css');<br />
} else {<br />
removeCss('mini.css');<br />
}<br />
</code></p>
<p>The above example should in theory by compatible with old web browsers (including IE6) .</p>
<h1>Images</h1>
<p>The last of my needs is to scale images, here are few ways how I can do it.</p>
<h2>Fluid images</h2>
<p>When user opens my application on a mobile device with small screen and low resolution or changes web browser window size, it might happen that my images will reach a stress point where they will consume more space that the window is able to offer. To avoid this problem I need to scale them proportionally.</p>
<p>Fortunately there is a CSS property called max-width, if I set to  100% in theory I get all I need. My images will by default be displayed in their original size and will be proportionally scaled when needed.</p>
<p>But in practice this solution is affected by few problems, the main is that I will need to load oversized images in low resolution which can be a problem for small mobile devices. The other problem is a poor quality of scaled images on IE.</p>
<h2>Hiding images</h2>
<p>Another possibility is to have alternative versions of an image, depending on the environment images can be visible or hidden, just like on the example below:</p>
<p><code>.small-image {<br />
display:none;<br />
}</p>
<p>@media only screen and (max-width: 600px) {<br />
.default-image { display:none; }<br />
.small-image { display:inline; }<br />
}</p>
<p>&lt;img class="default-image" src="img1.jpg"&gt;<br />
&lt;img class="small-image" src="img2.jpg"&gt;</p>
<p></code></p>
<p>&nbsp;</p>
<p>It works quite well, if windows size is below 600px (this is the stress point) small-image gets attribute display:inline; and default-image gets display:none;<br />
Nice solution, compatible with all common web browsers, however  IE always loads both images even if one of them will never be showed and it is not quite clean code.</p>
<h2>&#8220;Content&#8221; attribute</h2>
<p>It is possible to show images with combination of content property and url value, see example below:<br />
<code>@media screen and (max-width: 600px) {<br />
.image1:before {<br />
content:url(img2.jpg);<br />
}<br />
}<br />
@media screen and (min-width: 600px){<br />
.image1:before {<br />
content:url(img1.jpg);<br />
}<br />
}<br />
&lt;span class="image1" /&gt;</code></p>
<p><code> </code><br />
But still, this code isn&#8217;t clean and is not compatible with some common web browsers.</p>
<h2>Java Script way</h2>
<p>JS come here with help as well.</p>
<p>One of the possibilities is to set a cookie with screen size information.<br />
<code>document.cookie = "screenWidth=" + screen.width;</code><br />
and then serve all images through media content, which will send the right image version depending on screenWidth value:<br />
<code>&lt;img src="media/?test.jpg"&gt;</code></p>
<h2>CSS 3 way</h2>
<p>In the future I&#8217;m expecting below code to be supported in all CSS3 compatible web browsers,  for now only Opera supports this syntax partially.<br />
<code><br />
&lt;img src="test.jpg"<br />
img-400px="test-400px.jpg"<br />
&gt;<br />
@media (min-device-width:400px) {<br />
img[img-400px] {<br />
content: url(attr(img-400px));<br />
}<br />
}</code></p>
]]></content:encoded>
			<wfw:commentRss>http://elephpants.blog.redpill-linpro.com/2011/10/22/responsive_web_design/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Practising the fundamentals: Staying in touch</title>
		<link>http://elephpants.blog.redpill-linpro.com/2011/10/20/stay-in-touch/</link>
		<comments>http://elephpants.blog.redpill-linpro.com/2011/10/20/stay-in-touch/#comments</comments>
		<pubDate>Thu, 20 Oct 2011 15:37:46 +0000</pubDate>
		<dc:creator>bjori</dc:creator>
				<category><![CDATA[Coding practices]]></category>
		<category><![CDATA[Fundamentals]]></category>
		<category><![CDATA[Get involved]]></category>

		<guid isPermaLink="false">http://elephpants.blog.redpill-linpro.com/2011/10/20/</guid>
		<description><![CDATA[With the recent massive flood of frameworks, libraries and toolkits on the market these days it is easy to forget that underneath it all is the good old, plain and simple, PHP with all its kinks, quirks, and huuge set of builtin functionality. PHP has vast amount of extensions which solve all sort of problems. <a href='http://elephpants.blog.redpill-linpro.com/2011/10/20/stay-in-touch/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p>With the recent massive flood of frameworks, libraries and toolkits on the market these days it is easy to forget that underneath it all is the good old, plain and simple, PHP with all its kinks, quirks, and huuge set of builtin functionality.</p>
<p>PHP has vast amount of <a title="Extension reference" href="http://php.net/funcref" target="_blank">extensions</a> which solve all sort of problems. And if PHP doesn&#8217;t have it built-in, we have an impressive amount of additional extensions both on <a title="PECL Extensions" href="http://pecl.php.net/packages.php" target="_blank">pecl</a> and now recently more and more on github.<br />
There is a high chance that someone else has been in your shoes already and solved the problem, so it is worth looking around over the horizon and see if the problem has been solved already.</p>
<p>For some reason the current practice seems to be the &#8220;<a title="Ruby On Rails" href="http://rubyonrails.org/" target="_blank">RoR</a>&#8221; idiocy where &#8220;RoR developers&#8221; barely even know that there is this Ruby some miles down the stack. PHP has hit this &#8220;stepping stone&#8221; already with WordPress, Drupal and even Symfony and that is a weird and scary thought. Remembering &#8220;where you came from&#8221; is an important fact to remember, even for those who specialize in specific products. Looking at how other projects work, comparing notes, work ethics, features and functionality is also very important. Getting different perspective and knowledge is how we can improve our solutions and work more efficiently. If your specific product doesn&#8217;t have native support for something, why not look at a different framework/library/cms/toolkit/.. even PHP extensions?</p>
<p>As June mentioned earlier, going &#8216;back home&#8217; and checkout the <a href="http://php.net/manual" target="_blank">PHP manual</a> pages is generally a good idea. Things change, manual pages are updated, improved, added, and you have different perspective, other problems to solve and so on. Even though you believe you know all the basics, you still need to practice them, and that includes browsing the manual from time to time, again and again &#8211; no matter which project it is.</p>
<p>So what is the best way to stay in touch? Kept up2date with new ways and offerings? New solutions to the same problem? <a href="http://php.net/get-involved" target="_blank">Get involved</a>!</p>
<p>By far the best way is to get involved with the project you are using. Even just silently idling on the <a href="http://php.net/mailing-lists" target="_blank">mailinglists</a> and read the subjects. Subscribing to the commit lists is a fantastic way to see precisly what is going on and see which direction the project is taking. Who knows, after a while you may spot something the others didn&#8217;t. Get an idea for a killer feature. Shed a light on different perspective the others didn&#8217;t think of. After a while hanging on the lists you&#8217;ll get a feeling for how the project works, and hopefully start chiming in. Give your 2cents, and who knows &#8211; even cook up a patch or two.</p>
]]></content:encoded>
			<wfw:commentRss>http://elephpants.blog.redpill-linpro.com/2011/10/20/stay-in-touch/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Optimising a PHP (symfony 1.x/Doctrine 1.x) application</title>
		<link>http://elephpants.blog.redpill-linpro.com/2011/10/07/optimising_a_php_symfony_doctrine_application-2/</link>
		<comments>http://elephpants.blog.redpill-linpro.com/2011/10/07/optimising_a_php_symfony_doctrine_application-2/#comments</comments>
		<pubDate>Fri, 07 Oct 2011 13:35:12 +0000</pubDate>
		<dc:creator>Russ</dc:creator>
				<category><![CDATA[Coding practices]]></category>
		<category><![CDATA[Perfomance]]></category>
		<category><![CDATA[legacy code]]></category>
		<category><![CDATA[oldcode]]></category>
		<category><![CDATA[optimising]]></category>

		<guid isPermaLink="false">http://elephpants.blog.redpill-linpro.com/2011/10/07/</guid>
		<description><![CDATA[Introduction Whilst everyone is buzzing and creating fancy new Symfony2/Doctrine 2 applications, and perhaps even a shift to new frameworks/no frameworks, a great deal of us are still maintaining legacy apps and will be for some time to come. As these apps grow, we occasionally need to look back and scream at our old code <a href='http://elephpants.blog.redpill-linpro.com/2011/10/07/optimising_a_php_symfony_doctrine_application-2/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<h2>Introduction</h2>
<p>Whilst everyone is buzzing and creating fancy new Symfony2/Doctrine 2 applications, and perhaps even a shift to new frameworks/no frameworks, a great deal of us are still maintaining legacy apps and will be for some time to come. As these apps grow, we occasionally need to look back and scream at our old code and wonder why we didn&#8217;t make it more scalable or use neat optimisation tricks back when it was first conceived. The fact is, many of these &#8220;tricks&#8221; are not necessary at the time for a virgin app, and we need to develop code that is relevant to the task at hand.</p>
<p>That said, being aware of some of the case studies I will present to you now may help you to optimise old code, but may also allow you to think twice when you are working with new code &#8211; as the things I will describe do not take too much time to implement first time round.</p>
<h2>Case study: Working with large resultsets and array_merge</h2>
<p>In my sample application, the database contained many different types of organisation stored in different tables, and due to the structure of the data and the criteria for each organisation, there was no easy way to retrieve several organisations at once using pure SQL and joins (well, no convenient way). The solution is relatively simple, one query per organisation then combine the results, in this case as we go along:</p>
<pre class="brush: php; title: ;">
$membershipClasses = array(&quot;Entity1&quot;, &quot;Entity2&quot;, &quot;Entity3&quot;, &quot;Entity4&quot;, &quot;Entity5&quot;);
    $results = array();
    foreach ($membershipClasses as $joinedTable)
    {
      $query = $this-&gt;createQuery()-&gt;from(&quot;TablePrefix&quot;.$joinedTable.&quot; t&quot;);
      // Lots of differing criteria based on which class we were dealing with
      ...

      $results = array_merge($query-&gt;execute(array(), $hydration), $results);
    }
</pre>
<p>This logic was used to generate a report with approximately 50,000 rows, used 1.2GB of internal memory and took around 20 minutes to complete &#8211; often failing or bringing the system to a halt.</p>
<p>One optimisation used in this case (many more are surely possible but lets focus on one) involves the last line &#8211; using PHP&#8217;s array_merge function. Simply switching this out to use a simple array traversal brought the execution time down to under 2 minutes, however there was no change in memory usage.</p>
<pre class="brush: php; title: ;">

$theseResults = $query-&gt;execute(array(), $hydration);
foreach ($theseResults as $aResult)
{
  $results[] = $aResult;
}
</pre>
<p>Why is this so much faster? And why can&#8217;t we use += instead?</p>
<p>&nbsp;</p>
<p>The &#8220;problem&#8221; with array_merge, is that even though it discards numeric keys, it still has to *check* them all first, which is a lot of overhead on 50,000 rows. We can&#8217;t use += in this case either, because that would respect the numeric keys which would start from 0 each time, and therefore the results would not &#8220;stack&#8221; as intended, unless we tell Doctrine to index the results with some unique key.</p>
<p>Why it takes *so* much longer is a bit of a mystery to me. I&#8217;ve looked at the c code behind it (ext/standard/array.c) and it&#8217;s, well quite frankly voodoo.</p>
<h2>Case study: Limiting results</h2>
<p>Something that was &#8220;fixed&#8221; (read: removed) in Doctrine 2 was the ability to limit results returned from queries, at least the &#8220;magic&#8221; part of it. The problem with limiting hydrated results is that you need to know exactly how many rows each sub-tree will contain before you can limit the query as a whole. Imagine a person with many addresses, and you want an array limited to 5 people &#8211; you can&#8217;t list add &#8220;LIMIT 5&#8243; to the end of the query, because when this is hydrated you will most likely end up with one or 2 people, the second of whom may not have all their addresses, because you&#8217;ve told your database manager to return 5 *rows*, it has no idea how these rows relate to your model.</p>
<p>In Doctrine 1, adding a limit clause would cause all sorts of magic to happen, the resulting query ending up as a collection of complex subqueries each with their own limit clause, the more joins you introduced, and the more levels of join, the more complicated it becomes. First level joining is not so bad, but joining several levels deep soon starts to get heavy, and your execution speed will suffer for it. Couple this with a large resultset and you will see the smoke drifting from the server room in no time.</p>
<p>So, what&#8217;s the solution? Well, this one is not so clear cut &#8211; you have to experiment. Sometimes, doing it the &#8220;magic&#8221; way will work just fine, and is totally acceptable, but when the query becomes &#8220;heavy&#8221; you have a few options:</p>
<h3>Work out your subset first</h3>
<p>This is the default Doctrine 2 approach, it&#8217;s quite simple &#8211; you use one query to get all the ids of the subset of top level elements, then pass these IDs to another query in a &#8220;WHERE IN&#8221; clause. When you look at the resulting SQL, it can be quite scary, especially if you are dealing with many results &#8211; you can easily be saying &#8220;WHERE IN (1,2,3,4&#8230;..9999999999)&#8221;. Most dbms will handle this surprisingly well, as long as you are using the primary keys, so experiment with it and it might be the way to go.</p>
<pre class="brush: php; title: ;">

if ($limit)
{
  $subQuery = $this-&gt;createQuery(&quot;foo&quot;)
                   -&gt;select(&quot;foo.id&quot;)
                   -&gt; //
                   -&gt;limit(50);
  $ids      = $subQuery-&gt;execute(array(), DOCTRINE_CORE::HYDRATE_SINGLE_SCALAR);
  $query-&gt;andWhereIn(&quot;cf.id&quot;, $ids);
}
</pre>
<p>Note the use of &#8220;single scalar hydration&#8221; &#8211; we have no need for more than this (to be really picky could go straight to PDO here but for consistency this is ok). In this case, the single scalar hydration will give us a resulting array of raw IDs, which is exactly what we need to pass to the main query.</p>
<h3>Make your own subquery</h3>
<p>A variation on the above is to embed the &#8220;ID sucking&#8221; query into your main query, some database engines may prefer this style, but I have not noticed any significant performance gain or loss doing this so prefer the above option as it&#8217;s cleaner in the PHP code.</p>
<pre class="brush: php; title: ;">

$query-&gt;whereIn('SELECT id FROM my_other_table WHERE blah LIMIT 50');
</pre>
<p>In a perfect world, this is the kind of thing Doctrine could have done instead of the subquery magic, but there are so many factors to consider here that I can understand why they did not go down that route.</p>
<h3>Stick with the magic, but simplify</h3>
<p>It is also possible to continue using the magic, but greatly improve performance by simplifying. Remove all those second+ level joins and use separate queries to get hold of the data you need. How often have you added a chain of joins just to get one snippet of data from the last node? Scrap all the joins and make a new query later where you can pass in all the IDs from your main query and get the data you need. Now you don&#8217;t need a limit clause, because you are asking for exactly the data you need in the first place.</p>
<h2>Start with the fastest hydration mode and work upwards</h2>
<p>This one I can&#8217;t stress enough &#8211; an ORM such as Doctrine is there to give you the tools you need when you need them, but it is often the case that applications are built with all the overhead and magic just because it can be, or because it&#8217;s the default behaviour. Stop. Look at what data you *actually* need, and especially ask yourself if you need objects in your results. Perhaps you are retrieving all your users and listing them with their profile data, but you are hydrating them as objects because you need some custom functions you&#8217;ve written, classic examples are getAge() or getFullName() which are derived from other fields. If this is the only reason you are object hydrating, consider something like this:</p>
<pre class="brush: php; title: ;">

class User
{
  function getAge()
  {
    return self::getAgeFromDOB($this[&quot;dob&quot;]);
  }

  function getFullName()
  {
    return self::getFullNameFromUserArray($this);
  }

  public static function getAgeFromDOB($dob)
  {
    $dob = strtotime($dob);

    $year_diff  = date(&quot;Y&quot;) - date(&quot;Y&quot;, $dob);
    $month_diff = date(&quot;m&quot;) - date(&quot;m&quot;, $dob);
    $day_diff   = date(&quot;d&quot;) - date(&quot;d&quot;, $dob);

    if ($month_diff &amp;lt; 0 || ($month_diff == 0 &amp;amp;&amp;amp; $day_diff &amp;lt; 0))
    {
      $year_diff--;
    }
    return $year_diff;
  }

  public static function getFullNameFromUserArray($user)
  {
    return $user[&amp;quot;first_name&amp;quot;] . &amp;quot; &amp;quot; . $user[&amp;quot;first_name&amp;quot;];
  }
}
</pre>
<p>In this example, we&#8217;ve kept the sideways compatibility of the getFullName function with array/object hydration, so it will work whether an object is passed or an array (sanity checking needed of course). This method could be expanded to support more &#8220;raw&#8221; hydration methods also. Now in our templates, we can just use:</p>
<pre class="brush: php; title: ;">
&lt;li&gt;&lt;?php echo $user[&quot;username&quot;]; ?&gt;&lt;/li&gt;
&lt;li&gt;&lt;?php echo $user[&quot;Addresses&quot;][0][&quot;city&quot;]; ?&gt;&lt;/li&gt;
&lt;li&gt;&lt;?php echo User::getFullNameFromUserArray($user); ?&gt;&lt;/li&gt;
&lt;li&gt;&lt;?php echo User::getAgeFromDOB($user[&quot;dob&quot;]); ?&gt;&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
</pre>
<p>This can massively speed up your application if you have long lists or are generally dealing with lots of data, especially data than spans several levels.</p>
<p>Lets also take a second to consider the super fast hydration methods, if we are really struggling for resources (perhaps working with large downloadable reports) and we can live with slightly less friendly arrays of data, scalar hydration can save the day. Shifting to scalar hydration means we lose the ability to later instantly switch to object hydration due to the alternate syntax and lack of nesting, but if we are considering scalar hydration in the first place we are probably in a situation where object hydration will never be practical.</p>
<pre class="brush: php; title: ;">
&lt;li&gt;&lt;?php echo $results[&quot;u_username&quot;]; ?&gt;&lt;/li&gt;
&lt;li&gt;&lt;?php echo $results[&quot;a_city&quot;]; ?&gt;&lt;/li&gt;
&lt;li&gt;&lt;?php echo User::getFullNameFromUserArray(array(&quot;first_name&quot; =&gt; $results[&quot;u_first_name&quot;], &quot;last_name&quot; =&gt; $[&quot;u_last_name&quot;])); ?&gt;&lt;/li&gt;
&lt;li&gt;&lt;?php echo User::getAgeFromDOB($results[&quot;u_dob&quot;]); ?&gt;&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
</pre>
<p>I could go on and on but I hope these points have given you some food for thought!</p>
]]></content:encoded>
			<wfw:commentRss>http://elephpants.blog.redpill-linpro.com/2011/10/07/optimising_a_php_symfony_doctrine_application-2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Ubuntu and phpunit.</title>
		<link>http://elephpants.blog.redpill-linpro.com/2011/09/15/ubuntu-and-phpunit/</link>
		<comments>http://elephpants.blog.redpill-linpro.com/2011/09/15/ubuntu-and-phpunit/#comments</comments>
		<pubDate>Thu, 15 Sep 2011 08:40:08 +0000</pubDate>
		<dc:creator>thomasez</dc:creator>
				<category><![CDATA[Howto]]></category>
		<category><![CDATA[phpunit]]></category>
		<category><![CDATA[tools]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://elephpants.blog.redpill-linpro.com/2011/09/15/</guid>
		<description><![CDATA[I had the annoying message about modules missing when I upgraded to Natty (or even Maverick?) and started Googling it. I was not alone but the maintainers seems to not care so people was going around it. They tended to try to get the existing phpunit package running by adding pear pacages like mads.. I <a href='http://elephpants.blog.redpill-linpro.com/2011/09/15/ubuntu-and-phpunit/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p>I had the annoying message about modules missing when I upgraded to Natty (or even Maverick?) and started Googling it.</p>
<p>I was not alone but the maintainers seems to not care so people was going around it. They tended to try to get the existing phpunit package running by adding pear pacages like mads..</p>
<p>I did that aswell, once. And got borded. Instead I downloaded an old phpunit package and installed it. And then Ubuntu found out there was a new one and wanted to upgrade to that, which we now know, is broken.</p>
<p>So, we download and then stop apt to upgrade.</p>
<pre>cd /tmp
wget http://no.archive.ubuntu.com/pool/universe/p/phpunit/phpunit_3.4.13-1_all.deb
sudo dpkg -i phpunit_3.4.13-1_all.deb
sudo echo phpunit hold | dpkg --set-selections</pre>
<p>Then it will stick. You&#8217;ll have an older version, 3.4 instead of 3.5 but at least it works.</p>
]]></content:encoded>
			<wfw:commentRss>http://elephpants.blog.redpill-linpro.com/2011/09/15/ubuntu-and-phpunit/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>var_dump is nice and all, but..</title>
		<link>http://elephpants.blog.redpill-linpro.com/2011/09/13/var_dump-is-nice-and-all-but/</link>
		<comments>http://elephpants.blog.redpill-linpro.com/2011/09/13/var_dump-is-nice-and-all-but/#comments</comments>
		<pubDate>Tue, 13 Sep 2011 07:39:44 +0000</pubDate>
		<dc:creator>alek</dc:creator>
				<category><![CDATA[Debugging]]></category>
		<category><![CDATA[screencast]]></category>

		<guid isPermaLink="false">http://elephpants.blog.redpill-linpro.com/2011/09/13/</guid>
		<description><![CDATA[While I am a firm believer in TDD [Test Driven Development], we all know that a lot of the time you dump an object or variable to chase a bug down the rabbit hole. And while both print_r and var_dump are usable for this, especially after Xdebug made var_dump a lot nicer. However, this was <a href='http://elephpants.blog.redpill-linpro.com/2011/09/13/var_dump-is-nice-and-all-but/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p>While I am a firm believer in TDD [Test Driven Development], we all know that a lot of the time you dump an object or variable to chase a bug down the rabbit hole. And while both print_r and var_dump are usable for this, especially after Xdebug made var_dump a lot nicer. However, this was not enough for me, I wanted more power, at first for dealing with the depth and recursion, so I built my own debug tool. It has grown quite a bit and it is <a title="Al13 on Github" href="https://github.com/alkemann/AL13/tree/master/al13_debug" target="_blank">available on Github</a> [1].<br />
It supports these features:</p>
<ul>
<li>Automatic block recursive references (only show an object once)</li>
<li>Easy on-the-fly change of depth* Blacklist classes, keys and properties</li>
<li>Meta info about objects like access level of properties</li>
<li>Includes knowledge of where it dies when you debug-die</li>
<li>Alternative adapters for outputting to file, json or firephp</li>
<li>Inspect global defines</li>
<li>Output a trace of &#8220;how you got here&#8221;</li>
<li>Dump an api (method list) of an object</li>
</ul>
<p>The tool is basically just a Debug class with an adapter (typically Html for browser output). It also comes with a css for styling the output as well as a &#8220;bootstrap&#8221; file where you can set up default values, import them from your framework and define convenience method. The most used such functions are d() and dd(). The first will debug dump any amount of variables with the default values. The second will dump and die, with an ob_flush, allowing you to use the debug dumping anywhere in your project without worrying about started output or headers etc.<br />
You can try it for yourself, but here is a little screencast that demonstrates the kinds of outputs it shows:</p>
<p><a href="http://www.youtube.com/watch?v=CBWFM_bs6nw">http://www.youtube.com/watch?v=CBWFM_bs6nw</a></p>
<p>[1] <a href="https://github.com/alkemann/AL13/tree/master/al13_debug" target="_blank">https://github.com/alkemann/AL13/tree/master/al13_debug</a></p>
]]></content:encoded>
			<wfw:commentRss>http://elephpants.blog.redpill-linpro.com/2011/09/13/var_dump-is-nice-and-all-but/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Practising the fundamentals &#8211; new blog series!</title>
		<link>http://elephpants.blog.redpill-linpro.com/2011/09/09/practising-the-fundamentals-new-blog-series/</link>
		<comments>http://elephpants.blog.redpill-linpro.com/2011/09/09/practising-the-fundamentals-new-blog-series/#comments</comments>
		<pubDate>Fri, 09 Sep 2011 09:54:56 +0000</pubDate>
		<dc:creator>juneih</dc:creator>
				<category><![CDATA[Fundamentals]]></category>
		<category><![CDATA[PHP Functions]]></category>
		<category><![CDATA[break]]></category>
		<category><![CDATA[series]]></category>

		<guid isPermaLink="false">http://elephpants.blog.redpill-linpro.com/2011/09/09/</guid>
		<description><![CDATA[You would be forgiven for thinking that experts never do the boring beginners stuff. Surely, the football player getting paid X fantazillion gold dubloons a week (yes it is a figure so large it is measured by the week), surely he with all that skill and money, does not practise passing? Or ball receiving? But <a href='http://elephpants.blog.redpill-linpro.com/2011/09/09/practising-the-fundamentals-new-blog-series/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p>You  would be forgiven for thinking that experts never do the boring  beginners stuff. Surely, the football player getting paid X fantazillion  gold dubloons a week (yes it is a figure so large it is measured by the  week), surely he with all that skill and money, does not practise  passing? Or ball receiving? But he does &#8211; in fact that is why he is an  expert.</p>
<p>We  are all in different places on our way to glory, stardom and general  PHP-related insight &#8211; but what we have in common on this path could be  that we have to keep practising the fundamentals. It is never a bad idea  to re-read that man page, or to get more background information on  things you already know. Since last time you visited that man page, you  have learned new stuff which will give you more insight or a different  perspective this time around. Often I find I have misunderstood some  concepts, and repetition helps correcting a point of view about to go  askew.</p>
<p>Here is a small example to get you started: did you know break[1] accepts  parameters? Neither did I. Think about it. Why would you even look up  break, you have used break hundreds of times before, you know how it  works and when you should use it. In fact it is so basic you would think  it does not have much of an entry &#8211; a quick lookup from vim in the  PHP-docs [2] though &#8211; and tada &#8211; there it is. White on black: break  accepts an optional parameter to break out of zero, one or more  loop-flavour or switch. You know you will be needing it shortly.</p>
<p>Like  that football player spending a late practise shooting at the goal, so  should we practise our  fundamentals. I’m passing this on to bjori next  month &#8211; he’ll give you one of his to ponder.</p>
<p>[1]   <a href="http://php.net/break">http://php.net/break</a><br />
[2]  You can have unix man pages for PHP functions integrated in Vim &#8211; so  you don’t even have to waste bandwidth. Awesome.<a href="http://bjori.blogspot.com/2010/01/unix-manual-pages-for-php-functions.html" target="_blank"> http://bjori.blogspot.com/2010/01/unix-manual-pages-for-php-functions.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://elephpants.blog.redpill-linpro.com/2011/09/09/practising-the-fundamentals-new-blog-series/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>FirePHP 1.0 Beta!</title>
		<link>http://elephpants.blog.redpill-linpro.com/2011/03/30/firephp-1-0-beta/</link>
		<comments>http://elephpants.blog.redpill-linpro.com/2011/03/30/firephp-1-0-beta/#comments</comments>
		<pubDate>Wed, 30 Mar 2011 19:58:19 +0000</pubDate>
		<dc:creator>wojak</dc:creator>
				<category><![CDATA[Debugging]]></category>
		<category><![CDATA[firephp]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[introduction]]></category>

		<guid isPermaLink="false">http://elephpants.blog.redpill-linpro.com/2011/03/30/</guid>
		<description><![CDATA[1. Installation Create a file &#8220;package.json&#8221; with the following content (set uid of your package) { "uid": "(your package uid)" } Create a file called &#8220;package.json&#8221; with with content as example below (add IP restriction or/and keys), the example gives unlimited access. { "cadorn.org/insight/@meta/config/0": { "allow": { "ips": [ "*" ], "authkeys": [ "*" ] <a href='http://elephpants.blog.redpill-linpro.com/2011/03/30/firephp-1-0-beta/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p><strong>1. Installation</strong><br />
Create a file &#8220;package.json&#8221; with the following content (set uid of your package)<br />
<code>{<br />
"uid": "(your package uid)"<br />
}</code></p>
<p>Create a file called &#8220;package.json&#8221; with with content as example below (add IP restriction or/and keys), the example gives unlimited access.<br />
<code>{<br />
"cadorn.org/insight/@meta/config/0": {<br />
"allow": {<br />
"ips": [ "*"  ],<br />
"authkeys": [ "*" ]<br />
}<br />
}<br />
}</code></p>
<p><a href="http://upgrade.firephp.org/">Download the server library</a>, the easiest is to use phar file, and set up your virtual host:<br />
<code>&lt;VirtualHost *:80&gt;<br />
php_value auto_prepend_file phar:///var/www/firePHP_1.0/firephp.phar/FirePHP/Init.php<br />
SetEnv INSIGHT_CONFIG_PATH /var/www/firePHP_1.0/package.json,/var/www/firePHP_1.0/credentials.json<br />
...<br />
&lt;/VirtualHost&gt;</code></p>
<p>Install client plugin (FirePHP Companion) in your web browser,</p>
<p><strong>2. Page Context</strong><br />
<code> $inspector = FirePHP::to("page");<br />
$console = $inspector-&gt;console();<br />
$console-&gt;log("Hello World");</code></p>
<p><strong>3. Request Context</strong><br />
<code> $inspector = FirePHP::to("request");<br />
$console = $inspector-&gt;console();<br />
$console-&gt;log("Hello World");</code></p>
<p><strong>4. Controller Context</strong><br />
<code> $inspector = FirePHP::to("request");<br />
$console = $inspector-&gt;console();<br />
$console-&gt;log("Hello World");<br />
$controller = FirePHP::to("controller");<br />
$controller-&gt;triggerInspect()</code><br />
<strong><br />
5. Package Context</strong><br />
<code> $package = FirePHP::to("package");<br />
$package-&gt;addQuickLink("Link 1", "http://www.firephp.org/");<br />
$package-&gt;addQuickLink("Link 2", array(<br />
"target" =&gt; "window", // tab (default), window or hidden<br />
"url" =&gt; "http://www.firephp.org/"<br />
));</code><br />
<code><br />
$controller = FirePHP::to("controller");<br />
$controller-&gt;triggerInspect();</code></p>
<p><strong>6. Basic API</strong><br />
<code> $inspector = FirePHP::to("request");<br />
$console = $inspector-&gt;console();<br />
$variable = "Hello World";</code></p>
<p><code> $console-&gt;log($variable);<br />
$console-&gt;info($variable);<br />
$console-&gt;warn($variable);<br />
$console-&gt;error($variable);</code></p>
<p><code> // Message Label<br />
$console-&gt;label("My label")-&gt;log($variable);</code></p>
<p><code> // Table<br />
$header = array("Column 1 Heading", "Column 2 Heading");<br />
$table = array(<br />
array("Row 1 Column 1 Value", "Row 1 Column 2 Value"),<br />
array("Row 2 Column 1 Value", "Row 2 Column 2 Value"),<br />
);<br />
$console-&gt;table("Table", $table);<br />
$console-&gt;table("Table with header", $table, $header);</code></p>
<p><code> // Stack Traces<br />
$console-&gt;trace("My stack trace");</code></p>
<p><code> // Group<br />
$group = $console-&gt;group("myGroup", "Group Title")-&gt;open();<br />
$console-&gt;info("Hey!, I am in a group");<br />
$console-&gt;error("I am in a group too!");<br />
$group-&gt;close();</code><br />
<code><br />
// Console controller<br />
$controller = FirePHP::to("controller");<br />
$controller-&gt;triggerInspect();</code></p>
<p><strong>7. Conditional Logging</strong></p>
<p><code> $inspector = FirePHP::to("request");<br />
$console = $inspector-&gt;console();<br />
</code><br />
<code> $console-&gt;on("Show warnings")-&gt;warn("I am warning you!");</code></p>
<p><code> // Console controller<br />
$controller = FirePHP::to("controller");<br />
$controller-&gt;triggerInspect();<br />
</code></p>
<p><strong>8. Engine API</strong><br />
<code> $inspector = FirePHP::to("request");<br />
$console = $inspector-&gt;console();<br />
$engine = FirePHP::plugin("engine");<br />
// Send all exceptions and errors to a specific console<br />
$engine-&gt;onError($console);<br />
$engine-&gt;onAssertionError($console);<br />
$engine-&gt;onException($console);<br />
// Console controller<br />
$controller = FirePHP::to("controller");<br />
$controller-&gt;triggerInspect();</code></p>
<p><code> // Handle manually<br />
try {<br />
throw new Exception("Hello, I am a manually handled exception");<br />
} catch(Exception $e) {<br />
$engine-&gt;handleException($e);<br />
}</code></p>
<p><code> throw new Exception("Test Exception");</code></p>
<p><strong>9. FirePHP API</strong><br />
<code> $inspector = FirePHP::to("request");</code></p>
<p><code> // Log p() messages to the provided console<br />
$firephp = FirePHP::plugin("firephp");<br />
$inspectorConsole = $inspector-&gt;console("InspectorConsole");<br />
$firephp-&gt;declareP($inspectorConsole, true);</code></p>
<p><code> $variable = array("key"=&gt;"value");<br />
p($variable); // or<br />
p($inspector, "Inspector");</code></p>
<p><code> // Log the current FirePHP version to a FirePHP console.<br />
$versionConsole = $inspector-&gt;console("Version Console");<br />
$firephp-&gt;logVersion($versionConsole);</code></p>
<p><code> // Send information about the PHP environment to an Environment console.<br />
$envConsole = $inspector-&gt;console("Environment");<br />
$firephp-&gt;recordEnvironment($envConsole);</code></p>
<p><code> // Console controller<br />
$controller = FirePHP::to("controller");<br />
$controller-&gt;triggerInspect();</code></p>
<p><code> //Send all errors and exceptions to a Problems console.<br />
$problemConsole = $inspector-&gt;console("Problem Console");<br />
$firephp-&gt;trapProblems($problemConsole);<br />
</code><br />
<code> throw new Exception("I am your problem");</code></p>
]]></content:encoded>
			<wfw:commentRss>http://elephpants.blog.redpill-linpro.com/2011/03/30/firephp-1-0-beta/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>FirePHP 0.5</title>
		<link>http://elephpants.blog.redpill-linpro.com/2011/03/30/firephp-0-5/</link>
		<comments>http://elephpants.blog.redpill-linpro.com/2011/03/30/firephp-0-5/#comments</comments>
		<pubDate>Wed, 30 Mar 2011 19:26:40 +0000</pubDate>
		<dc:creator>wojak</dc:creator>
				<category><![CDATA[Debugging]]></category>
		<category><![CDATA[firephp]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[introduction]]></category>

		<guid isPermaLink="false">http://elephpants.blog.redpill-linpro.com/2011/03/30/</guid>
		<description><![CDATA[1. FirePHP 0.5 &#8211; Installation 1. Dwonload The Server Library and include it 2. require_once("./FirePHPCore-0.3.2/lib/FirePHPCore/FirePHP.class.php"); Or find a plugin for your framework. 2. Object Oriented API require_once("./FirePHPCore-0.3.2/lib/FirePHPCore/FirePHP.class.php"); $firephp = FirePHP::getInstance(true); $firephp-&#62;log("Hello World"); 3. Procedural API require_once("./FirePHPCore-0.3.2/lib/FirePHPCore/fb.php"); fb("Hello World"); fb("Hello World", "Label"); 4. Options require_once("./FirePHPCore-0.3.2/lib/FirePHPCore/FirePHP.class.php"); // Defaults: $options = array("maxObjectDepth" =&#62; 5, // Maximum depth to <a href='http://elephpants.blog.redpill-linpro.com/2011/03/30/firephp-0-5/'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p><strong>1. FirePHP 0.5 &#8211; Installation</strong><br />
1.<a href="http://www.firephp.org/"> Dwonload The Server Library</a> and include it<br />
2.<code> require_once("./FirePHPCore-0.3.2/lib/FirePHPCore/FirePHP.class.php");</code><br />
<a href="http://www.firephp.org/Wiki/Reference/FAQ">Or find a plugin for your framework.</a></p>
<p><strong>2. Object Oriented API</strong><br />
<code> require_once("./FirePHPCore-0.3.2/lib/FirePHPCore/FirePHP.class.php");<br />
$firephp = FirePHP::getInstance(true);<br />
$firephp-&gt;log("Hello World");</code></p>
<p><strong>3. Procedural API</strong><br />
<code> require_once("./FirePHPCore-0.3.2/lib/FirePHPCore/fb.php");<br />
fb("Hello World");<br />
fb("Hello World", "Label");</code></p>
<p><strong>4. Options</strong><br />
<code> require_once("./FirePHPCore-0.3.2/lib/FirePHPCore/FirePHP.class.php");</code></p>
<p><code> // Defaults:<br />
$options = array("maxObjectDepth" =&gt; 5, // Maximum depth to traverse objects.<br />
"maxArrayDepth" =&gt; 5, // Maximum depth to traverse arrays.<br />
"maxDepth" =&gt; 10, // Maximum depth to traverse mixed arrays/objects.<br />
"useNativeJsonEncode" =&gt; true, // Set to FALSE to use JSON encoder included with FirePHPCore instead of json_encode().<br />
"includeLineNumbers" =&gt; false); // Include File and Line information in message</code></p>
<p><code> $firephp = FirePHP::getInstance(true);<br />
$firephp-&gt;setOptions($options);<br />
$firephp-&gt;log("Hello World");</code></p>
<p><strong>5. Log level</strong><br />
<code> require_once("./FirePHPCore-0.3.2/lib/FirePHPCore/FirePHP.class.php");</code></p>
<p><code> $firephp = FirePHP::getInstance(true);<br />
$firephp-&gt;log("Logs a message to firebug console.");<br />
$firephp-&gt;info("Logs a message to firebug console and displays an info icon before the message.");<br />
$firephp-&gt;warn("Logs a message to firebug console, displays an warning icon before the message and colors the line turquoise.");<br />
$firephp-&gt;error("Logs a message to firebug console, displays an error icon before the message and colors the line yellow. Also increments the firebug error count.");<br />
// or<br />
$firephp-&gt;fb("Log with fb() method", FirePHP::LOG);<br />
$firephp-&gt;fb("Info with fb() method", FirePHP::INFO);<br />
$firephp-&gt;fb("Warning with fb() method", FirePHP::WARN);<br />
$firephp-&gt;fb("Error with fb() method", FirePHP::ERROR);</code></p>
<p><strong>6. Dump</strong><br />
<code>require_once("./FirePHPCore-0.3.2/lib/FirePHPCore/FirePHP.class.php");</code></p>
<p><code> $firephp = FirePHP::getInstance(true);<br />
$firephp-&gt;dump("array",array("key"=&gt;"value"));<br />
$firephp-&gt;dump("firePHP",$firephp); </code></p>
<p><strong>7. Trace</strong><br />
<code> require_once("./FirePHPCore-0.3.2/lib/FirePHPCore/FirePHP.class.php");</code></p>
<p><code> $firephp = FirePHP::getInstance(true);<br />
$firephp-&gt;trace("Trace Label"); </code></p>
<p><strong>8. Groups</strong><br />
<code> require_once("./FirePHPCore-0.3.2/lib/FirePHPCore/FirePHP.class.php");</code></p>
<p><code> $firephp = FirePHP::getInstance(true);<br />
$firephp-&gt;group("Test Group");<br />
$firephp-&gt;log("Hello World");<br />
$firephp-&gt;groupEnd();</code></p>
<p><code> $firephp-&gt;group("Collapsed and Colored Group",<br />
array("Collapsed" =&gt; true,<br />
"Color" =&gt; "#FF00FF"));<br />
$firephp-&gt;log("Hello World");<br />
$firephp-&gt;groupEnd();</code></p>
<p><strong>9. Tables</strong><br />
<code> require_once("./FirePHPCore-0.3.2/lib/FirePHPCore/FirePHP.class.php");</code></p>
<p><code> $firephp = FirePHP::getInstance(true);</code></p>
<p><code> $table = array();<br />
$table[] = array("Col 1 Heading","Col 2 Heading");<br />
$table[] = array("Row 1 Col 1","Row 1 Col 2");<br />
$table[] = array("Row 2 Col 1","Row 2 Col 2");<br />
$table[] = array("Row 3 Col 1","Row 3 Col 2");</code></p>
<p><code> $firephp-&gt;table("Table Label", $table);</code></p>
<p><strong>10. Exception Handling</strong><br />
<code> require_once("./FirePHPCore-0.3.2/lib/FirePHPCore/FirePHP.class.php");</code></p>
<p><code> $firephp = FirePHP::getInstance(true);<br />
$firephp-&gt;registerErrorHandler( $throwErrorExceptions=false);<br />
$firephp-&gt;registerExceptionHandler();<br />
$firephp-&gt;registerAssertionHandler( $convertAssertionErrorsToExceptions=true,  $throwAssertionExceptions=false);</code></p>
<p><code> throw new Exception("Test Exception");<br />
// or manually<br />
try {<br />
throw new Exception("Test Exception");<br />
} catch(Exception $e) {<br />
$firephp-&gt;error($e);<br />
} </code></p>
<p><strong>11. Disabling firePHP</strong><br />
<code> require_once("./FirePHPCore-0.3.2/lib/FirePHPCore/FirePHP.class.php");</code></p>
<p><code> $firephp = FirePHP::getInstance(true);<br />
$firephp-&gt;log("Hello");<br />
$firephp-&gt;setEnabled(false);<br />
$firephp-&gt;log("Hello again");<br />
</code></p>
]]></content:encoded>
			<wfw:commentRss>http://elephpants.blog.redpill-linpro.com/2011/03/30/firephp-0-5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

