<?
/************<?
/********************************************************************************
This is a basic classloader for PHP, designed to give the end user the ability
to use an include_path-like feature without having access to the include_path
variable (i.e., for users who don't have admin access to their PHP setup, or who
don't want to fiddle with it). It uses a Java-like mechanism, substituting
$PHP_CLASSPATH in place of Java's CLASSPATH.
Note that files containing classes loaded via this tool MUST be named like this:
Classname.$CLASSLOADER_CLASS_SUFFIX
$CLASSLOADER_CLASS_SUFFIX defaults to ".class.php" but can be reset before this
file is include()d. If you need a special suffix just for certain files,
you can create your own classloader
$EXT_INCLUDE_FILE_SUFFIX defaults to ".inc.php" but can be reset at any time before
ext_include() is called. .inc.php files are intended to be include files which
do not contain classes and may or may not create output when include()ed.
License: public domain. do as you will, and that shall be the whole of the law.
Author: stephan@wanderinghorse.net http://stephan.rootonfire.org
$Revision: 1.12 $
Sample usages:
// set up the classloading system:
$PHP_CLASSPATH = ".:test"; # defaults to HTTP_ENV_VARS[CLASSPATH] (Java's classpath)
// OPTIONAL: $CLASSLOADER_CLASS_SUFFIX = ".inc.php";
include( "classload.inc.php" );
// load MyClass:
$foo = classload( "test/MyClass" );
if( $foo == 0 ) die( "fuck!" );
$foo->foo();
// try loading the same class using a different name, just to see if we get a dual-include error (we won't)
$foo = classload( "MyClass" );
$foo->foo();
// just to be fancy:
$class = "MyClass";
$foo = classload( $class );
$foo->foo();
// try ext_include()
echo (ext_include( "MyFoo.class.php" ) ? "got MyFoo.class.php" : "damn")."<br>";
$foo = new MyFoo();
$foo->foo();
// see how it works:
show_classload_source();
********************************************************************************/
######################################################################
# some global vars
if( ! isset( $PHP_CLASSPATH ) ) {
if( isset( $HTTP_ENV_VARS[CLASSPATH] ) ) $PHP_CLASSPATH = $HTTP_ENV_VARS[CLASSPATH];
else $PHP_CLASSPATH = ".";
}
if( ! isset( $CLASSLOADER_CLASS_SUFFIX ) ) $CLASSLOADER_CLASS_SUFFIX = ".class.php";
if( ! isset( $EXT_INCLUDE_FILE_SUFFIX ) ) $EXT_INCLUDE_FILE_SUFFIX = ".inc.php";
######################################################################
# classload()
# loads the given class and returns an instantiated copy. Returns 0
# on error. For some reason returning 'false' does not work correctly:
# conditionals based on that are invariably incorrectly interpretted.
# If $dieonerror is true, then this function will exit() if there's
# the slightest hint of a problem.
function classload( $class, $dieonerror = true ) {
global $DefaultClassLoader;
$ret = $DefaultClassLoader->load( $class, $dieonerror );
$gotit = (strcasecmp( get_class( $ret ), $DefaultClassLoader->clean_classname($class) ) == 0);
if( $gotit == 0 && $dieonerror ) {
echo "fatal classloader error: ".$DefaultClassLoader->error();
exit();
}
if( $gotit == 0 ) {
#echo "classload( $class ): ".$DefaultClassLoader->error();
return 0;
}
return $ret;
}
######################################################################
# classload_error()
# returns the last error recorded by the classloader, or an empty string
function classload_error( $exit = false ) {
global $DefaultClassLoader;
if( $exit ) {
echo $DefaultClassLoader->error();
exit;
}
return $DefaultClassLoader->error();
}
######################################################################
# ext_include()
# a wrapper around include() which uses heuristics similar to classload(),
# except that it does not instantiate anything and does not append
# any suffix to the filename. Returns false on error, else true.
#
static $ext_include_cache = array();
function ext_include( $file, $dieonerror = true ) {
global $DefaultClassLoader, $EXT_INCLUDE_FILE_SUFFIX, $ext_include_cache;
$paths = split( ":", $DefaultClassLoader->$searchpath );
if( ! ereg( "\.", $file ) ) $file = $file.$EXT_INCLUDE_FILE_SUFFIX;
while( list( $k, $d ) = each( $paths ) ) {
$f = $d."/$file";
if( $ext_include_cache[$f] ) return true; # don't allow multiple inclusion
#echo "checking [$f]<br>";
if( ! file_exists( $f ) ) continue;
$ext_include_cache[$f] = include( $f );
return $ext_include_cache[$f];
}
if( $dieonerror ) die( "Couldn't ext_include( '$file' ) from any paths in [".$DefaultClassLoader->searchpath."]!" );
return false;
}
################################################################################
# show_classload_source()
# eye candy.
function show_classload_source() {
show_source( __FILE__ );
}
################################################################################
# class PHPClassLoader:
# This can be used directly, but it is not as convenient to do so (because
# you'll probably need to GLOBAL it). A static copy, $DefaultClassLoader, is instantiated
# when this file is include()d, and can be used. It is preferred to use the
# function classload(), however, which does some additional error checking.
#
class PHPClassLoader {
var $searchpath;
var $suffix = ".class.php";
var $error = "";
function PHPClassLoader( $spath = false, $class_suffix = false ) {
global $PHP_CLASSPATH;
if( $spath ) $this->$searchpath = $spath;
if( $class_suffix ) $this->suffix = $class_suffix;
if( ! $this->searchpath ) $this->searchpath = $PHP_CLASSPATH;
#echo "instaniated PHPClassLoader: suffix=[".$this->suffix."] searchpath=[".$this->searchpath."]<br>";
}
########################################
# strips the path part of a class' name, returning just the class name.
# i.e.: de/einsurance/mypackage/Foo becomes Foo.
function clean_classname( $class ) {
return preg_replace( "/.*\/(\w+)$/", "\\1", $class );
}
########################################
# Loads the given class, or returns 0.
#
function load( $class ) {
$cl = $this->clean_classname( $class );
if( class_exists( $cl ) ) return new $cl();
$this->error = "";
#echo $this->searchpath."<br>";
$paths = split( ":", $this->searchpath );
while( list( $k, $d ) = each( $paths ) ) {
$f = $d."/$class".$this->suffix;
#echo "checking [$f]<br>";
if( ! file_exists( $f ) ) continue;
include( $f );
if( ! class_exists( $cl ) ) {
$this->error = "File [$f] does not contain class [$cl]!";
return 0;
}
return new $cl();
}
$this->error = "class [$cl]: filename [$class".$this->suffix."] not found in path: [".$this->searchpath."]";
return 0;
} // end PHPClassLoader
/**
Returns the last recorded error.
*/
function error() {
return $this->error ? "PHPClassLoader: ".$this->error : "";
}
} // end class PHPClassLoader
######################################################################
# set up some shared vars:
static $DefaultClassLoader;
if( ! isset( $DefaultClassLoader ) )
$DefaultClassLoader = new PHPClassLoader( $PHP_CLASSPATH, $CLASSLOADER_CLASS_SUFFIX );
?> |