<?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; zend framework</title>
	<atom:link href="http://codepoets.co.uk/tag/zend-framework/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>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>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>
	</channel>
</rss>

