package php.runtime.ext.core.reflection; import php.runtime.Memory; import php.runtime.common.HintType; import php.runtime.env.Environment; import php.runtime.invoke.Invoker; import php.runtime.memory.LongMemory; import php.runtime.memory.ObjectMemory; import php.runtime.memory.StringMemory; import php.runtime.memory.helper.ClassConstantMemory; import php.runtime.memory.helper.ConstantMemory; import php.runtime.reflection.ClassEntity; import php.runtime.reflection.FunctionEntity; import php.runtime.reflection.MethodEntity; import php.runtime.reflection.ParameterEntity; import php.runtime.reflection.helper.ClosureEntity; import php.runtime.reflection.support.AbstractFunctionEntity; import static php.runtime.annotation.Reflection.*; @Name("ReflectionParameter") @Signature( @Arg(value = "name", type = HintType.STRING, readOnly = true) ) public class ReflectionParameter extends Reflection implements Reflector { private ParameterEntity entity; private AbstractFunctionEntity functionEntity; private ObjectMemory cachedFunction; private int position; public ReflectionParameter(Environment env, ClassEntity clazz) { super(env, clazz); } @Signature({@Arg("function"), @Arg("parameter")}) public Memory __construct(Environment env, Memory... args) { ParameterEntity[] parameters = null; if (args[0].isClosure()) { ClosureEntity tmp = (ClosureEntity) args[0].toValue(ObjectMemory.class).getReflection(); parameters = tmp.parameters; } else if (args[0].isArray()) { Invoker invoker = Invoker.valueOf(env, null, args[0]); if (invoker == null) { exception(env, "%s does not exists", args[0].toString()); return Memory.NULL; } parameters = invoker.getParameters(); } else { String name = args[0].toString(); if (name.contains("::")) { Invoker invoker = Invoker.valueOf(env, null, args[0]); if (invoker == null) { exception(env, "%s does not exists", args[0].toString()); return Memory.NULL; } parameters = invoker.getParameters(); } else { FunctionEntity tmp = env.fetchFunction(name); functionEntity = tmp; if (tmp == null) { exception(env, "Function %s does not exist", args[0].toString()); return Memory.NULL; } if (tmp.isInternal()) { exception(env, "%s(): ReflectionParameter does not support internal functions", tmp.getName()); return Memory.NULL; } parameters = tmp.getParameters(); } } entity = null; String name = args[1].toString(); if (parameters != null) { if (args[1].isNumber()) { int index = args[1].toInteger(); if (index >= 0 && index < parameters.length) { entity = parameters[index]; position = index; } } else { int i = 0; for (ParameterEntity e : parameters) { if (e.getName().equals(name)) { entity = e; position = i; break; } i++; } } } if (entity == null) exception(env, "Parameter %s does not exist", name); setEntity(entity); return Memory.NULL; } public void setEntity(ParameterEntity entity) { this.entity = entity; getProperties().put("name", new StringMemory(entity.getName())); } public void setFunctionEntity(AbstractFunctionEntity functionEntity) { this.functionEntity = functionEntity; } public void setPosition(int position) { this.position = position; } @Signature public Memory allowsNull(Environment env, Memory... args) { if (entity.getType() == HintType.OBJECT && entity.getDefaultValue() == null) return Memory.FALSE; return Memory.TRUE; } @Signature public Memory canBePassedByValue(Environment env, Memory... args) { return entity.canBePassedByValue() ? Memory.TRUE : Memory.FALSE; } @Signature public Memory getDefaultValue(Environment env, Memory... args) { if (entity.getDefaultValue() == null) { exception(env, "Parameter has no default value"); return Memory.NULL; } return entity.getDefaultValue().toImmutable(env, env.trace()); } @Signature public Memory getDefaultValueConstantName(Environment env, Memory... args) { if (entity.getDefaultValueConstName() == null) return Memory.FALSE; else return new StringMemory(entity.getDefaultValueConstName()); } @Signature public Memory getName(Environment env, Memory... args) { return new StringMemory(entity.getName()); } @Signature public Memory getPosition(Environment env, Memory... args) { return LongMemory.valueOf(position); } @Signature public Memory isArray(Environment env, Memory... args) { return entity.getType() == HintType.ARRAY ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isCallable(Environment env, Memory... args) { return entity.getType() == HintType.CALLABLE ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isScalar(Environment env, Memory... args) { return entity.getType() == HintType.SCALAR ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isString(Environment env, Memory... args) { return entity.getType() == HintType.STRING ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isBoolean(Environment env, Memory... args) { return entity.getType() == HintType.BOOLEAN ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isNumber(Environment env, Memory... args) { return entity.getType() == HintType.NUMBER ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isInteger(Environment env, Memory... args) { return entity.getType() == HintType.INT ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isDouble(Environment env, Memory... args) { return entity.getType() == HintType.DOUBLE ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isObject(Environment env, Memory... args) { return entity.getType() == HintType.OBJECT ? Memory.TRUE : Memory.FALSE; } @Signature public Memory getHintType(Environment env, Memory... args) { return LongMemory.valueOf(entity.getType().ordinal()); } @Signature public Memory isDefaultValueAvailable(Environment env, Memory... args) { return entity.getDefaultValue() != null ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isDefaultValueConstant(Environment env, Memory... args) { return entity.getDefaultValue() instanceof ConstantMemory || entity.getDefaultValue() instanceof ClassConstantMemory ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isOptional(Environment env, Memory... args) { return entity.isOptional() ? Memory.TRUE : Memory.FALSE; } @Signature public Memory isPassedByReference(Environment env, Memory... args) { return entity.isPassedByReference() ? Memory.TRUE : Memory.FALSE; } @Signature @Name("getClass") public Memory _getClass(Environment env, Memory... args) { if (entity.getTypeClass() == null) return Memory.NULL; ClassEntity entity = env.fetchClass(this.entity.getTypeClass(), this.entity.getTypeClassLower(), true); if (entity == null) return Memory.NULL; ClassEntity classEntity = env.fetchClass("ReflectionClass"); ReflectionClass r = new ReflectionClass(env, classEntity); r.setEntity(entity); return new ObjectMemory(r); } @Signature public Memory getDeclaringClass(Environment env, Memory... args) { if (functionEntity == null) return Memory.NULL; if (functionEntity instanceof FunctionEntity) return Memory.NULL; MethodEntity method = (MethodEntity) functionEntity; ClassEntity classEntity = env.fetchClass("ReflectionClass"); ReflectionClass r = new ReflectionClass(env, classEntity); r.setEntity(method.getClazz()); return new ObjectMemory(r); } @Signature public Memory getDeclaringFunction(Environment env, Memory... args) throws Throwable { if (cachedFunction != null) return cachedFunction; if (functionEntity == null) return Memory.NULL; if (functionEntity instanceof FunctionEntity) { ClassEntity classEntity = env.fetchClass("ReflectionFunction"); ReflectionFunction e = new ReflectionFunction(env, classEntity); e.setFunctionEntity((FunctionEntity) functionEntity); return cachedFunction = new ObjectMemory(e); } else { ClassEntity classEntity = env.fetchClass("ReflectionMethod"); ReflectionMethod e = new ReflectionMethod(env, classEntity); e.setEntity((MethodEntity) functionEntity); return cachedFunction = new ObjectMemory(e); } } }