<?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>David Goodwin &#187; php</title>
	<atom:link href="http://codepoets.co.uk/tag/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://codepoets.co.uk</link>
	<description>PHP, running, family stuff, Bromsgrove and other bits</description>
	<lastBuildDate>Fri, 11 May 2012 09:43:39 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Netbeans vs Vim &#8230; round 1 &#8230; fight</title>
		<link>http://codepoets.co.uk/2012/netbeans-vs-vim-round-1-fight/</link>
		<comments>http://codepoets.co.uk/2012/netbeans-vs-vim-round-1-fight/#comments</comments>
		<pubDate>Fri, 13 Apr 2012 14:49:25 +0000</pubDate>
		<dc:creator>David Goodwin</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[netbeans]]></category>
		<category><![CDATA[psr0]]></category>
		<category><![CDATA[vim]]></category>

		<guid isPermaLink="false">http://codepoets.co.uk/?p=558</guid>
		<description><![CDATA[So, I think I&#8217;ve changed &#8216;editor&#8217;. Perhaps this is a bit like an engineer changing their calculator or something. For the last 10 years, I&#8217;ve effectively only used &#8216;vim&#8216; for development of any PHP code I work on. I felt I was best served using something like vim &#8211; where the interface was uncluttered, everything &#8230; <a class="read-excerpt" href="http://codepoets.co.uk/2012/netbeans-vs-vim-round-1-fight/">Continue reading <span class="meta-nav">&#187;</span></a>]]></description>
			<content:encoded><![CDATA[<p>So, I think I&#8217;ve changed &#8216;editor&#8217;. Perhaps this is a bit like an engineer changing their calculator or something.</p>
<p>For the last 10 years, I&#8217;ve effectively only used &#8216;<a title="Vim - an excellent text based editor" href="http://www.vim.org/">vim</a>&#8216; for development of any PHP code I work on.</p>
<p>I felt I was best served using something like vim &#8211; where the interface was uncluttered, everything was a keypress away and I could literally fill my entire monitor with code. This was great if my day consisted of writing new code.</p>
<p>Unfortunately, this has rarely been the case for the last few years. I&#8217;ve increasingly found myself dipping in and out of projects &#8211; or needing to navigate through a complex set of dependencies to find methods/definitions/functions &#8211; thanks to  the likes of <a title="PSR0 - PHP naming convention(s)" href="https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md">PSR0</a>. Suffice to say, Vim doesn&#8217;t really help me do this.</p>
<p>Perhaps, I&#8217;ve finally learnt that &#8216;raw&#8217; typing speed is not the only measure of productivity &#8211; navigation through the codebase, viewing inline documentation or having a debugger at my fingertips is also important.</p>
<p>So, last week, while working on one project, I eventually got fed up of juggling between terminals and fighting with tab completion that I re-installed netbeans &#8211; so, while I&#8217;m sure vim can probably do anything netbeans can &#8211; if you have the right plugin installed and super flexible fingers.</p>
<p>So, what have I gained/lost :</p>
<ul>
<li>a 10 second slow down &#8211; that&#8217;s how long it takes to start Netbeans &#8211; even with an SSD and a desktop that should be quick enough (perhaps this is justification for a faster desktop?). Lesson learnt &#8211; do not close Netbeans.</li>
<li>indexing of the code &#8211; although this takes some time when importing an existing project &#8211; it does make it very quick to &#8216;find uses&#8217; of function/class X</li>
<li>the ability to easily jump to a function/class definition (right click, find uses &#8230;)</li>
<li>a list of &#8216;todo&#8217; items &#8211; from my code comments &#8230; this has led to me removing some old legacy cruft&#8230;</li>
<li>the &#8216;refactor&#8217; functionality &#8211; i.e. rename function <em>old_name()</em> and change all instances of it to <em>new_name()</em></li>
<li>code indentation seems to work better under netbeans</li>
<li>inline &#8216;warnings&#8217; (i.e. unused variable, previously undefined variable[x], syntax errors etc) &#8211; so I don&#8217;t have to wait for them to appear in a browser or elsewhere.</li>
<li>inline documentation etc while typing (i.e. type in <em>in_array(</em> and it reminds me where the needle and haystack are)</li>
<li>with the right them, a nicer editor Window (mine is based on <a title="Netbeans Dark Theme" href="http://brandonbeasley.com/blog/netbeans-dark-color-theme/">BrandonDark</a>)</li>
</ul>
<p>x &#8211; Fails with global variables on legacy projects though &#8211; in that netbeans doesn&#8217;t realise the variable has been sucked in through a earlier &#8216;require&#8217; call.</p>
<p>I did briefly look at <a title="Sublime text editor" href="http://www.sublimetext.com">sublime</a> a few weeks ago, but couldn&#8217;t see what the fuss was about &#8211; it didn&#8217;t seem to do very much &#8211; apart from have multiple tabs open for the various files I was editing.</p>
]]></content:encoded>
			<wfw:commentRss>http://codepoets.co.uk/2012/netbeans-vs-vim-round-1-fight/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>A week of fire fighting (aka why you should </title>
		<link>http://codepoets.co.uk/2012/a-week-of-fire-fighting-aka-why-you-should/</link>
		<comments>http://codepoets.co.uk/2012/a-week-of-fire-fighting-aka-why-you-should/#comments</comments>
		<pubDate>Fri, 17 Feb 2012 14:47:50 +0000</pubDate>
		<dc:creator>David Goodwin</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[work]]></category>

		<guid isPermaLink="false">http://codepoets.co.uk/?p=493</guid>
		<description><![CDATA[I feel like I&#8217;ve spent most of this week debugging some PHP code, and writing unit tests for it. Thankfully I think this firefighting exercise is nearly over. Perhaps the alarm bells should have been going off a bit more in my head when it was implied that the code was being written in a &#8230; <a class="read-excerpt" href="http://codepoets.co.uk/2012/a-week-of-fire-fighting-aka-why-you-should/">Continue reading <span class="meta-nav">&#187;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I feel like I&#8217;ve spent most of this week debugging some PHP code, and writing unit tests for it. Thankfully I think this firefighting exercise is nearly over.</p>
<p>Perhaps the alarm bells should have been going off a bit more in my head when it was implied that the code was being written in a quick-and-dirty manner (&#8220;as long as it works&#8230;.&#8221;) and the customer kept adding in additional requirements &#8211; to the extent it is no longer clear where the end of the project is.</p>
<p>&#8220;It&#8217;s really simple &#8211; you just need to get a price back from two APIs&#8221;</p>
<p>then they added in :</p>
<p>&#8220;Some customers need to see the cheapest, some should only see some specific providers &#8230;&#8221;</p>
<p>and then :</p>
<p>&#8220;We want a global markup to be applied to all quotes&#8221;</p>
<p>and then :</p>
<p>&#8220;We also want a per customer markup&#8221;</p>
<p>and so on&#8230;.</p>
<p>And the customer didn&#8217;t provide us with any verified test data (i.e. for a quote consisting of X it should cost A+B+C+D=Y).</p>
<p>The end result is an application which talks to two remote APIs to retrieve quotes. Users are asked at least 6 questions per quote (so there are a significant number of variations).</p>
<p>Experience made me slightly paranoid about editing the code base &#8211; I was worried I&#8217;d fix a bug in one pathway only to break another. On top of which, I initially didn&#8217;t really have any idea of whether it was broken or not &#8211; because I didn&#8217;t know what the correct (£) answers were.</p>
<p>Anyway, to start with, it was a bit like :</p>
<ul>
<li>Deploy through some weird copy+pasting manner due to Windows file permissions</li>
<li>No unit test coverage</li>
<li>No logging</li>
<li>Apparently finished</li>
<li>Apparently working (but the customer kept asking for more changes)</li>
</ul>
<p>Now:</p>
<ul>
<li>Deployment through git; Stupid Windows file permissions fixed.</li>
<li>Merged in changes by third party graphics designer &#8211; should be much easier to track any changes he makes in the future</li>
<li>~80% test code coverage. I&#8217;ve had to modify the &#8216;real&#8217; scripts to accept a new parameter, which would make them read a local XML file (rather than the remote API/service) &#8211; in order for the tests to be reproducible (and quick to run)</li>
<li>Logging in place, so there&#8217;s some traceability</li>
<li>Better error handing</li>
<li>Calculations manually checked and confirmed.</li>
</ul>
<p>Interesting things I didn&#8217;t like about the code :</p>
<ul>
<li>Premature attempt at dependency injection &#8211; the few functions there are/were have a $db variable being passed in &#8211; but often don&#8217;t use it.</li>
<li>There is significant duplication in the code base still.</li>
<li>The code didn&#8217;t (and still doesn&#8217;t really) support testing particularly well &#8211; I&#8217;m having to retrieve output through a Zend_Http_Client call (i.e. mimicking a browser) &#8211; which means I can&#8217;t get code test coverage stats easily.</li>
<li>In some places a variable was being set to 0 (e.g. $speed) which would be used to determine a special case (if $speed == 0). Having multiple meanings in/on the same variable makes it difficult to follow what&#8217;s going on &#8211; and is a pain when the customer requests it behaves a bit differently. Really a separate parameter should have been used.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://codepoets.co.uk/2012/a-week-of-fire-fighting-aka-why-you-should/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Zend_Cache &#8211; automatic cache cleaning can be bad, mmkay?</title>
		<link>http://codepoets.co.uk/2011/zend_cache-automatic-cache-cleaning-can-be-bad-mmkay/</link>
		<comments>http://codepoets.co.uk/2011/zend_cache-automatic-cache-cleaning-can-be-bad-mmkay/#comments</comments>
		<pubDate>Tue, 05 Jul 2011 10:02:36 +0000</pubDate>
		<dc:creator>David Goodwin</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[xdebug]]></category>
		<category><![CDATA[zend cache]]></category>

		<guid isPermaLink="false">http://codepoets.co.uk/?p=430</guid>
		<description><![CDATA[$customer uses Zend_Cache in their codebase &#8211; and I noticed that every so often a page request would take ~5 seeconds (for no apparent reason), while normally they take &#60; 1 second &#8230; Some rummaging and profiling with xdebug showed that some requests looked like : Note how there are 25,000 or so calls for &#8230; <a class="read-excerpt" href="http://codepoets.co.uk/2011/zend_cache-automatic-cache-cleaning-can-be-bad-mmkay/">Continue reading <span class="meta-nav">&#187;</span></a>]]></description>
			<content:encoded><![CDATA[<p>$<a title="Food Hygiene Ratings - Scores On The Doors" href="http://www.scoresonthedoors.org.uk">customer</a> uses Zend_Cache in their codebase &#8211; and I noticed that every so often a page request would take ~5 seeconds (for no apparent reason), while normally they take &lt; 1 second &#8230;</p>
<p>Some rummaging and profiling with <a title="xdebug php profiler etc" href="http://xdebug.org">xdebug</a> showed that some requests looked like :</p>
<div id="attachment_434" class="wp-caption alignnone" style="width: 160px"><a href="http://codepoets.co.uk/wp-content/uploads/2011/07/Screen-shot-2011-07-05-at-11.50.30.png"><img class="size-thumbnail wp-image-434" title="xdebug profiling output - note lots of zend_cache stuff" src="http://codepoets.co.uk/wp-content/uploads/2011/07/Screen-shot-2011-07-05-at-11.50.30-150x150.png" alt="xdebug profiling output - note lots of zend_cache stuff" width="150" height="150" /></a><p class="wp-caption-text">xdebug profiling output - note lots of zend_cache stuff</p></div>
<p>Note how there are 25,000 or so calls for various Zend_Cache_Backend_File thingys (fetch meta data, load contents, flock etc etc).</p>
<p>This alternative rendering might make it more clear &#8211; especially when compared with the image afterwards :</p>
<div id="attachment_432" class="wp-caption alignnone" style="width: 160px"><a href="http://codepoets.co.uk/wp-content/uploads/2011/07/Screen-shot-2011-07-05-at-11.53.23.png"><img class="size-thumbnail wp-image-432" title="zend cache dominating the call map" src="http://codepoets.co.uk/wp-content/uploads/2011/07/Screen-shot-2011-07-05-at-11.53.23-150x150.png" alt="zend cache dominating the call map" width="150" height="150" /></a><p class="wp-caption-text">zend cache dominating the call map</p></div>
<p>while a normal request should look more like :</p>
<div id="attachment_433" class="wp-caption alignnone" style="width: 160px"><a href="http://codepoets.co.uk/wp-content/uploads/2011/07/Screen-shot-2011-07-05-at-11.52.42.png"><img class="size-thumbnail wp-image-433" title="a &quot;normal&quot; request - note Zend_Cache is not dominating " src="http://codepoets.co.uk/wp-content/uploads/2011/07/Screen-shot-2011-07-05-at-11.52.42-150x150.png" alt="a &quot;normal&quot; request - note Zend_Cache is not dominating " width="150" height="150" /></a><p class="wp-caption-text">a &quot;normal&quot; request - note Zend_Cache is not dominating </p></div>
<p>Zend_Cache has a &#8216;automatic_cleaning_mode&#8217; frontend parameter &#8211; which is by default set to 10 (i.e. 10% of all write requests to the cache result in it checking if there is anything to garbage collect/clean). Since we&#8217;re nearly always writing something to the cache, this results in 10% of requests triggering the cleaning logic.</p>
<p>See <a title="zend framework - cache - frontend docs" href="http://framework.zend.com/manual/en/zend.cache.frontends.html">http://framework.zend.com/manual/en/zend.cache.frontends.html</a>.</p>
<p>&nbsp;</p>
<p>The cleaning is now run via a cron job something like :</p>
<p>$cache_instance-&gt;clean(Zend_Cache::CLEANING_MODE_OLD);</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://codepoets.co.uk/2011/zend_cache-automatic-cache-cleaning-can-be-bad-mmkay/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>A caching PHP autoloader</title>
		<link>http://codepoets.co.uk/2011/a-caching-php-autoloader/</link>
		<comments>http://codepoets.co.uk/2011/a-caching-php-autoloader/#comments</comments>
		<pubDate>Mon, 21 Mar 2011 21:52:58 +0000</pubDate>
		<dc:creator>David Goodwin</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[apc]]></category>
		<category><![CDATA[autoload]]></category>
		<category><![CDATA[zend framework]]></category>
		<category><![CDATA[zend_cache]]></category>

		<guid isPermaLink="false">http://codepoets.co.uk/?p=303</guid>
		<description><![CDATA[This is probably of little use to normal people, or even many PHP programmers &#8211; unless you have more than a handful of directories to rummage through when __autoload()&#8217;ing PHP class files. I&#8217;ve sometimes found myself rummaging through 10-15, and this has a performance impact. Some random code which uses APC to cache a lookup &#8230; <a class="read-excerpt" href="http://codepoets.co.uk/2011/a-caching-php-autoloader/">Continue reading <span class="meta-nav">&#187;</span></a>]]></description>
			<content:encoded><![CDATA[<p>This is probably of little use to normal people, or even many <a title="PHP" href="http://php.net">PHP</a> programmers &#8211; unless you have more than a handful of directories to rummage through when __<a title="__autoload (PHP manual)" href="http://uk.php.net/__autoload">autoload</a>()&#8217;ing PHP class files. I&#8217;ve sometimes found myself rummaging through 10-15, and this has a performance impact. Some random code which uses APC to cache a lookup of class name to absolute file path is below.</p>
<p>For historical reasons, a few projects of mine look in a number of directories (perhaps 10-15) for object files, and I&#8217;ve used an autoload function to handle the code inclusion. Unfortunately at the time, I wasn&#8217;t sensible enough to follow e.g. the <a title="Zend Framework - autoloading etc" href="http://framework.zend.com/manual/en/learning.autoloading.design.html">Zend</a>/<a title="PEAR" href="http://pear.php.net">PEAR</a> framework&#8217;s naming convention which would have allowed me to greatly reduce the number of directory lookups when autoloading. In my mind it made sense to e.g keep <a title="Smarty - PHP template engine" href="http://smarty.net">Smarty</a> in it&#8217;s own separate directory (and not rely on PEAR packages being installed and of the right version) and ditto with ezComponents, Zend Framework and so on with a few bits I wrote.</p>
<p>One approach I could have taken would be to generate a fixed class map &#8211; similar to how <a title="Propel installation stuff" href="http://www.propelorm.org/wiki/Documentation/1.5/BuildTime">Propel</a> now behaves (or <a title="ezComponents - class loading etc" href="http://share.ez.no/learn/ez-publish/an-introduction-to-ez-components/(page)/3">ezComponents</a>, for that matter), but I&#8217;m too lazy to do that &#8211; so instead I changed my Autoloader to perform some caching &#8211; namely it remembers where it&#8217;s found objects with a given name from before. Years ago, I found this <a title="A PHP Autoloader class " href="http://anthonybush.com/projects/autoloader/">Autoloader</a> class, and the other day I thought I&#8217;d finally look into using it. Unfortunately (for it) I didn&#8217;t think much of it&#8217;s code &#8211; specifically, I think if a class contains only static functions, then it&#8217;s probably designed incorrectly; I also wanted to use <a title="APC - PHP Op-Code Cache and more" href="http://pecl.php.net/APC">APC</a> to cache the class lookup map &#8211; rather than  relying on a file on disk (well, one aim is to improve performance, so I might as well try&#8230;).</p>
<p>So, without any further ado, here&#8217;s some code.</p>
<pre class="brush:php">/**
 * Autoloader is a class scanner with caching. i.e. it'll try and discover class files in the
 * given list of directories, and if it finds matche(s) it'll save them in a cache for later use (E.g. APC via Zend_Cache)
 *
 *
 *
 * @see http://anthonybush.com/projects/autoloader/
 * DG re-coded it to not be all static, as that seems stupid.
 *
 *  Sample Usage:
 *  include_once('Autoloader.php');
 *  $autoloader = Autoloader::getInstance();
 *  $autoloader-&gt;addClassPath('path/to/classes');
 *  $autoloader-&gt;addClassPath(explode(':', ini_get('include_path'));
 *  $autoloader-&gt;setCache(Zend_Cache_Frontend $x); // APC?
 *  $autoloader-&gt;excludeFolderNamesMatchingRegexp('/^CVS|^\./');
 *  $autoloader-&gt;ignoreClassNamesRegexp('/Zend_/'); // use e.g. Zend_Loader instead.
 *  $autoloader-&gt;setCacheKey('whatever');
 *  $autoloader-&gt;register(); // register with SPL.
 *
 * @author Original: Anthony Bush, Wayne Wight
 * @author David Goodwin
 * @copyright 2006-2008 Academic Superstore. This software is open source protected by the FreeBSD License.
 * @version 2011-04-18
 **/

class Autoloader {
    /* @var Autoloader singleton static thing */
    private static $instance = null;

    /* @var string cache key; should be unique per project using this,
      if multiple projects on the same server. */
    protected $cacheKey = 'autoloader_cache';
    /* @var array */
    protected $classPaths = array();
    /* @var string */
    protected $classFileSuffix = '.php';
    /* @var Zend_Cache instance */
    protected $cacheBackend = null;
    /* @var array list of directories to rummage through */
    protected $cachedPaths = null;
    /* @var string regexp to use to exclude folders we do not wish to search */
    protected $excludeFolderNames = '/^CVS|\..*$/'; // CVS directories and directories starting with a dot (.).
    /* @var string regexp for class names to not even bother looking for - e.g. Zend_ */
    protected $ignoreClassNamesRegexp = '/Zend_/';

   /* explicitly here so you are aware that it doesn't have to be a singleton */
    public function __construct() {
    }

    /**
      * do not consider a file name matching this regexp; e.g. anything with Zend_ - don't bother
      * trying, as we'll always have a 'miss', as we'll use Zend_Loader for them.
      * @param string $regexp
      */
    public function ignoreClassesMatching($regexp) {
        $this-&gt;ignoreClassNamesRegexp = $regexp;
    }

    /**
     * Well, if you want, you can use it as a singleton....
     * @return Autoloader $singleton instance
     */
    public static function getInstance() {
        if(self::$instance == null) {
            self::$instance = new Autoloader();
        }
        return self::$instance;
    }

    /**
      * You might need this if running the same code base twice on the same server but
      * under different directories - e.g. dev and live. In which case, specify a local per project key.
      */
    public function setCacheKey($string) {
        $this-&gt;cacheKey = $string;
    }

    /**
     * Sets the paths to search in when looking for a class.
     *
     * @param array $paths
     * @return void
     **/
    public  function setClassPaths($paths) {
        $this-&gt;classPaths = $paths;
    }

    /**
     * Adds a path to search in when looking for a class.
     *
     * @param string $path
     * @return void
     **/
    public  function addClassPath($path) {
        if(!is_array($path)) {
            $path = array($path);
        }
        foreach($path as $item) {
            $this-&gt;classPaths[] = $item;
        }
    }

    /**
     * Set the Zend_Cache instance to use.
     *
     *     <code>
     *     Autoloader-&gt;setCache($cache);
     *     </code>
     *
     * @param Zend_Cache_Frontend $cache
     * @return void
     **/
    public function setCache($cache) {
        $this-&gt;cacheBackend = $cache;
    }

    /**
     * Return caching backend used; or create new one if none already defined
     * (Zend_Cache_Frontend_Core with APC backend).
     */
    public function getCache() {
        if($this-&gt;cacheBackend == null) {
            $this-&gt;cacheBackend = Zend_Cache::factory('Core', 'Apc', array('automatic_serialization' =&gt; true));
        }
        return $this-&gt;cacheBackend;
    }

    /**
     * Sets the suffix to append to a class name in order to get a file name
     * to look for
     *
     * @param string $suffix - $className . $suffix = filename.
     * @return void
     **/
    public static function setClassFileSuffix($suffix) {
        $this-&gt;classFileSuffix = $suffix;
    }

    /**
     * When searching the {@link $classPaths} recursively for a matching class
     * file, folder names matching $regex will not be searched.
     *
     * Example:
     *     <code>
     *     Autoloader::excludeFolderNamesMatchingRegex('/^CVS|\..*$/');
     *     </code>
     * @param string $regex - regexp to exclude files/dirs from being selected for possible candidates.
     **/
    public function excludeFolderNamesMatchingRegex($regex) {
        $this-&gt;excludeFolderNames = $regex;
    }

    /**
     * Given a map of class names to absolute file paths, try and load the class.
     * If we get to including the file, we ensure that the class_exists after doing
     * so, otherwise we'll return false.
     * Also return false if we don't know where the class ($name) could be.
     * @param string $name the name of the class we wish to load.
     * @param array $list - map of known classnames to absolute file paths.
     */
    protected function tryAndLoadClass($name, $list) {
        if(in_array($name, array_keys($list))) {
            include_once $list[$name];
            if(class_exists($name) || interface_exists($name)) {
                //echo "Successfully loaded $name\n";
                return true;
            }
        }
        return false;
    }

    /**
     * Returns true if the class file was found and included, false if not.
     *
     * @return boolean
     **/
    public function loadClass($className) {
        $cache = $this-&gt;getCache();
        $entries = $cache-&gt;load($this-&gt;cacheKey);
        if($entries == false) {
            $entries = array();
        }
        $status = $this-&gt;tryAndLoadClass($className, $entries);
        if($status) {
            // class loaded
            return true;
        }
        if(preg_match($this-&gt;ignoreClassNamesRegexp, $className)) {
            return false;
        }

        foreach($this-&gt;classPaths as $path) {
            // Scan for file
            $realPath = $this-&gt;searchForClassFile($className, $path);
            if($realPath !== false) {
                $entries[$className] = $realPath;
                break;
            }
        }
        $cache-&gt;save($entries, $this-&gt;cacheKey);
        $status = $this-&gt;tryAndLoadClass($className, $entries);
        return $status;
    }

    /**
     * Rummage recursively through all directories found within $directory for a
     * file matching ClassName.$suffix
     * @return string class name if one found; otherwise false.
     */
    protected function searchForClassFile($className, $directory) {
        if(is_dir($directory) &amp;&amp; is_readable($directory)) {
            $d = dir($directory);
            while($f = $d-&gt;read()) {
                $subPath = realpath($directory . DIRECTORY_SEPARATOR . $f);
                //echo "Looking in $subPath for $className{$this-&gt;classFileSuffix}
\n";
                if(is_dir($subPath)) {
                    // Found a subdirectory
                    if(!preg_match($this-&gt;excludeFolderNames, $f)) {
                        if($filePath = $this-&gt;searchForClassFile($className, $subPath . '/')) {
                            return $filePath;
                        }
                    }
                }
                else { // it's a file... so does the name match ?
                    if($f == $className . $this-&gt;classFileSuffix) {
                        return $subPath;
                    }
                }
            }
        }
        return false;
    }

    /**
     * Register this class with SPL as an autoloader.
     * @return void
     */
    public function register() {
        spl_autoload_register(array('Autoloader', 'loadClass'));
    }
}</pre>
<p>There are a few ways it could be improved &#8211; e.g.</p>
<ul>
<li>The ability to pass in a callback or similar which calculates the class name (E.g. appending &#8216;.class.php&#8217; or strtolower&#8217;ing it or whatever);</li>
<li>The cache key stuff could just be worked out by md5(dirname(__FILE__)) or something&#8230; but nevermind.</li>
<li>I&#8217;m not totally sure I like how it recursively trawls the filesystem &#8211; this makes it quite expensive to use if the class you are looking for doesn&#8217;t exist in the specified hierarchy.</li>
<li>Finally, it has the obvious problem that Apache needs to be restarted if you change your file/directory structure.</li>
</ul>
<p>From a performance point of view, one arbitrary page went from taking 180ms to load, to 65ms. That&#8217;s a good decrease from my point of view, and does almost seem noticeable.</p>
<p>The only problem is that I&#8217;ve seen a few APC Cache slam defence error messages, so I&#8217;m not sure if I&#8217;ll stick with APC or move to use something else (at least, I can easily inject a different cache into the class, thanks to Zend_Cache), but life is easier if the &#8216;default&#8217; option works most of the time.</p>
<p>So, perhaps I&#8217;ll fix it to not do the recursive thing, and perhaps make the class name lookup part pluggable. Perhaps.</p>
]]></content:encoded>
			<wfw:commentRss>http://codepoets.co.uk/2011/a-caching-php-autoloader/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>PHP Serialization &amp; igbinary</title>
		<link>http://codepoets.co.uk/2011/php-serialization-igbinary/</link>
		<comments>http://codepoets.co.uk/2011/php-serialization-igbinary/#comments</comments>
		<pubDate>Thu, 03 Feb 2011 15:05:04 +0000</pubDate>
		<dc:creator>David Goodwin</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[igbinary]]></category>
		<category><![CDATA[phpbarcelona]]></category>

		<guid isPermaLink="false">http://codepoets.co.uk/?p=282</guid>
		<description><![CDATA[Recently I&#8217;ve been trying to cache more and more stuff &#8211; mostly to speed things up. All was well, while I was storing relatively small numbers of data &#8211; because (as you&#8217;ll see below) my approach was a little flawed. Random background &#8211; I use Zend_Cache, in a sort of wrapped up local &#8216;Cache&#8217; object, &#8230; <a class="read-excerpt" href="http://codepoets.co.uk/2011/php-serialization-igbinary/">Continue reading <span class="meta-nav">&#187;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Recently I&#8217;ve been trying to cache more and more stuff &#8211; mostly to speed things up. All was well, while I was storing relatively small numbers of data &#8211; because (as you&#8217;ll see below) my approach was a little flawed.</p>
<p>Random background &#8211; I use Zend_Cache, in a sort of wrapped up local &#8216;Cache&#8217; object, because I&#8217;m lazy. This uses Zend_Cache_Backend_File for storage of data, and makes sure e.g. different sites (dev/demo/live) have their own unique storage location &#8211; and also that nothing goes wrong if e.g. a maintenance script is run by a different user account.</p>
<p>My naive approach was to do e.g.</p>
<pre class="brush:php">
$cached_data = $cache-&gt;load('lots_of_stuff');
if(!empty($cached_data)) {
   if(isset($cached_data[$key])) {
       return $value;
   }
}
else {
    // calculate $value
    $cached_data[$key] = $value;
    $cache-&gt;save($cached_data, $cache_key);
}
return $value;
</pre>
<p>The big problem with this is that the $cached_data array tends to grow quite large; and PHP spends too long unserializing/serializing. The easy solution for that is to use more than one cache key. Problem mostly solved.</p>
<p>However, if the site is performing a few thousand calculations, speed of [de]serialisation is still gong to be an issue &#8211; even if the data involved is in small packets. I&#8217;d already profiled the code with <a href='http://xdebug.org'>xdebug</a>/kcachegrind and could see PHP was spending a significant amount of time performing serialisation &#8211; and then remembered a presentation I&#8217;d seen (<a href="http://ilia.ws/files/zendcon_2010_hidden_features.pdf">http://ilia.ws/files/zendcon_2010_hidden_features.pdf</a> &#8211; see slides 14/15/16 I think) at <a title="php barcelona conference 2010" href="http://phpconference.es/">PHPBarcelona</a> covering Igbinary (<a href="https://github.com/phadej/igbinary">https://github.com/phadej/igbinary</a>)</p>
<p>Once you install the extension -</p>
<pre classs="brush:bash">
phpize
./configure
make
cp igbinary.so /usr/lib/somewhere
#add .ini file to /etc/php5/conf.d/
</pre>
<p>You&#8217;ll have access to igbinary_serialize() and igbinary_unserialize() (I think &#8216;make install&#8217; failed for me, hence the manual cp etc).</p>
<p>I did a random performance test based on this and it seems to be somewhat quicker than other options (json_encode/serialize) &#8211; this was using PHP 5.3.5 on a 64bit platform. Each approach used the same data structure (a somewhat nested array); the important things to realise are that igbinary is quickest and uses less disk space.</p>
<p>JSON (json_encode/json_decode):</p>
<ul>
<li>JSON encoded in 2.18 seconds</li>
<li>JSON decoded in 9.83 seconds</li>
<li>serialized &#8220;String&#8221; size : 13993</li>
</ul>
<p>Native PHP :</p>
<ul>
<li>PHP serialized in 2.91 seconds</li>
<li>PHP unserialized in 6.43 seconds</li>
<li>serialized &#8220;String&#8221; size : 20769</li>
</ul>
<p>Igbinary :</p>
<ul>
<li><em>WIN</em> igbinary serialized in 1.60 seconds</li>
<li><em>WIN</em> igbinrary unserialized in 4.77 seconds</li>
<li><em>WIN</em> serialized &#8220;String&#8221; Size : 4467</li>
</ul>
<p>The performance testing bit is related to this <a href="http://stackoverflow.com/questions/804045/preferred-method-to-store-php-arrays-json-encode-vs-serialize/4820537#4820537">Stackoverflow comment I made on what seemed a related post</a></p>
]]></content:encoded>
			<wfw:commentRss>http://codepoets.co.uk/2011/php-serialization-igbinary/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Late to the performance party</title>
		<link>http://codepoets.co.uk/2010/late-to-the-performance-party/</link>
		<comments>http://codepoets.co.uk/2010/late-to-the-performance-party/#comments</comments>
		<pubDate>Fri, 10 Sep 2010 22:36:59 +0000</pubDate>
		<dc:creator>David Goodwin</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[wtf]]></category>

		<guid isPermaLink="false">http://codepoets.co.uk/?p=228</guid>
		<description><![CDATA[Everyone else probably already knows this, but $project is/was doing two queries on the MySQL database every time the end user typed in something to search on to get the data between a set range (SELECT x,y&#8230;.. LIMIT n, OFFSET m or whatever) and another to get the total count of records (SELECT count(field) &#8230;.). &#8230; <a class="read-excerpt" href="http://codepoets.co.uk/2010/late-to-the-performance-party/">Continue reading <span class="meta-nav">&#187;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Everyone else probably already knows this, but $project is/was doing two queries on the MySQL database every time the end user typed in something to search on</p>
<ol>
<li> to get the data between a set range (SELECT x,y&#8230;.. LIMIT n, OFFSET m or whatever) and</li>
<li>another to get the total count of records (SELECT count(field) &#8230;.).</li>
</ol>
<p>This is all very good, until there is sufficiently different logic in each query that when I deliberately set the offset in query #1 to 0 and limit very high and find that the of rows returned by both doesn&#8217;t match (this leads to broken paging for example)</p>
<p>Then I thought &#8211; surely everyone else doesn&#8217;t do a count query and then repeat it for the range of data they want back &#8211; there must be a better way&#8230; mustn&#8217;t there?</p>
<p>At which point I found:<br />
<a title="MySQL performance tips" href="http://forge.mysql.com/wiki/Top10SQLPerformanceTips "> http://forge.mysql.com/wiki/Top10SQLPerformanceTips<br />
</a> and<br />
<a title="MySQL found_rows()" href="http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_found-rows"> http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_found-rows</a></p>
<p>See also the comment at the bottom of <a href="http://php.net/manual/en/pdostatement.rowcount.php">http://php.net/manual/en/pdostatement.rowcount.php</a> which gives a good enough example (Search for SQL_CALC_FOUND_ROWS)</p>
<p>A few modifications later, run unit tests&#8230; they all pass&#8230;. all good.</p>
<p>I also found some interesting code like :</p>
<p>$total = sizeof($blah);<br />
if($total == 0) { &#8230; }<br />
elseif ($total != 0) { &#8230;. }<br />
elseif ($something) { // WTF? }<br />
else { // WTF? }</p>
<p>(The WTF comment were added by me&#8230; and I did check that I wasn&#8217;t just stupidly tired and not understanding what was going on).</p>
<p>The joys of software maintenance.</p>
]]></content:encoded>
			<wfw:commentRss>http://codepoets.co.uk/2010/late-to-the-performance-party/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Still looking for a PHP contractor&#8230;.</title>
		<link>http://codepoets.co.uk/2010/still-looking-for-a-php-contractor/</link>
		<comments>http://codepoets.co.uk/2010/still-looking-for-a-php-contractor/#comments</comments>
		<pubDate>Thu, 04 Feb 2010 20:40:07 +0000</pubDate>
		<dc:creator>David Goodwin</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[contractor]]></category>
		<category><![CDATA[interview]]></category>

		<guid isPermaLink="false">http://codepoets.co.uk/?p=112</guid>
		<description><![CDATA[At work I&#8217;m still looking for a short term PHP contractor. Perhaps I&#8217;m being unrealistic in my expectations/requirements (rate/location/duration/skills etc), but nevertheless&#8230;. As I&#8217;ve not found anyone via normal channels (twitter/phpwm user group etc) I thought I&#8217;d turn to a random recruitment agency (who I&#8217;d spoken to a week or so ago). Yesterday I interviewed &#8230; <a class="read-excerpt" href="http://codepoets.co.uk/2010/still-looking-for-a-php-contractor/">Continue reading <span class="meta-nav">&#187;</span></a>]]></description>
			<content:encoded><![CDATA[<p>At <a title="Pale Purple PHP development" href="http://www.palepurple.co.uk">work</a> I&#8217;m still looking for a short term PHP contractor. Perhaps I&#8217;m being unrealistic in my expectations/requirements (rate/location/duration/skills etc), but nevertheless&#8230;. As I&#8217;ve not found anyone via normal channels (twitter/<a title="PHP user group" href="http://phpwm.org">phpwm</a> user group etc) I thought I&#8217;d turn to a random recruitment agency (who I&#8217;d spoken to a week or so ago).</p>
<p>Yesterday I interviewed one guy &#8211; who&#8217;d been a programmer for a number of years (10+) &#8211; using Visual Foxpro (whatever that is) &#8211; presumably it&#8217;s a dead language, as he wants to move across into <a title="PHP" href="http://php.net">PHP</a>. He has very basic PHP experience (yet claims 2 years on his CV), figured out how to do FizzBuzz and Recursion without too much help &#8211; but didn&#8217;t know anything about object orientation, separation of concerns (specifically <a title="Model View Controller - Wikipedia" href="http://en.wikipedia.org/wiki/Model–view–controller">MVC</a>), security (obvious SQL injection) or unit testing and failed to make any comment on what is almost the worst code I could find to present to him. This isn&#8217;t necessarily a problem &#8211; I would normally be happy to train someone &#8211; however, not when I&#8217;m paying him £25/hour and I&#8217;d be lucky if he was productive within a week. (Hint: students are better than this when they&#8217;ve only been in <a title="Computer Science - Aberystwyth" href="http://www.aber.ac.uk/compsci">University</a> for two years).</p>
<p>Today, I therefore continued hunting, with mixed success. I had three more CVs &#8211; all asking for more money, and one looked quite good &#8211; but had a requirement he worked remotely after the first few days (well he does live in Telford). Another, who is local, I&#8217;m interviewing tomorrow. Wanting to do some homework on him, I had a look at a couple of websites mentioned in his doctored CV  - the first is clearly .Net from the error message it throws when you pass a &gt; into it&#8217;s search box &#8211; so either they replaced his PHP site quickly or his CV is misleading. The <a title="ladyflamingo" href="http://www.ladyflamingo.info/ladytalk/">second has a PHP error</a> on it &#8211; and is only (effectively) a themed <a title="wordpress" href="http://wordpress.org">wordpress</a> site which looks like it&#8217;s slowly rotting. From these I found out his address (hint: whois $flamingodomain) and an invalid email address/domain (which archive.org seems to not do much with). Typing in his name into Google / LinkedIn, Facebook etc produces no obvious matches. So I know hardly anything about him, and for all intent he may as well not exist. Great sales job there.</p>
<p>From talking to the recruiters it seems it&#8217;s difficult to find decent PHP programmers &#8211; and anyone who may be decent will almost certainly not be programming PHP as their primary language (i.e. they&#8217;ll be doing web development in Java/.Net, and know PHP quite well). This seems a shame, but really only confirms what I already knew from interacting with others in the community. I&#8217;ve known for ages that I&#8217;ve effectively taken a large pay cut by running my own company, and doing PHP. It sucks that this continues to be the case. Clearly I&#8217;m a martyr or something.</p>
<p>So, if you happen to be a contractor looking for work, please make an effort. I&#8217;m not overly impressed so far, and may just end up stalling customers for another week/month instead.</p>
<p>(Oddly I wrote this post, posted it, and it vanished. What are you up to wordpress? Why do you want me to retype things in twice?)</p>
]]></content:encoded>
			<wfw:commentRss>http://codepoets.co.uk/2010/still-looking-for-a-php-contractor/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
		<item>
		<title>Random PHP project progress</title>
		<link>http://codepoets.co.uk/2010/random-php-project-progress/</link>
		<comments>http://codepoets.co.uk/2010/random-php-project-progress/#comments</comments>
		<pubDate>Wed, 27 Jan 2010 22:03:40 +0000</pubDate>
		<dc:creator>David Goodwin</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[mvc]]></category>
		<category><![CDATA[pdo]]></category>
		<category><![CDATA[propel]]></category>
		<category><![CDATA[simpletest]]></category>
		<category><![CDATA[smarty]]></category>
		<category><![CDATA[tdd]]></category>
		<category><![CDATA[unit testing]]></category>
		<category><![CDATA[zend framework]]></category>

		<guid isPermaLink="false">http://codepoets.co.uk/?p=99</guid>
		<description><![CDATA[Random php development musing <a class="read-excerpt" href="http://codepoets.co.uk/2010/random-php-project-progress/">Continue reading <span class="meta-nav">&#187;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Initially when we founded <a title="Pale Purple PHP web development" href="http://www.palepurple.co.uk">Pale Purple</a> all our new <a title="PHP" href="http://php.net">PHP</a> development used a combination of <a title="Propel" href="http://propel.phpdb.org">Propel</a>, <a title="Smarty" href="http://smarty.net">Smarty</a> and some inhouse glue. Over time we seem to have drifted towards the <a title="Zend Framework" href="http://framework.zend.com">Zend Framework</a>, but I&#8217;ve never been particularly happy with Zend_Db or Zend_View. Why the Zend Framework? Well, it has loads of useful components (Cache, Form, Routing, Mail etc) and it&#8217;s near enough an industry standard from what we see &#8211; and obviously I&#8217;d rather build on the shoulders of others than spend time developing an in-house framework no one else will ever use.</p>
<p>For one customer, we&#8217;re currently working on the next iteration of their code base &#8211; which incorporates a number of significant changes. When we inherited the code base from the previous developers we spent a long time patching various SQL Injection holes (casting to ints), moving over to use PDO&#8217;s prepared statements and trying to keep on top of the customer&#8217;s new functionality requests and support issues. There&#8217;s still a lot of horrible code to refactor, plenty of security holes (although none public facing) and we know we&#8217;re moving in the right direction &#8211; hopefully patching and duct tape will soon be a thing of the past as it will develop some form of architecture and look like someone has thought about design and long term maintenance.</p>
<p>I&#8217;ve started to properly do Test First Development &#8211; at least from a support perspective &#8211; as too often we&#8217;d find we would patch a bug, only for it to reappear again in a few weeks/months time. This has been especially useful with the SOAP interface the application exposes. The tests run every 5 minutes, and we all get emailed when stuff breaks &#8211; it took all of 30 minutes to setup and put in place &#8211; then it was just a case of actually writing the unit tests themselves (the tests take minutes to write; finding/fixing any bugs they pin point takes somewhat longer :-/ ). I&#8217;ve also abused Simpletest&#8217;s web testing &#8216;stuff&#8217; to also act as an availability checker of the live site (i.e. hit a few remote URLs, and check that we don&#8217;t get error messages back and do see expected strings).</p>
<p>The original code base had no &#8216;model&#8217; like layer (or MVC &#8216;compliance&#8217;) &#8211; files containing HTML, CSS, SQL, Javascript and PHP were the norm &#8211; we&#8217;ve added Propel to the project as the &#8216;model&#8217; layer &#8211; which took a few hours; and then when reverse engineering the database we found a few oddities (tables without primary keys and so on) &#8211; anyway, moving the functionality from a handful of legacy objects across into the Propel ones seems to be well underway, and I for one will be glad to see the end of :</p>
<pre>$x = new Foo(5);</pre>
<p>Accompanied with code that does the equivalent of :</p>
<pre>class Foo {</pre>
<pre>    public function __construct($id = false) {</pre>
<pre>        if($id != false) {</pre>
<pre>            // select * from foo where id = 5</pre>
<pre>            // populate $this; don't bother checking for the edge case where $id isn't valid</pre>
<pre>       }</pre>
<pre>       else {</pre>
<pre>           // insert into foo values ('');</pre>
<pre>          // populate $this-&gt;id; leaving all other fields as empty strings...</pre>
<pre>     }</pre>
<pre>     public function setBaz($nv) { // repeat for all table fields</pre>
<pre>         $this-&gt;baz = $nv;</pre>
<pre>         global $db;</pre>
<pre>         $db-&gt;query('update foo set baz = "' . $nv . '" where id = ' . $this-&gt;id);</pre>
<pre>     }</pre>
<pre>}</pre>
<pre></pre>
<p>Finally, we have a meaningful directory structure &#8211; where some things aren&#8217;t exposed in the document root. Hopefully soon a front controller and some decent routing. At the moment a huge amount of code is just sat in the &#8216;public&#8217; directory due to it&#8217;s nature. We hope to fix this in time, and move to using Zend Controller &#8211; once we get Smarty integrated with it.</p>
<p>Propel has added some nice new features since we last used it (effectively v1.2); it was a toss up between it and Doctrine (as obviously the ZF is moving in that direction) &#8211; but we already had knowledge/experience with Propel and it seemed the easier option.</p>
<p>I&#8217;m hoping that with time we&#8217;ll be able to get up to at least 60% test coverage of the code base &#8211; at that point we should be able to refactor the code far easier and with less fear. At the moment I doubt the unit tests cover more than 5-10% &#8211; although maybe it&#8217;s time I pointed xdebug or whatever at it to generate some meaningful stats.</p>
<p>My final task is to get some decent performance measurements out of the code base &#8211; so we can track any performance regressions. I&#8217;m fairly confident that moving to Propel will result in an speedup as duplicate object hydrations will be eliminated thanks to it&#8217;s instance pool, however having hard figures and nice graphs to point at would be ideal. So far I&#8217;ve knocked up my own script around &#8216;ab&#8217; which stores some figures to a .csv file and uses ezComponents to generate a graph file. This seems to be a crap solution, but I can&#8217;t think or find anything better. Any suggestions dear Internet? Perhaps I should integrate changeset/revision id&#8217;s in my benchmarking too. Suggestions here would be exceedingly appreciated.</p>
<p>There, I should have ticked all necessary boxes wrt development practices now. Now to work on finding a contract PHP developer&#8230;.</p>
]]></content:encoded>
			<wfw:commentRss>http://codepoets.co.uk/2010/random-php-project-progress/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>PHP array and object addition and string indexing</title>
		<link>http://codepoets.co.uk/2009/php-arrays-objects-addition-and-string-indexing/</link>
		<comments>http://codepoets.co.uk/2009/php-arrays-objects-addition-and-string-indexing/#comments</comments>
		<pubDate>Tue, 27 Oct 2009 09:08:21 +0000</pubDate>
		<dc:creator>David Goodwin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://codepoets.co.uk/?p=49</guid>
		<description><![CDATA[While reading someone&#8217;s code, I came across the following sort of thing: function foo($config = array()) { $this-&#62;_config += $config; //... } To which I thought WTF? How does PHP cast an array to a number to perform addition? A few random tests later, it appears PHP joins the two arrays together, only adding indexes &#8230; <a class="read-excerpt" href="http://codepoets.co.uk/2009/php-arrays-objects-addition-and-string-indexing/">Continue reading <span class="meta-nav">&#187;</span></a>]]></description>
			<content:encoded><![CDATA[<p>While reading someone&#8217;s code, I came across the following sort of thing:</p>
<p><code><br />
function foo($config = array()) {</code></p>
<p><code> $this-&gt;_config += $config;<br />
//...<br />
}<br />
</code></p>
<p>To which I thought WTF? How does PHP cast an array to a number to perform addition?</p>
<p>A few random tests later, it appears PHP joins the two arrays together, only adding indexes that appear in the second (and not first) array.</p>
<p>(as per <a href="http://php.net/manual/en/language.operators.array.php">php manual &#8211; array operators</a>)</p>
<p>Namely :</p>
<p>$array_1 = array(&#8216;a&#8217;,'b&#8217;, 4=&gt;&#8217;c');<br />
$array_2 = array(4=&gt;&#8217;e', &#8216;f&#8217;, &#8216;g&#8217;);</p>
<p>$array_1 += $array_2;</p>
<p>print_r($array_1);</p>
<p>will give :<br />
Array<br />
(<br />
[0] =&gt; a<br />
[1] =&gt; b<br />
[4] =&gt; c<br />
[5] =&gt; f<br />
[6] =&gt; g<br />
)</p>
<p>(Note; 4=&gt;e is not in the resultant array, because 4=&gt;c was in array_1).</p>
<p>After a round about conversation with Moobert on this on IRC &#8211; at which point he probably put me out of my misery, he also gave me the following :</p>
<p>$x = &#8216;test&#8217;;<br />
echo $x['whatever']; // outputs &#8216;t&#8217;</p>
<p>Which I can understand &#8211; as PHP allows for per-character access to a string (based on position) &#8211; hence &#8216;something&#8217; gets casted to zero, and we get the first character back.</p>
<p>I know I can cast objects to arrays, and vice versa.</p>
<p>Seemingly Objects don&#8217;t follow any sort of &#8216;union&#8217; rule however&#8230; as adding two objects results in &#8217;2&#8242;. Not sure how PHP converts an object into &#8217;1&#8242;&#8230; but there we are. I sort of expected to get an object back (assuming the inputs were the same type) with a union of properties, but no.</p>
]]></content:encoded>
			<wfw:commentRss>http://codepoets.co.uk/2009/php-arrays-objects-addition-and-string-indexing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

