package php.runtime.invoke; import php.runtime.Memory; import php.runtime.common.Messages; import php.runtime.env.Environment; import php.runtime.env.TraceInfo; import php.runtime.lang.IObject; import php.runtime.memory.ObjectMemory; import php.runtime.reflection.ClassEntity; import php.runtime.reflection.MethodEntity; import php.runtime.reflection.ParameterEntity; public class DynamicMethodInvoker extends Invoker { protected final IObject object; protected final MethodEntity method; public DynamicMethodInvoker(Environment env, TraceInfo trace, IObject object, MethodEntity method) { super(env, trace); this.object = object; this.method = method; } @Override public ParameterEntity[] getParameters() { return method.getParameters(); } @Override public String getName() { return object.getReflection().getName() + "::" + method.getName(); } public IObject getObject() { return object; } public MethodEntity getMethod() { return method; } @Override public int getArgumentCount() { return method.getParameters() == null ? 0 : method.getParameters().length; } @Override public void pushCall(TraceInfo trace, Memory[] args) { env.pushCall(trace, object, args, method.getName(), method.getClazz().getName(), object.getReflection().getName() ); } @Override protected Memory invoke(Memory... args) throws Throwable { return ObjectInvokeHelper.invokeMethod( object, method, env, trace == null ? TraceInfo.UNKNOWN : trace, args, false ); } @Override public int canAccess(Environment env) { return method.canAccess(env); } public static DynamicMethodInvoker valueOf(Environment env, TraceInfo trace, IObject object, String methodName){ String methodNameL = methodName.toLowerCase(); int pos; MethodEntity methodEntity; if ((pos = methodName.indexOf("::")) > -1){ String className = methodNameL.substring(0, pos); methodNameL = methodNameL.substring(pos + 2); ClassEntity classEntity = object.getReflection(); ClassEntity clazz = env.fetchClass(methodName.substring(0, pos), className, false); if (!classEntity.isInstanceOf(clazz)){ return null; } methodEntity = clazz.findMethod(methodNameL); } else methodEntity = object.getReflection().findMethod(methodNameL); if (methodEntity == null){ if (object.getReflection().methodMagicCall != null) { return new MagicDynamicMethodInvoker( env, trace, object, object.getReflection().methodMagicCall, methodName ); } if (trace == null) { return null; } env.error(trace, Messages.ERR_CALL_TO_UNDEFINED_METHOD.fetch(object.getReflection().getName() + "::" + methodName)); } return new DynamicMethodInvoker(env, trace, object, methodEntity); } public static DynamicMethodInvoker valueOf(Environment env, TraceInfo trace, Memory object, String methodName){ return valueOf(env, trace, ((ObjectMemory)object).value, methodName); } public static DynamicMethodInvoker valueOf(Environment env, TraceInfo trace, IObject object){ MethodEntity methodEntity = object.getReflection().methodMagicInvoke; if (methodEntity == null){ if (trace == null) return null; env.error(trace, Messages.ERR_CALL_TO_UNDEFINED_METHOD.fetch(object.getReflection().getName() + "::__invoke")); } return new DynamicMethodInvoker(env, null, object, methodEntity); } public static DynamicMethodInvoker valueOf(Environment env, TraceInfo trace, Memory object){ return valueOf(env, trace, ((ObjectMemory)object).value); } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof DynamicMethodInvoker)) return false; DynamicMethodInvoker that = (DynamicMethodInvoker) o; return method.equals(that.method) && object.getPointer() == that.object.getPointer(); } @Override public int hashCode() { int result = object.hashCode(); result = 31 * result + method.hashCode(); return result; } }