Improving Ajax performance in Zend Framework applications

Tags:

A common reason to use Ajax in a website is to make it feel faster, so you usually want Ajax requests be processed as quickly as possible.

While there are many ways to speed up Zend Framework based applications, there are still some things like routing and dispatching which still add up to the total.

There is, however, another way to make Ajax work even faster

A french translation of this post by Antoine Delaisse is available at “Le blog du Zend Framework”

Create a separate Ajax handler

Most of the time Ajax code does not need routing, dispatching, plugins and all the usual stuff that runs in a Zend Framework based application.

To get rid of these mostly useless processes, we can create a separate Ajax handler script.

The idea is that instead of calling the main application, we have a separate lean script which is greatly simplified and handles just some selected cases. For example, if we have an Ajax-based search, it will work just fine without a plugin which checks if the user has access to the current page.

It may seem that this will lead to code duplication – indeed it will if your application is poorly designed. For this to be easy to implement, the code needs to be properly separated into reusable classes.

An example on code separation

Let’s take a look at an example, continuing with the idea of having an ajax based search feature. Let’s say we only have a non-ajax based search, and we want to modify our code to have a blazingly fast Ajax-based version of it.

You might have something like this in your code

//Note that this is a simplified example
class SomeController extends Zend_Controller_Action {
  public function searchAction() {
    $db = new Database();
 
    //LIKE may be slow, but this is just an example so it'll do
    $sql = 'SELECT * FROM items WHERE name LIKE ?';
    $results = $db->fetchAll($sql, '%' . $_GET['search'] . '%');
 
    $this->view->results = $results;
  }
}

Now if we wanted to also have a separate script for the search feature, we would have to copy-paste the above code. Instead, we should move the searching code into its own class:

class ItemSearch {
  private $_db = null;
  public function __construct($db) {
    $this->_db = $db;
  }
 
  public function getResults($search) {
    $sql = 'SELECT * FROM items WHERE name LIKE ?';
    $results = $this->_db->fetchAll($sql, '%' . $search . '%');
    return $results;
  }
}

Now, in the actual controller we call this class instead:

public function searchAction() {
  $search = new ItemSearch(new Database());
  $this->view->results = $search->getResults($_GET['search']);
}

An example handler script

Now that we have the searching “business logic” separated into its own class, we can create the search script without having to resort to cooking copy-pasta.

require_once 'bootstrap.php';
 
$results = array();
if(isset($_GET['search'])) {
  $search = new ItemSearch(new Database());
  $results = $search->getResults($_GET['search']);
}
 
//Let's assume the ajax request expects the results in JSON
echo json_encode($results);

In this case the bootstrap.php file would contain common initialization logic: Setting up the database connection, registering an autoloader, and other tasks needed for the ItemSearch to function properly. It would not include setting up the front controller, as that is not needed in the separate handler.

You may wonder why aren’t we just using the controller, which does pretty much the same.

If you think about it, what do you need to get a ZF controller, and the result from it? A lot of other things, like Zend_View, an action helper broker, etc.

For getting a complete list of the various classes you would need for a controller, you could use the packageizer. Just check “Zend_Controller_Action” from “Zend_Controller”.

Summing up

As you can see, the ajax handler script can be extremely simple. This way it avoids all the overhead of the usual Zend Framework related things like routing and dispatching, and can make your sites Ajax requests work very quickly!

This approach can also be used with most other frameworks. You should usually get some more performance out of it.