package php.runtime.reflection; import php.runtime.Memory; import php.runtime.common.Messages; import php.runtime.common.Modifier; import php.runtime.env.Context; import php.runtime.env.Environment; import php.runtime.env.TraceInfo; import php.runtime.exceptions.support.ErrorType; import php.runtime.invoke.ObjectInvokeHelper; import php.runtime.lang.IObject; import php.runtime.memory.ArrayMemory; import php.runtime.reflection.support.Entity; import java.lang.reflect.Field; public class PropertyEntity extends Entity { protected ClassEntity clazz; protected ClassEntity trait; protected Modifier modifier = Modifier.PUBLIC; private Memory defaultValue; protected DocumentComment docComment; protected boolean isStatic; protected Field field; protected String specificName; protected PropertyEntity prototype; protected boolean isDefault; protected MethodEntity getter; protected MethodEntity setter; protected boolean hiddenInDebugInfo = false; public PropertyEntity(Context context) { super(context); } public PropertyEntity getPrototype() { return prototype; } public void setPrototype(PropertyEntity prototype) { this.prototype = prototype; } public boolean isDefault() { return isDefault; } public void setDefault(boolean aDefault) { isDefault = aDefault; } public Field getField() { return field; } public void setField(Field field) { field.setAccessible(true); this.field = field; } public DocumentComment getDocComment() { return docComment; } public void setDocComment(DocumentComment docComment) { this.docComment = docComment; } public boolean isHiddenInDebugInfo() { return hiddenInDebugInfo; } public void setHiddenInDebugInfo(boolean hiddenInDebugInfo) { this.hiddenInDebugInfo = hiddenInDebugInfo; } public Memory getDefaultValue(){ return defaultValue; } public Memory getDefaultValue(Environment env) { if (defaultValue == null) { Memory r = env.getStatic(isStatic ? specificName : internalName); return r == null ? Memory.NULL : r; } else return defaultValue; } public void setDefaultValue(Memory defaultValue) { this.defaultValue = defaultValue; } public Modifier getModifier() { return modifier; } public boolean isPrivate(){ return modifier == Modifier.PRIVATE; } public boolean isProtected(){ return modifier == Modifier.PROTECTED; } public boolean isPublic(){ return modifier == Modifier.PUBLIC; } public void setModifier(Modifier modifier) { this.modifier = modifier; updateSpecificName(); } public boolean isStatic() { return isStatic; } public void setStatic(boolean aStatic) { isStatic = aStatic; } public ClassEntity getClazz() { return clazz; } public void setClazz(ClassEntity clazz) { this.clazz = clazz; updateSpecificName(); } public boolean isDeprecated(){ return false; // TODO } public void updateSpecificName(){ switch (modifier){ case PRIVATE: if (clazz != null) { specificName = "\0" + clazz.getName() + "\0" + name; } break; case PROTECTED: specificName = "\0*\0" + name; break; default: specificName = name; } if (isStatic && clazz != null) specificName = "\0" + clazz.getLowerName() + "#" + specificName; if (clazz != null) internalName = "\0" + clazz.getLowerName() + "\0#" + name; } @Override public void setName(String name) { super.setName(name); updateSpecificName(); } public String getSpecificName() { return specificName; } public ClassEntity getTrait() { return trait; } public void setTrait(ClassEntity trait) { this.trait = trait; } public boolean isOwned(ClassEntity entity){ return clazz.getId() == entity.getId(); } public int canAccess(Environment env) { return canAccess(env, null); } public MethodEntity getGetter() { return getter; } public void setGetter(MethodEntity getter) { this.getter = getter; } public MethodEntity getSetter() { return setter; } public void setSetter(MethodEntity setter) { this.setter = setter; } /** * 0 - success * 1 - invalid protected * 2 - invalid private * @param env * @return */ public int canAccess(Environment env, ClassEntity context) { switch (modifier){ case PUBLIC: return 0; case PRIVATE: ClassEntity cl = context == null ? env.getLastClassOnStack(true) : context; return cl != null && cl.getId() == this.clazz.getId() ? 0 : 2; case PROTECTED: ClassEntity clazz = context == null ? env.getLastClassOnStack(true) : context; if (clazz == null) return 1; long id = this.clazz.getId(); do { if (clazz.getId() == id) return 0; clazz = clazz.parent; } while (clazz != null); } return 2; } public boolean canAccessAsNonStatic(Environment env, TraceInfo trace){ if (isStatic){ env.error( trace, ErrorType.E_STRICT, Messages.ERR_ACCESSING_STATIC_PROPERTY_AS_NON_STATIC, getClazz().getName(), name ); return false; } return true; } public boolean isReadOnly() { return getter == null && setter != null; } public PropertyEntity duplicate() { PropertyEntity propertyEntity = new PropertyEntity(context); propertyEntity.setStatic(isStatic); propertyEntity.setDocComment(docComment); propertyEntity.setName(name); propertyEntity.setDefault(isDefault); propertyEntity.setDefaultValue(defaultValue); propertyEntity.setModifier(modifier); propertyEntity.setPrototype(propertyEntity); propertyEntity.setTrace(trace); propertyEntity.setGetter(getter); propertyEntity.setSetter(setter); return propertyEntity; } public Memory assignValue(Environment env, TraceInfo trace, Object object, String name, Memory value) { return ((IObject) object).getProperties().refOfIndex(name).assign(value); } public Memory getStaticValue(Environment env, TraceInfo trace) { return env.getOrCreateStatic( specificName, getDefaultValue(env).toImmutable() ); } public Memory getValue(Environment env, TraceInfo trace, Object object) throws Throwable { if (getter != null && object instanceof IObject) { return ObjectInvokeHelper.invokeMethod((IObject) object, getter, env, trace, null, false); } ArrayMemory props = ((IObject) object).getProperties(); Memory result = props.getByScalar(specificName); if (result == null) { result = props.getByScalar(name); } return result; } }