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.exceptions.CriticalException; import php.runtime.exceptions.support.ErrorType; import php.runtime.ext.core.classes.WrapInvoker; import php.runtime.lang.ForeachIterator; import php.runtime.memory.ObjectMemory; import php.runtime.memory.support.MemoryOperation; import php.runtime.reflection.ParameterEntity; abstract public class Invoker implements Cloneable { protected Environment env; protected TraceInfo trace; protected boolean pushCallTrace = true; private Object userData; protected Invoker(Environment env, TraceInfo trace) { this.env = env; this.trace = trace; } @Override protected Invoker clone() throws CloneNotSupportedException { return (Invoker) super.clone(); } public Object getUserData() { return userData; } public void setUserData(Object userData) { this.userData = userData; } public Invoker forEnvironment(Environment env) { try { Invoker clone = clone(); clone.env = env; return clone; } catch (CloneNotSupportedException e) { throw new CriticalException(e); } } public Environment getEnvironment() { return env; } public void setPushCallTrace(boolean pushCallTrace) { this.pushCallTrace = pushCallTrace; } public void check(String name, TraceInfo trace){ } abstract public ParameterEntity[] getParameters(); abstract public String getName(); abstract public int getArgumentCount(); abstract protected void pushCall(TraceInfo trace, Memory[] args); abstract protected Memory invoke(Memory... args) throws Throwable; final public Memory call(Memory... args) throws Throwable { trace = trace == null ? (env == null ? TraceInfo.UNKNOWN : env.trace()) : trace; /*pushCall(trace, args); try {*/ return invoke(args); /*} finally { popCall(); }*/ } final public Memory callAny(Object... args) { if (args != null && args.length > 0) { Memory[] passed = new Memory[args.length]; for (int i = 0; i < passed.length; i++) { if (args[i] == null) { passed[i] = Memory.NULL; continue; } MemoryOperation operation = MemoryOperation.get( args[i].getClass(), args[i].getClass().getGenericSuperclass() ); if (operation == null) { throw new CriticalException("Unsupported bind type - " + args[i].getClass().toString()); } passed[i] = operation.unconvertNoThow(env, trace, args[i]); } return callNoThrow(passed); } else { return callNoThrow(); } } public Memory callNoThrow(Memory... args){ try { return call(args); } catch (RuntimeException e){ throw e; } catch (Throwable e){ throw new RuntimeException(e); } } protected void popCall(){ env.popCall(); } public void setTrace(TraceInfo trace) { this.trace = trace; } /** * Use create() method. */ @Deprecated public static Invoker valueOf(Environment env, Memory method){ return valueOf(env, env.peekCall(0).trace, method); } abstract public int canAccess(Environment env); public static Invoker create(Environment env, Memory method) { return Invoker.valueOf(env, null, method); } public static Invoker valueOf(Environment env, TraceInfo trace, Memory method){ method = method.toValue(); if (method.isObject()){ if (method.toValue(ObjectMemory.class).value instanceof WrapInvoker) return method.toObject(WrapInvoker.class).getInvoker(); return DynamicMethodInvoker.valueOf(env, trace, method); } else if (method.isArray()){ Memory one = null, two = null; ForeachIterator iterator = method.getNewIterator(env, false, false); while (iterator.next()){ if (one == null) one = iterator.getValue(); else if (two == null) two = iterator.getValue(); else break; } if (one == null || two == null) { if (trace == null) { return null; } env.error(trace, ErrorType.E_ERROR, Messages.ERR_CALL_TO_UNDEFINED_FUNCTION.fetch(method.toString())); } assert one != null; assert two != null; String methodName = two.toString(); if (one.isObject()) { return DynamicMethodInvoker.valueOf(env, trace, one.toValue(), methodName); } else { String className = one.toString(); return StaticMethodInvoker.valueOf(env, trace, className, methodName); } } else { String methodName = method.toString(); int p; if ((p = methodName.indexOf("::")) > -1) { String className = methodName.substring(0, p); methodName = methodName.substring(p + 2, methodName.length()); return StaticMethodInvoker.valueOf(env, trace, className, methodName); } else { return FunctionInvoker.valueOf(env, trace, methodName); } } } }