예제 #1
0
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());
    }
}