/// <summary> /// Sets property value dynamically on the newly instantiated object. /// </summary> protected static void SetProperty(object /*!*/ instance, PhpTypeInfo tinfo, string /*!*/ name, PhpValue value, Context /*!*/ context) { // the property name might encode its visibility and "classification" -> use these // information for suitable property desc lookups FieldAttributes visibility; string type_name; string property_name = Serialization.ParseSerializedPropertyName(name, out type_name, out visibility); var declarer = (type_name == null) ? tinfo : context.GetDeclaredType(type_name, true) ?? tinfo; // try to find a suitable field handle var fld = TypeMembersUtils.ResolveInstanceField(tinfo, property_name); if (fld != null && TypeMembersUtils.IsVisible(fld, declarer.Type.AsType())) { if ((fld.IsPrivate && declarer.Type.AsType() != fld.DeclaringType)) { // if certain conditions are met, don't use the handle even if it was found // (this is to precisely mimic the PHP behavior) fld = null; } } if (fld != null) { fld.SetValue(instance, value); } else if (tinfo.RuntimeFieldsHolder != null) { // suitable CT field not found -> add it to RT fields // (note: care must be taken so that the serialize(unserialize($x)) round // trip returns $x even if user classes specified in $x are not declared) var runtime_fields = tinfo.GetRuntimeFields(instance); if (runtime_fields == null) { runtime_fields = new PhpArray(1); tinfo.RuntimeFieldsHolder.SetValue(instance, runtime_fields); } runtime_fields[name] = value; } else { throw new ArgumentException(); } }
IEnumerable <KeyValuePair <string, PhpValue> > EnumerateSerializableProperties(object obj, PhpTypeInfo tinfo, PhpArray properties) { Debug.Assert(obj != null); Debug.Assert(tinfo != null); Debug.Assert(properties != null); PhpArray runtime_fields = null; var enumerator = properties.GetFastEnumerator(); while (enumerator.MoveNext()) { // TODO: PhpFieldInfo instead of System.Reflection.FieldInfo FieldAttributes visibility; string name = enumerator.CurrentValue.ToStringOrThrow(_ctx); string declaring_type_name; string property_name = Serialization.ParseSerializedPropertyName(name, out declaring_type_name, out visibility); PhpTypeInfo declarer; // for visibility check if (declaring_type_name == null) { declarer = tinfo; } else { declarer = _ctx.GetDeclaredType(declaring_type_name); if (declarer == null) { // property name refers to an unknown class -> value will be null yield return(new KeyValuePair <string, PhpValue>(name, PhpValue.Null)); continue; } } // obtain the property desc and decorate the prop name according to its visibility and declaring class var fld = TypeMembersUtils.ResolveInstanceField(tinfo, name); if (fld != null && TypeMembersUtils.IsVisible(fld, declarer.Type.AsType())) { var fld_declarer = fld.DeclaringType; // if certain conditions are met, serialize the property as null // (this is to precisely mimic the PHP behavior) if ((visibility == (fld.Attributes & FieldAttributes.FieldAccessMask) && visibility != FieldAttributes.Public) || (visibility == FieldAttributes.Private && declarer.Type.AsType() != fld_declarer)) { yield return(new KeyValuePair <string, PhpValue>(name, PhpValue.Null)); continue; } name = Serialization.FormatSerializedPropertyName(fld, property_name, fld_declarer.GetPhpTypeInfo()); } else { fld = null; // field is not visible, try runtime fields } // obtain the property value PhpValue val; if (fld != null) { val = PhpValue.FromClr(fld.GetValue(obj)); } else { if (runtime_fields == null) { runtime_fields = tinfo.GetRuntimeFields(obj) ?? PhpArray.Empty; } if (!runtime_fields.TryGetValue(name, out val)) { // PHP 5.1+ PhpException.Throw(PhpError.Notice, string.Format(Core.Resources.ErrResources.sleep_returned_bad_field, name)); } } yield return(new KeyValuePair <string, PhpValue>(name, val)); } }