How to Make a PHP 5 WordPress Plugin Die Gracefully in PHP 4

I’ve been coding all my plugins in PHP 4 to make them as compatible as possible with the wide variety of hosting environments out there. But I’ve been eager to make use of PHP 5’s features, especially its greatly improved OO features. PHP 4 reached its end-of-life over a year ago (which means no more enhancements, and no more security fixes). My impression is that the great majority of hosting providers have upgraded to PHP 5 since then, and WordPress 3.0 is expected to require PHP 5 for some features, so future versions of my plugins will make use of PHP 5 only features.

If you’re writing a plugin in PHP 5, it’s important to write it in such a way that it fails gracefully if someone tries to run it in a PHP 4 environment. This is because:

  1. There are still people using PHP 4.
  2. While you can – and should – make a prominent note in your readme file and on your website that your plugin requires PHP 5, many people will inevitably overlook it (when reading online, people – including me – generally notice only what they’re looking for, not what you want them to notice).
  3. PHP 5-specific code can cause hard failures when run in PHP 4, making users frustrated, and making you frustrated when they email you with their frustrations.

The best place to check for compatibility is during plugin activation. But WordPress performs plugin activation in a separate process, making it difficult to communicate anything back to the user. Brian Krausz solved this problem, and my solution for safely checking PHP compatibility builds on his work.

If you are only using functions introduced in PHP 5, then you can use Brian’s code and incorporate a function_exists() check for one of them in your activation function. But if you’re using language constructs introduced in PHP 5 – like protected properties or abstract classes – then they can’t be in the same script as the one containing your call to register_activation_hook(). This is because the script will fail to parse in PHP 4, and the user will get a syntax error message (it won’t be at all obvious to the untrained eye that it’s failing because it requires PHP 5).

My solution is a PHP 4-safe “boot” script for my plugins, which loads my class files written in PHP 5 only after it confirms that it’s safe to do so. Here is what I have in the update I’m working on for my Shashin plugin:

register_activation_hook(__FILE__, 'shashin_activate');

if ($_GET['action'] == 'error_scrape') {
    die("Sorry, Shashin requires PHP 5.0 or higher, and mySQL 4.1 or higher. Please deactivate Shashin.");
}

function shashin_activate() {
    global $wpdb;
    $mysql_version = $wpdb->get_var("select version()");

    if (version_compare(phpversion(), "5.0", "<") || version_compare($mysql_version, "4.1", "<")) {
        trigger_error('', E_USER_ERROR);
    }

    else {
        require_once(dirname(__FILE__) . "/Shashin.php");
        $shashin = new Shashin();
        $shashin->install();
    }
}

if (version_compare(phpversion(), "5.0", ">=")) {
    require_once(dirname(__FILE__) . "/Shashin.php");
    $shashin = new Shashin();
}

A few notes:

  • version_compare() can be used to compare version numbers generally, not just PHP versions. Shashin requires mySQL 4.1, so I’m checking for that too.
  • There is an ongoing cost to this approach: every time your plugin is run, it does a version_compare and a require_once. I haven’t benchmarked it, but I’d be surprised if it caused any noticeable performance difference.
  • Savvy programmers generally recommend checking for the existence of the functions you want to use rather than checking language version numbers. I agree when it comes to client-side languages like JavaScript, where it can be difficult to anticipate all the environments your script might encounter. I think it’s less of an issue with server-side languages, and in my case I’m not using a particular PHP 5 function. I’m using PHP 5 language constructs such as abstract classes.

Leave a Reply