function create($spec) { if ($spec instanceof Generic) { return $spec; } // Parse type specification: "new " TYPE "()"? // TYPE:= B "<" ARGS ">" // ARGS:= TYPE [ "," TYPE [ "," ... ]] $b = strpos($spec, '<'); $base = substr($spec, 4, $b - 4); $typeargs = Type::forNames(substr($spec, $b + 1, strrpos($spec, '>') - $b - 1)); // BC check: For classes with __generic field, instanciate without // invoking the constructor and pass type information. This is done // so that the constructur can already use generic types. $class = XPClass::forName(strstr($base, '.') ? $base : xp::nameOf($base)); if ($class->hasField('__generic')) { $__id = uniqid('', TRUE); $name = $class->literal(); $instance = unserialize('O:' . strlen($name) . ':"' . $name . '":1:{s:4:"__id";s:' . strlen($__id) . ':"' . $__id . '";}'); foreach ($typeargs as $type) { $instance->__generic[] = xp::reflect($type->getName()); } // Call constructor if available if (method_exists($instance, '__construct')) { $a = func_get_args(); call_user_func_array(array($instance, '__construct'), array_slice($a, 1)); } return $instance; } // Instantiate, passing the rest of any arguments passed to create() // BC: Wrap IllegalStateExceptions into IllegalArgumentExceptions try { $reflect = new ReflectionClass(XPClass::createGenericType($class, $typeargs)); if ($reflect->hasMethod('__construct')) { $a = func_get_args(); return $reflect->newInstanceArgs(array_slice($a, 1)); } else { return $reflect->newInstance(); } } catch (IllegalStateException $e) { throw new IllegalArgumentException($e->getMessage()); } catch (ReflectionException $e) { throw new IllegalAccessException($e->getMessage()); } }