CXO

Optimizing dynamic performance with sessions in PHP

Performance is one of the most critical success factors of any Web site. Users are inherently impatient, and alternatives are plentiful. This article examines the use of session objects to improve performance.


A dynamic Web site can provide both a money-saving solution, where updates and maintenance are concerned, and the ability to create interesting, useful Web environments. So what's the downside? It's in performance.

Regardless of platform or language, any preprocessing of Web content creates a hit on the amount of time it takes to return a page to the user. Often, this lag time isn't noticeable because the user's download speed is the limiting factor. However, when used on a large scale, dynamic content will affect the performance of your site.

In this article, I'll offer some guidelines for content generation, with a focus on using PHP session objects to improve application performance. First, however, here's a real-world example that illustrates just how profound an effect preprocessing dynamic content can have on Web site performance.

Dynamic death
In writing this article, I was reminded of an excruciating experience I once witnessed while working on an e-commerce site as a systems integrator. The servers were robust, and the software was from a major contender in the e-commerce realm.

The designers deployed their content using the software, and in testing, everything was great: The site was beautiful and truly customized the user's experience seamlessly. Once we got to quality assurance, however, we were quite astonished to find that the entire million-dollar-plus solution could support only a maximum of 12 users simultaneously before rejecting visitors and eventually crashing the Web server.

The hardware should have been able to support thousands of simultaneous hits, and the software's limit in a static environment was around 8,000. What caused the bottleneck? Preprocessing time. The home page alone contained more than 20 separate dynamic elements from varying sources—some of them remote. The software had choked.

After extensive diagnostics, the offender proved to be the page generator. It was using a single process to find and retrieve each element in turn, cache it temporarily on the file system, compile the elements, and finally return a page that still had to be preprocessed with user-specific data. Rather than a super-dynamic, ultimate user experience, the final effect was a Web server that continually timed out.

To solve our problem, we took two approaches. First, we worked with the vendor's developers to write a custom patch that specifically matched our page-generation needs. Second, we created a local cache of as much of the dynamic content as possible and updated it periodically instead of in real-time. Finally, a day late and a dollar short, we launched.

The issues we experienced on this project are typical of those encountered when delivering dynamic content. But by following a few guidelines during development of the software, we were able to resolve our performance issues. Let's look at some elements that affect performance, along with best practices for minimizing the hit that results from certain types of processing.

Optimization overview
We all know that the server hardware directly affects its performance. If you install a faster hard drive, you'll be able to read faster from the disk. With software, the functions and constructs that are instantiated will also affect performance due to how those entities were designed to use hardware and supporting software.

A good programmer is mindful of both hardware and server software limitations in general when writing an application, and this is particularly important when working with dynamic content. To reduce the impact of these types of limitations on software you develop, organize your code with the following performance observations in mind:
  • All dynamically generated pages have the same overhead as static pages, in addition to data access performance.
  • Data stored in memory is the most readily available. Accessing memory has the least impact on performance until it is saturated. At that point, the performance will be the same as accessing an indexed file.
  • Accessing indexed files, such as virtual memory or PHP session objects, is conventionally the next quickest way to retrieve data. An indexed file's location is stored in memory, with the file itself existing on the file system (hard drive).
  • Database access is another big factor in the performance of dynamic Web sites. The speed of data access will vary depending on the manufacturer, configuration, and type of query, of course. Obviously, it is faster to read from a database that's already been opened.
  • The least desirable way to get at data is by accessing the file system directly. In order to be read, a file must be located, indexed, opened, read, and closed, and then the index needs to be removed. Usually, the hard drive is the fastest local medium, followed by CD, floppy, and tape.
  • Accessing remote data will vary in performance, based on proximity to your server, data access type, and network availability.

Certainly, every hardware and software configuration will yield varying results, and the order of events and other such considerations may affect specific benchmarking. Additionally, each platform will have other, platform-specific issues that can affect performance, which can be taken into account when writing code for a particular solution. For the most part, however, the guidelines above represent the major sources of lag in an application and should always be considered during development. We can now use those assumptions to derive some rules of thumb to follow when writing code:
  • Static content will always be faster than dynamic content. Ask yourself if the page has a real need to be generated on the fly.
  • Limit file-system activity to logging and one-time configuration loading. Try to consolidate file system operations to one or a few files, or you may bog the system down with repeated, unnecessary drive access. Also, leave a file open until you are through with it, instead of opening and closing a file several times. Writing temp files is expensive and usually unnecessary.
  • Whenever possible, consolidate calls to the database and be aware of searches. You may want to return results to an array and search the array for the subset you need rather than call the database multiple times. If you need to perform multiple database queries in tandem, think about using database stored procedures. If you still must make continuous database calls, use a persistent connection.
  • Use native functions over extensions. For example, explode() is a native PHP function used to split a string. The function split(), on the other hand, is part of a PHP extension and has to load the regular expression engine each time you call it.
  • Localize data whenever possible. Move data sources to your local network, cache when you can, and keep frequently requested variables resident in memory.

If you keep these five rules in mind, your applications' performance will improve.

Benchmarking
To find out how to benchmark your own PHP applications, check out this article from zend.com.

Using PHP sessions
With the desire to improve site performance comes the need to store variables globally without creating debilitating interdependencies within your application. By using session objects in PHP, you can greatly improve the performance of your dynamic site by limiting database calls and improving data accessibility. It's also a great way to manage state information and allow for nonlinear interoperability.

PHP sessions can work in one of two ways. One way is by creating a cookie containing the session ID on the user's system and putting a temporary, indexed file on the server. You can specify the location by setting session.save_path in your Php.ini configuration. This file holds the values for whatever variables you've stored in the session object. This is the default session method and will occur as long as the user has cookies enabled in his or her browser and you have not changed the value of session.use_cookies in Php.ini.

If you want to ensure that the user doesn't need to have cookies enabled, you can use the second approach: Have the session ID preserve values in the URL using GET. When a client doesn't send the appropriate cookie, the constant, SID, is set with session name and ID information. You can then pass this to another page within an href tag in your HTML, like this:
<A HREF="somepage.php?<?=SID?>">Link</A>

Alternatively, you can compile PHP with —enable-trans-sid, and the URL will be automatically be appended to a local link, like this:
<A HREF="somepage.php">Link</A>

The syntax for handling a session object depends on how you have configured sessions in your PHP configuration file, Php.ini. I recommend enabling register_globals so that you can register any global variable to a session. Your session data will then be available through both the global associative array, $HTTP_SESSION_VARS, and the global variable name you assign. Alternatively, with PHP version 4.1.0 or higher, you may reference these values without register_globals enabled by calling $_SESSION. Either way, referencing an assigned global variable name will provide the same outcome.

Aside from that, session object variable handling is the same as for any object you create with PHP (for example, $user_info->username = "Brad"; or $HTTP_SESSION_VARS["user_info"]->username = "Brad";). You can add, update, and delete variables within the session instance at any time. These variables are then globally accessible to any script that registers the session.

That should be all you need to know to begin, but be sure to read the manual page about other Php.ini session configuration parameters, such as session duration. Additionally, some of these parameters can be overridden for the duration of the session using in-line session commands. These are listed on the same manual page as the configuration file parameters. Advanced users who want to play with using a database to hold your session values may want to check out the session_set_save_handler() function manual page.

Session example
To demonstrate how to use session objects in PHP, let's work through a quick example. First, start the session to get a new session ID. Next, use session_register to register a variable into the session. To get us started, I've defined some values:
start_script.php
<?
session_start();
session_register("user_info");
$user_info->home[address]="123 Blah St.";
$user_info->home[phone]="(612) 123-4567";
?>

Then, to retrieve these values in another script, reference the session and call them as global variables:
next_script.php
<?
session_register("user_info");
echo $user_info->home[address];
?>

Here's another example from within a function:
fn_script.php
<?
session_register("user_info");
$go = new blah;
class Blah {
function blah() {
global $user_info;
echo $user_info->home[address];
} }
?>

Summary
Dynamic content offers tremendous benefits, but it comes at a cost: compromised performance. One way to minimize its effect is to use PHP session objects to keep data readily available. You should also be aware of the impact that your code will have on the server and avoid using hardware unnecessarily. As you use more and more dynamic content, the need to pay attention to optimization increases. Your site should be customized for your users, but it shouldn't be a resource hog.

Editor's Picks

Free Newsletters, In your Inbox