/** * Adds a source loader * * @param lang.IClassLoader */ public function addSourceLoader(IClassLoader $l) { $this->sourcepath[$l->hashCode()] = $l; }
/** * Returns the XPClass object for a proxy class given a class loader * and an array of interfaces. The proxy class will be defined by the * specified class loader and will implement all of the supplied * interfaces (also loaded by the classloader). * * @param lang.IClassLoader classloader * @param lang.XPClass[] interfaces names of the interfaces to implement * @return lang.XPClass * @throws lang.IllegalArgumentException */ public static function getProxyClass(IClassLoader $classloader, array $interfaces) { static $num = 0; static $cache = array(); $t = sizeof($interfaces); if (0 === $t) { throw new IllegalArgumentException('Interfaces may not be empty'); } // Calculate cache key (composed of the names of all interfaces) $key = $classloader->hashCode() . ':' . implode(';', array_map(create_function('$i', 'return $i->getName();'), $interfaces)); if (isset($cache[$key])) { return $cache[$key]; } // Create proxy class' name, using a unique identifier and a prefix $name = self::PREFIX . $num++; $bytes = 'class ' . $name . ' extends ' . xp::reflect('lang.reflect.Proxy') . ' implements '; $added = array(); for ($j = 0; $j < $t; $j++) { $bytes .= xp::reflect($interfaces[$j]->getName()) . ', '; } $bytes = substr($bytes, 0, -2) . " {\n"; for ($j = 0; $j < $t; $j++) { $if = $interfaces[$j]; // Verify that the Class object actually represents an interface if (!$if->isInterface()) { throw new IllegalArgumentException($if->getName() . ' is not an interface'); } // Implement all the interface's methods foreach ($if->getMethods() as $m) { // Check for already declared methods, do not redeclare them if (isset($added[$m->getName()])) { continue; } $added[$m->getName()] = TRUE; // Build signature and argument list if ($m->hasAnnotation('overloaded')) { $signatures = $m->getAnnotation('overloaded', 'signatures'); $max = 0; $cases = array(); foreach ($signatures as $signature) { $args = sizeof($signature); $max = max($max, $args - 1); if (isset($cases[$args])) { continue; } $cases[$args] = 'case ' . $args . ': ' . 'return $this->_h->invoke($this, \'' . $m->getName(TRUE) . '\', array(' . ($args ? '$_' . implode(', $_', range(0, $args - 1)) : '') . '));'; } // Create method $bytes .= 'function ' . $m->getName() . '($_' . implode('= NULL, $_', range(0, $max)) . '= NULL) { ' . 'switch (func_num_args()) {' . implode("\n", $cases) . ' default: throw new IllegalArgumentException(\'Illegal number of arguments\'); }' . '}' . "\n"; } else { $signature = $args = ''; foreach ($m->getParameters() as $param) { $signature .= ', '; $restriction = $param->getTypeRestriction(); if ($restriction instanceof XPClass) { $signature .= '\\' . strtr($restriction->getName(), array('php.' => '', '.' => '\\')); } else { if (Primitive::$ARRAY->equals($restriction)) { $signature .= 'array'; } } $signature .= ' $' . $param->getName(); $args .= ', $' . $param->getName(); $param->isOptional() && ($signature .= '= ' . var_export($param->getDefaultValue(), TRUE)); } $signature = substr($signature, 2); $args = substr($args, 2); // Create method $bytes .= 'function ' . $m->getName() . '(' . $signature . ') { ' . 'return $this->_h->invoke($this, \'' . $m->getName(TRUE) . '\', array(' . $args . ')); ' . '}' . "\n"; } } } $bytes .= ' }'; // Define the generated class try { $dyn = DynamicClassLoader::instanceFor(__METHOD__); $dyn->setClassBytes($name, $bytes); $class = $dyn->loadClass($name); } catch (FormatException $e) { throw new IllegalArgumentException($e->getMessage()); } // Update cache and return XPClass object $cache[$key] = $class; return $class; }
/** * Unregister a class loader as a delegate * * @param lang.IClassLoader l * @return bool TRUE if the delegate was unregistered */ public static function removeLoader(IClassLoader $l) { $id = $l->instanceId(); if (!isset(self::$delegates[$id])) { return FALSE; } unset(self::$delegates[$id]); return TRUE; }