From: Stig Bakken Date: Mon, 10 Dec 2001 01:50:11 +0000 (+0000) Subject: * initial commit of PEAR method autoloader X-Git-Tag: ChangeLog~61 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b11d1eb4407c6eae1b1f2140968b5201c4927a17;p=php * initial commit of PEAR method autoloader --- diff --git a/pear/PEAR/Autoloader.php b/pear/PEAR/Autoloader.php new file mode 100644 index 0000000000..6068fdce5c --- /dev/null +++ b/pear/PEAR/Autoloader.php @@ -0,0 +1,166 @@ + + */ +class PEAR_Autoloader extends PEAR +{ + /** + * Map of methods and classes where they are defined + * + * @var array + * + * @access private + */ + var $_autoload_map = array(); + + /** + * Map of methods and aggregate objects + * + * @var array + * + * @access private + */ + var $_method_map = array(); + + /** + * Add one or more autoload entries. + * + * @param $method string which method to autoload + * + * @param $classname string (optional) which class to find the method in. + * If the $method parameter is an array, this + * parameter may be omitted (and will be ignored + * if not), and the $method parameter will be + * treated as an associative array with method + * names as keys and class names as values. + * + * @return void + * + * @access public + */ + function addAutoload($method, $classname = null) + { + if (is_array($method)) { + $this->_autoload_map = array_merge($this->_autoload_map, $method); + } else { + $this->_autoload_map[$method] = $classname; + } + } + + /** + * Remove an autoload entry. + * + * @param $method string which method to remove the autoload entry for + * + * @return bool TRUE if an entry was removed, FALSE if not + * + * @access public + */ + function removeAutoload($method) + { + $ok = isset($this->_autoload_map[$method]); + unset($this->_autoload_map[$method]); + return $ok; + } + + /** + * Add an aggregate object to this object. If the specified class + * is not defined, loading it will be attempted following PEAR's + * file naming scheme. All the methods in the class will be + * aggregated, except private ones (name starting with an + * underscore) and constructors. + * + * @param $classname string what class to instantiate for the object. + * + * @return void + * + * @access public + */ + function addAggregateObject($classname) + { + $classname = strtolower($classname); + if (!class_exists($classname)) { + $include_file = preg_replace('/[^a-z0-9]/i', '_', $classname); + include_once $include_file; + } + $obj =& new $classname; + $methods = get_class_methods($classname); + foreach ($methods as $method) { + // don't import priviate methods and constructors + if ($method{0} != '_' && $method != $classname) { + $this->_method_map[$method] = $obj; + } + } + } + + /** + * Remove an aggregate object. + * + * @param $classname string the class of the object to remove + * + * @return bool TRUE if an object was removed, FALSE if not + * + * @access public + */ + function removeAggregateObject($classname) + { + $ok = false; + $classname = strtolower($classname); + reset($this->_method_map); + while (list($method, $obj) = each($this->_method_map)) { + if (get_class($obj) == $classname) { + unset($this->_method_map[$method]); + $ok = true; + } + } + return $ok; + } + + /** + * Overloaded object call handler, called each time an + * undefined/aggregated method is invoked. This method repeats + * the call in the right aggregate object and passes on the return + * value. + * + * @param $method string which method that was called + * + * @param $args array An array of the parameters passed in the + * original call + * + * @return mixed The return value from the aggregated method, or a PEAR + * error if the called method was unknown. + */ + function __call($method, $args) + { + if (empty($this->_method_map[$method]) && isset($this->_autoload_map[$method])) { + $this->addAggregateObject($this->_autoload_map[$method]); + } + if (isset($this->_method_map[$method])) { + return call_user_func_array(array($this->_method_map[$method], $method), $args); + } + return $this->raiseError("undefined method: $method"); + } +} + +overload("PEAR_Autoloader"); + +?> diff --git a/pear/tests/pear_autoloader.phpt b/pear/tests/pear_autoloader.phpt new file mode 100644 index 0000000000..d6c780d1ac --- /dev/null +++ b/pear/tests/pear_autoloader.phpt @@ -0,0 +1,80 @@ +--TEST-- +PEAR_Autoloader +--SKIPIF-- + +--FILE-- +addAutoload(array( + 'testfunc1' => 'testclass1', + 'testfunca' => 'testclass1', + 'testfunc2' => 'testclass2', + 'testfuncb' => 'testclass2', + )); + } +} + +class testclass1 { + function testfunc1($a) { + print "testfunc1 arg=";var_dump($a); + return 1; + } + function testfunca($a) { + print "testfunca arg=";var_dump($a); + return 2; + } +} + +class testclass2 { + function testfunc2($b) { + print "testfunc2 arg=";var_dump($b); + return 3; + } + function testfuncb($b) { + print "testfuncb arg=";var_dump($b); + return 4; + } +} + +function dump($obj) { + print "mapped methods:"; + foreach ($obj->_method_map as $method => $object) { + print " $method"; + } + print "\n"; +} + +function call($msg, $retval) { + print "calling $msg returned $retval\n"; +} + +$obj = new test1; +dump($obj); +call("testfunc1", $obj->testfunc1(2)); +dump($obj); +call("testfunca", $obj->testfunca(2)); +dump($obj); +call("testfunc2", $obj->testfunc2(2)); +dump($obj); +call("testfuncb", $obj->testfuncb(2)); +dump($obj); + +?> +--EXPECT-- +mapped methods: +testfunc1 arg=int(2) +calling testfunc1 returned 1 +mapped methods: testfunc1 testfunca +testfunca arg=int(2) +calling testfunca returned 2 +mapped methods: testfunc1 testfunca +testfunc2 arg=int(2) +calling testfunc2 returned 3 +mapped methods: testfunc1 testfunca testfunc2 testfuncb +testfuncb arg=int(2) +calling testfuncb returned 4 +mapped methods: testfunc1 testfunca testfunc2 testfuncb