Example #1
0
 /**
  * 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;
 }
 /** Creates fixture */
 protected function newFixture() : IClassLoader
 {
     return DynamicClassLoader::instanceFor('test');
 }
 /**
  * Define an interface with a given name
  *
  * @param   string class fully qualified class name
  * @param   var[] parents The parent interfaces either by qualified names or XPClass instances
  * @param   string bytes default "{}" inner sourcecode of class (containing {}) 
  * @return  lang.XPClass
  * @throws  lang.FormatException in case the class cannot be defined
  */
 public static function defineInterface($class, $parents, $bytes = '{}')
 {
     $name = xp::reflect($class);
     if (!isset(xp::$cl[$class])) {
         // Load parent class and implemented interfaces
         $if = array();
         foreach ((array) $parents as $interface) {
             $if[] = self::classOf($interface)->literal();
         }
         // Define class
         with($dyn = self::registerLoader(DynamicClassLoader::instanceFor(__METHOD__)));
         $dyn->setClassBytes($class, sprintf('interface %s%s %s', $name, $parents ? ' extends ' . implode(', ', $if) : '', $bytes));
         return $dyn->loadClass($class);
     }
     return new XPClass($name);
 }
Example #4
0
function newinstance($spec, $args, $bytes)
{
    static $u = 0;
    // Check for an anonymous generic
    if (strstr($spec, '<')) {
        $class = Type::forName($spec);
        $type = $class->literal();
        $p = strrpos(substr($type, 0, strpos($type, 'ии')), 'и');
    } else {
        FALSE === strrpos($spec, '.') && ($spec = xp::nameOf($spec));
        $type = xp::reflect($spec);
        if (!class_exists($type, FALSE) && !interface_exists($type, FALSE)) {
            xp::error(xp::stringOf(new Error('Class "' . $spec . '" does not exist')));
            // Bails
        }
        $p = strrpos($type, 'и');
    }
    // Create unique name
    $n = 'и' . ++$u;
    if (FALSE !== $p) {
        $ns = '$package= "' . strtr(substr($type, 0, $p), 'и', '.') . '"; ';
        $spec = strtr(substr($type, 0, $p), 'и', '.') . '.' . substr($type, $p + 1) . $n;
        $decl = $type . $n;
    } else {
        if (FALSE === ($p = strrpos($type, '\\'))) {
            $ns = '';
            $decl = $type . $n;
            $spec = substr($spec, 0, strrpos($spec, '.')) . '.' . $type . $n;
        } else {
            $ns = 'namespace ' . substr($type, 0, $p) . '; ';
            $decl = substr($type, $p + 1) . $n;
            $spec = strtr($type, '\\', '.') . $n;
            $type = '\\' . $type;
        }
    }
    // Checks whether an interface or a class was given
    $cl = DynamicClassLoader::instanceFor(__FUNCTION__);
    if (interface_exists($type)) {
        $cl->setClassBytes($spec, $ns . 'class ' . $decl . ' extends Object implements ' . $type . ' ' . $bytes);
    } else {
        $cl->setClassBytes($spec, $ns . 'class ' . $decl . ' extends ' . $type . ' ' . $bytes);
    }
    $decl = $cl->loadClass0($spec);
    // Build paramstr for evaluation
    for ($paramstr = '', $i = 0, $m = sizeof($args); $i < $m; $i++) {
        $paramstr .= ', $args[' . $i . ']';
    }
    return eval('return new ' . $decl . '(' . substr($paramstr, 2) . ');');
}
 /**
  * Creates an XPClass instance from the specified code using a
  * DynamicClassLoader.
  *
  * @param   string bytes
  * @return  lang.XPClass
  */
 private function createClass($bytes)
 {
     $dyn = DynamicClassLoader::instanceFor(__METHOD__);
     try {
         $dyn->setClassBytes($this->getProxyName(), $bytes);
         $class = $dyn->loadClass($this->getProxyName());
     } catch (FormatException $e) {
         throw new IllegalArgumentException($e->getMessage());
     }
     return $class;
 }
 /**
  * Define an interface with a given name
  *
  * @param   string class fully qualified class name
  * @param   string[] parents FQCNs of parent interfaces
  * @param   string bytes default "{}" inner sourcecode of class (containing {}) 
  * @return  lang.XPClass
  * @throws  lang.FormatException in case the class cannot be defined
  * @throws  lang.ClassNotFoundException if given parent class does not exist
  */
 public static function defineInterface($class, $parents, $bytes = '{}')
 {
     $name = xp::reflect($class);
     $if = array();
     if (!isset(xp::$cl[$class])) {
         if (!empty($parents)) {
             $if = array_map(array('xp', 'reflect'), (array) $parents);
             foreach ($if as $i => $super) {
                 if (interface_exists($super, FALSE)) {
                     continue;
                 }
                 raise('lang.ClassLinkageException', $parents[$i], self::getLoaders());
             }
         }
         with($dyn = self::registerLoader(DynamicClassLoader::instanceFor(__METHOD__)));
         $dyn->setClassBytes($class, sprintf('interface %s%s %s', $name, sizeof($if) ? ' extends ' . implode(', ', $if) : '', $bytes));
         return $dyn->loadClass($class);
     }
     return new XPClass($name);
 }