Zend Framework benchmark

A bit late, but Paul M. Jones did a nice benchmark on PHP frameworks in September.

While Paul seems to have put quite some time in it, some people will probably argue about the results (like with all benchmarks). Anyway, I’m of course mostly interested in the PHP – Zend Framework comparison which shows that his Zend Framework script runs > 90%  slower than a plain PHP script. In return you get of course RAD: faster results and tighter development budgets. In my, again, humble opinion it’s more than worth it!

They have lost speed between 1.0 and 1.6 but of course so many features were added. Hopefully it can be improved a bit in future versions.

Until now I have not worked on a high traffic project in ZF so I hope my opinion won’t change then. I did hear the guys working on tv.be had some issues once traffic started coming in…

It’s a shame I missed Shahar Evron’s presentation about Scaling PHP Applications with Zend Platform on this subject. Hopefully he’ll give this talk in Europe some day.

Zend_Pagination adapter for Propel

Like recently proposed by Jason Eisenmenger, I’ve written a Zend_Pagination adapter for Propel.

It uses the DbFinder symfony plugin (formerly sfPropelFinder) which mimics Doctrine’s way of performing queries. The strictlyPHP_Propel_Finder used below is just a wrapper around that plugin.

Please note: it can certainly be improved (and I’m not sure the Zend Framework coding standards are met).

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
class strictlyPHP_Paginator_Adapter_Propel implements
Zend_Paginator_Adapter_Interface
{
    /**
     * @var strictlyPHP_Propel_Finder
     */
    protected $_finder;
    /**
     * @var Criteria
     */
    protected $_criteria;
    /**
     * @var int
     */
    protected $_count;
    /**
     * Constructor
     * @param strictlyPHP_Propel_Finder $finder
     */
    public function __construct($finder)
    {
        $this->_finder = $finder;
        $this->_criteria = $finder->getCriteria();
    }
    /**
     * Get count
     * @return int
     */
    public function count()
    {
         if ($this->_count === null) {
             $this->_finder->setCriteria($this->_criteria);
            $this->_count = $this->_finder->count();
         }
        return $this->_count;
    }
    /**
     * Get items
     * @param int $pageNumber
     * @param int $itemCountPerPage
     * @return array
     */
    public function getItems($pageNumber, $itemCountPerPage)
    {
        $criteria = clone $this->_criteria;
        $criteria->setOffset($pageNumber);
        $criteria->setLimit($itemCountPerPage);
        return $this->_finder->setCriteria($criteria)->find();
    }
}

Zend_Log wrapper for Propel

Although Doctrine has its advantages, I still like Propel. It does its job and it does it fairly well.
If you integrate Propel with Zend Framework, you basically only need a Zend_Log wrapper that implements the BasicLogger interface Propel requires. This lets you use Zend_Log as the only log class in your application instead of creating one especially for Propel.

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/**
 * Wrapper for Zend_Log for use as Propel log
 * @author Sam Hauglustaine
 */
class strictlyPHP_Propel_Log extends Zend_Log implements BasicLogger
{
    /**
     * Log
     * @var Zend_Log
     */
    private $_log;
    /**
     * Constructor
     * @param Zend_Log $log
     */
    public function __construct(Zend_Log $log) {
        $this->_log = $log;
    }
    /**
     * Log message of specified severity
     * @param string $message
     * @param int $severity
     */
    public function log($message, $severity = null) {
        $this->_log->log($message, $severity);
    }
    public function emergency($message) {
        $this->log($message, Zend_Log::EMERG);
    }
    public function alert($message) {
        $this->log($message, Zend_Log::ALERT);
    }
    public function crit($message) {
        $this->log($message, Zend_Log::CRIT);
    }
    public function err($message) {
        $this->log($message, Zend_Log::ERR);
    }
    public function warning($message) {
        $this->log($message, Zend_Log::WARN);
    }
    public function notice($message) {
        $this->log($message, Zend_Log::NOTICE);
    }
    public function info($message) {
        $this->log($message, Zend_Log::INFO);
    }
    public function debug($message) {
        $this->log($message, Zend_Log::DEBUG);
    }
}

(the Zend_Log priority constants nicely match their Propel equivalents.)
You then need to extend the main Propel class to do the wrapping:

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
 * Wrapper for Propel
 * @author Sam Hauglustaine
 */
class strictlyPHP_Propel extends Propel
{
    /**
     * Set Propel log (required)
     * @param mixed $log
     * @return void
     */
    public static function setLog($log)
    {
        if($log instanceof Zend_Log)
            $log = new strictlyPHP_Propel_Log($log);
        parent::setLogger($log);
    }
}

That’s all. You can then call your Propel wrapper’s static methods in your bootstrap or a front controller plugin (I implemented that last option for a brand new project, a directory for stallion owners):

PHP
1
2
strictlyPHP_Propel::setLog($myLog);
strictlyPHP_Propel::init($myConfig);

Of course the bigger part is using the Propel class generator itself but that’s something for another post.

Famous bikinis

Last month I developed an online bikini store for a design company based on Zend Framework and some jQuery widgets. It wasn’t only a fun subject – the site also performs very well. Both on organic search and on conversions.

One thing that I found to be a life saver: use caching for Zend_Currency.

PHP
1
2
3
4
5
$cache = Zend_Cache::factory('Output',
'File',
$configFrontend,
$configBackend);
Zend_Currency::setCache($cache);

Or another caching mechanism of course – this will visibly speed up page loading.
Edit: also do this for Zend_Translate but you could have thought of that yourself.

Besides that the finishing touch is a local touch: Clickini loves your country (if they are shipping to you that is). Thanks to my flexible hosting company (who installed Maxminds PHP GeoIP extension) & the world’s favorite icons, that was easy to accomplish.

That last character is the first

Let’s dive right into it:

About a week ago I put on the JavaScript text-typing mode and developed a CMS with ExtJs and Zend Framework. Thanks to FireBug life is great. At least, until that last final test in that other browser. Ouch.

One thing that solves almost all issues: watch your JavaScript object notation (JSON) values separator. FireFox doesn’t complain about that last comma before the closing } or ] but Internet Explorer isn’t so keen on that.
Well… maybe that is a good thing.

Perhaps an easy way out is validating the stuff you type.