PHP4/5: Object orientation and compatibility

Some compatibility problems were reported following the release of SLOODLE 1.0, and they largely appear to centre around the object-oriented plugin system I developed for the Presenter module.

The idea is fairly simple. The SLOODLE core or 3rd party developers can create plugin classes to extend the functionality. These will all belong to a structured inheritance hiearchy, and will be automatically detected and loaded by the SLOODLE framework. However, it has been a big challenge maintaining compatibility for both PHP4 and PHP5, given that the object orientation of the language has changed so much in that time.

After considerable efforts, I think I’ve finally found the solution, and it’s infuriatingly inelegant.

What Needs To Be Done

Unfortunately, there is no sensible way (at least as far as I know) to detect where on disk a particular class was loaded from, without perhaps some rather laborious naming scheme. As such, all the relevant files are included by the framework, and then all the declared classes are scanned to determine which of them are SLOODLE plugins.

The Ideal Solution

Given that all plugin classes are ultimately derived from a single base class (called “SloodlePluginBase”), it would be nice if we could just pass the name of any given class to “is_subclass_of(..)” to determine if it is a SLOODLE plugin. Sadly though, PHP4 requires that it has an instance of an object rather than the name of a class. Instantiating every declared class just to test if it’s a SLOODLE plugin would be inefficient at best, and quite likely unstable.

Other Unworkable Solutions

  1. Use “get_parent_class(..)” to check if the base class is the parent of the given class. Doesn’t work because there are multiple levels of inheritance.
  2. Use a naming convention. Possible, but really confusing to program due to the different way class naming is handled between PHP4 and 5 (and the fact that the existing naming conventions in Moodle and SLOODLE use CamelCase).
  3. Define a unique static member variable (such as “$is_sloodle_plugin”) and check its existence with “isset(..)”. Doesn’t work because PHP4 doesn’t support static member variables.
  4. Define a unique static member method, and check for its existence with “method_exists(..)”. Doesn’t work because PHP4 (on some or all versions) requires an object instance to test, rather than just a class name.
  5. Define a unique static member method, and check for its existence with “is_callable(..)”. Not ideal because it is only compatible with PHP >= 4.0.6.

The Final Solution

You could probably see a theme emerging with ideas 3-5. In the same light, the final solution has been to define a unique static member method in the base class (called “sloodle_get_plugin_id()”). The code then uses this rather inelegant approach to check if it exists on any given class whose name is stored in “$classname”:

$result = @call_user_func(array($classname, 'sloodle_get_plugin_id'));
if (empty($result)) /* Not a plugin class */

Yep, it’s hideous. Executing this code on all declared classes is not exactly elegant or the most efficient thing ever, but it seems to be effective and compatible. Time will tell if it’s in fact portable to other platforms and configurations.

Leave a Reply

Your email address will not be published. Required fields are marked *