package php.runtime.ext.core.reflection; import php.runtime.Memory; import php.runtime.common.HintType; import php.runtime.common.Messages; import php.runtime.env.Environment; import php.runtime.memory.ArrayMemory; import php.runtime.memory.LongMemory; import php.runtime.memory.ObjectMemory; import php.runtime.memory.StringMemory; import php.runtime.reflection.ClassEntity; import php.runtime.reflection.ConstantEntity; import php.runtime.reflection.MethodEntity; import php.runtime.reflection.PropertyEntity; import static php.runtime.annotation.Reflection.*; @Name("ReflectionClass") @Signature( @Arg(value = "name", type = HintType.STRING, readOnly = true) ) public class ReflectionClass extends Reflection { public final static int IS_IMPLICIT_ABSTRACT = 16; public final static int IS_EXPLICIT_ABSTRACT = 32; public final static int IS_FINAL = 64; protected ClassEntity entity; protected ReflectionClass(Environment env) { super(env); } public ReflectionClass(Environment env, ClassEntity clazz) { super(env, clazz); } public ReflectionClass setEntity(ClassEntity entity) { this.entity = entity; getProperties().put("name", new StringMemory(entity.getName())); return this; } @Signature(@Arg("argument")) public Memory __construct(Environment env, Memory... args) { Memory argument = args[0]; if (argument.isObject()) { entity = argument.toValue(ObjectMemory.class).getReflection(); } else { entity = env.fetchClass(argument.toString(), true); if (entity == null) exception(env, Messages.ERR_CLASS_NOT_FOUND.fetch(argument.toString())); } setEntity(entity); return Memory.NULL; } @Signature public Memory getName(Environment env, Memory... args) { return new StringMemory(entity.getName()); } @Signature(@Arg("name")) public Memory getConstant(Environment env, Memory... args) { ConstantEntity constantEntity = entity.findConstant(args[0].toString()); if (constantEntity == null) return Memory.FALSE; return constantEntity.getValue(env); } @Signature public Memory getConstants(Environment env, Memory... args) { ArrayMemory result = new ArrayMemory(); for (ConstantEntity e : entity.getConstants()) { result.put(e.getName(), e.getValue(env)); } return result.toConstant(); } @Signature public Memory getDefaultProperties(Environment env, Memory... args) { ArrayMemory result = new ArrayMemory(); for (PropertyEntity e : entity.getStaticProperties()) { result.put(e.getName(), e.getDefaultValue(env)); } for (PropertyEntity e : entity.getProperties()) { result.put(e.getName(), e.getDefaultValue(env)); } return result.toConstant(); } @Signature public Memory getDocComment(Environment env, Memory... args) { if (entity.getDocComment() == null) return Memory.NULL; return new StringMemory(entity.getDocComment().toString()); } @Signature public Memory getEndLine(Environment env, Memory... args) { return LongMemory.valueOf(entity.getTrace().getEndLine()); } @Signature public Memory getExtension(Environment env, Memory... args) { if (entity.getExtension() == null) return Memory.NULL; ReflectionExtension extension = new ReflectionExtension(env); extension.setExtension(entity.getExtension()); return new ObjectMemory(extension); } @Signature public Memory getExtensionName(Environment env, Memory... args) { if (entity.getExtension() == null) return Memory.FALSE; return new StringMemory(entity.getExtension().getName()); } @Signature public Memory getFileName(Environment env, Memory... args) { if (entity.isInternal()) return Memory.FALSE; return new StringMemory(entity.getTrace().getFileName()); } @Signature public Memory getInterfaceNames(Environment env, Memory... args) { ArrayMemory result = new ArrayMemory(); for (ClassEntity e : entity.getInterfaces().values()) { result.add(new StringMemory(e.getName())); } return result.toConstant(); } @Signature public Memory getInterfaces(Environment env, Memory... args) { ArrayMemory result = new ArrayMemory(); ClassEntity classEntity = env.fetchClass("ReflectionClass"); for (ClassEntity e : entity.getInterfaces().values()) { ReflectionClass cls = new ReflectionClass(env, classEntity); cls.setEntity(e); result.add(new ObjectMemory(cls)); } return result.toConstant(); } @Signature public Memory getConstructor(Environment env, Memory... args) { return entity.methodConstruct == null ? Memory.NULL : new ObjectMemory(new ReflectionMethod(env, entity.methodConstruct)); } @Signature(@Arg("name")) public Memory getMethod(Environment env, Memory... args) { MethodEntity m = entity.findMethod(args[0].toString().toLowerCase()); if (m == null) { exception(env, Messages.ERR_METHOD_NOT_FOUND.fetch(entity.getName(), args[0])); return Memory.NULL; } ReflectionMethod r = new ReflectionMethod(env, m); return new ObjectMemory(r); } private boolean checkModifiers(MethodEntity e, int mod) { if (mod == -1) return true; if (e.isStatic() && (mod & ReflectionMethod.IS_STATIC) == ReflectionMethod.IS_STATIC) return true; if (e.isFinal() && (mod & ReflectionMethod.IS_FINAL) == ReflectionMethod.IS_FINAL) return true; if (e.isAbstract() && (mod & ReflectionMethod.IS_ABSTRACT) == ReflectionMethod.IS_ABSTRACT) return true; switch (e.getModifier()) { case PRIVATE: return (mod & ReflectionMethod.IS_PRIVATE) == ReflectionMethod.IS_PRIVATE; case PROTECTED: return (mod & ReflectionMethod.IS_PROTECTED) == ReflectionMethod.IS_PROTECTED; case PUBLIC: return (mod & ReflectionMethod.IS_PUBLIC) == ReflectionMethod.IS_PUBLIC; } return false; } @Signature(@Arg(value = "filter", optional = @Optional("NULL"))) public Memory getMethods(Environment env, Memory... args) { int mod = args[0].isNull() ? -1 : args[0].toInteger(); ArrayMemory result = new ArrayMemory(); ClassEntity classEntity = env.fetchClass("ReflectionMethod"); for (MethodEntity e : entity.getMethods().values()) { if (checkModifiers(e, mod)) { ReflectionMethod method = new ReflectionMethod(env, classEntity); method.setEntity(e); result.add(new ObjectMemory(method)); } } return result.toConstant(); } @Signature public Memory getModifiers(Environment env, Memory... args) { int mod = 0; if (entity.isFinal()) mod |= IS_FINAL; if (entity.isAbstract()) mod |= IS_EXPLICIT_ABSTRACT; return LongMemory.valueOf(mod); } @Signature public Memory getNamespaceName(Environment env, Memory... args) { if (!entity.isNamespace()) return Memory.FALSE; return new StringMemory(entity.getNamespaceName()); } @Signature public Memory getShortName(Environment env, Memory... args) { return new StringMemory(entity.getShortName()); } @Signature public Memory isNamespace(Environment env, Memory... args) { return entity.isNamespace() ? Memory.TRUE : Memory.FALSE; } private boolean checkModifiers(PropertyEntity prop, int mod) { boolean add = mod == -1; if (!add) { switch (prop.getModifier()) { case PRIVATE: add = (mod & ReflectionProperty.IS_PRIVATE) == ReflectionProperty.IS_PRIVATE; break; case PROTECTED: add = (mod & ReflectionProperty.IS_PROTECTED) == ReflectionProperty.IS_PROTECTED; break; case PUBLIC: add = (mod & ReflectionProperty.IS_PUBLIC) == ReflectionProperty.IS_PUBLIC; break; } } return add; } @Signature(@Arg("name")) public Memory getProperty(Environment env, Memory... args) { String name = args[0].toString(); PropertyEntity e = entity.findProperty(name); if (e == null) e = entity.findStaticProperty(name); if (e == null) return Memory.NULL; ClassEntity classEntity = env.fetchClass("ReflectionProperty"); ReflectionProperty prop = new ReflectionProperty(env, classEntity); prop.setEntity(e); return new ObjectMemory(prop); } @Signature public Memory getStaticProperties(Environment env, Memory... args) { ArrayMemory result = new ArrayMemory(); ClassEntity classEntity = env.fetchClass("ReflectionProperty"); for (PropertyEntity e : entity.getStaticProperties()) { ReflectionProperty prop = new ReflectionProperty(env, classEntity); prop.setEntity(e); result.add(new ObjectMemory(prop)); } return result.toConstant(); } @Signature(@Arg("name")) public Memory getStaticPropertyValue(Environment env, Memory... args) { String name = args[0].toString(); PropertyEntity e = entity.findStaticProperty(name); if (e == null) { exception(env, Messages.ERR_UNDEFINED_PROPERTY.fetch(entity.getName(), name)); return Memory.NULL; } if (!e.isDefault()) return Memory.FALSE; return e.getDefaultValue(env).toImmutable(); } @Signature(@Arg(value = "filter", optional = @Optional("NULL"))) public Memory getProperties(Environment env, Memory... args) { int mod = args[0].isNull() ? -1 : args[0].toInteger(); ArrayMemory result = new ArrayMemory(); ClassEntity classEntity = env.fetchClass("ReflectionProperty"); if (mod == -1 || (mod & ReflectionProperty.IS_STATIC) == ReflectionProperty.IS_STATIC) { for (PropertyEntity e : entity.getStaticProperties()) { ReflectionProperty prop = new ReflectionProperty(env, classEntity); prop.setEntity(e); result.add(new ObjectMemory(prop)); } } for (PropertyEntity e : entity.getProperties()) { if (checkModifiers(e, mod)) { ReflectionProperty prop = new ReflectionProperty(env, classEntity); prop.setEntity(e); result.add(new ObjectMemory(prop)); } } return result.toConstant(); } @Signature public Memory getParentClass(Environment env, Memory... args) { if (entity.getParent() == null) return Memory.NULL; ClassEntity classEntity = env.fetchClass("ReflectionClass"); ReflectionClass result = new ReflectionClass(env, classEntity); result.setEntity(entity.getParent()); return new ObjectMemory(result); } @Signature public Memory getTraits(Environment env, Memory... args) { ArrayMemory result = new ArrayMemory(); for (ClassEntity el : entity.getTraits().values()) { result.add(new ReflectionClass(env).setEntity(el)); } return result.toConstant(); } @Signature public Memory getTraitNames(Environment env, Memory... args) { ArrayMemory result = new ArrayMemory(); for (ClassEntity el : entity.getTraits().values()) { result.add(el.getName()); } return result.toConstant(); } @Signature public Memory getStartLine(Environment env, Memory... args) { if (entity.isInternal() || entity.getTrace().isUnknown()) return Memory.FALSE; return LongMemory.valueOf(entity.getTrace().getStartLine() + 1); } @Signature public Memory getPosition(Environment env, Memory... args) { if (entity.isInternal() || entity.getTrace().isUnknown()) return Memory.FALSE; return LongMemory.valueOf(entity.getTrace().getStartPosition() + 1); } @Signature(@Arg("name")) public Memory hasConstant(Environment env, Memory... args) { return entity.findConstant(args[0].toString()) != null ? Memory.TRUE : Memory.FALSE; } @Signature(@Arg("name")) public Memory hasMethod(Environment env, Memory... args) { MethodEntity method = entity.findMethod(args[0].toString().toLowerCase()); return method == null || (method.isPrivate() && !method.getClazz().equals(entity)) ? Memory.FALSE : Memory.TRUE; } @Signature(@Arg("name")) public Memory hasProperty(Environment env, Memory... args) { PropertyEntity prop = entity.findProperty(args[0].toString()); return prop == null || (prop.isPrivate() && !prop.getClazz().equals(entity)) ? Memory.FALSE : Memory.TRUE; } @Signature(@Arg("interface")) public Memory implementsInterface(Environment env, Memory... args) { String name = args[0].toString(); ClassEntity e = env.fetchClass(name, true); if (!e.isInterface()) exception(env, "Interface %s is a Class", name); if (!entity.isInstanceOf(e)) return Memory.FALSE; return env.fetchClass(name).isInterface() ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isAbstract(Environment env, Memory... args) { return entity.isAbstract() ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isCloneable(Environment env, Memory... args) { if (!entity.isClass()) return Memory.FALSE; if (entity.methodMagicClone == null || entity.methodMagicClone.isPublic()) return Memory.TRUE; else return Memory.FALSE; } @Signature public Memory isFinal(Environment env, Memory... args) { return entity.isFinal() ? Memory.TRUE : Memory.FALSE; } @Signature(@Arg("object")) public Memory isInstance(Environment env, Memory... args) { if (args[0].isObject()) { return args[0].toValue(ObjectMemory.class).getReflection().isInstanceOf(entity) ? Memory.TRUE : Memory.FALSE; } else return Memory.FALSE; } @Signature public Memory isInstantiable(Environment env, Memory... args) { if (entity.isClass() && !entity.isAbstract()) { return entity.methodConstruct == null || !entity.methodConstruct.isPrivate() ? Memory.TRUE : Memory.FALSE; } else return Memory.FALSE; } @Signature public Memory isInterface(Environment env, Memory... args) { return entity.isInterface() ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isTrait(Environment env, Memory... args) { return entity.isTrait() ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isInternal(Environment env, Memory... args) { return entity.isInternal() ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isIterable(Environment env, Memory... args) { return entity.isInstanceOfLower("iterator") ? Memory.TRUE : Memory.FALSE; } @Signature(@Arg("class")) public Memory isSubclassOf(Environment env, Memory... args) { String name = args[0].toString().toLowerCase(); return entity.isInstanceOf(name) && !entity.getLowerName().equals(name) ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isUserDefined(Environment env, Memory... args) { return entity.isInternal() ? Memory.FALSE : Memory.TRUE; } @Signature public Memory newInstance(Environment env, Memory... args) throws Throwable { return new ObjectMemory(entity.newObject(env, env.trace(), true, args)); } @Signature(@Arg(value = "args", type = HintType.ARRAY, optional = @Optional(type = HintType.ARRAY))) public Memory newInstanceArgs(Environment env, Memory... args) throws Throwable { if (args[0].isArray()) { return newInstance(env, args[0].toValue(ArrayMemory.class).values(true)); } else return Memory.NULL; } @Signature public Memory newInstanceWithoutConstructor(Environment env, Memory... args) throws Throwable { return new ObjectMemory(entity.newObject(env, env.trace(), false, args)); } @Signature({ @Arg(value = "reflector", type = HintType.OBJECT), @Arg(value = "return", type = HintType.BOOLEAN, optional = @Optional(value = "", type = HintType.BOOLEAN)) }) public static Memory export(Environment env, Memory... args) { ReflectionClass e = new ReflectionClass(env, env.fetchClass("ReflectionClass")); if (args[1].toBoolean()) return e.__toString(env); else env.echo(e.__toString(env)); return Memory.NULL; } }