/// <summary> /// Returns an unitialized instance of the specified type or <see cref="__PHP_Incomplete_Class"/>. /// </summary> /// <param name="typeName">The type name.</param> /// <param name="context">Current <see cref="ScriptContext"/>.</param> /// <returns>The newly created instance or <B>null</B> if <paramref name="typeName"/> denotes /// a primitive type.</returns> /// <remarks> /// If the <paramref name="typeName"/> denotes a CLR type, no constructor is executed. If the /// <paramref name="typeName"/> denotes a PHP type, no user constructor (e.g. <c>__construct</c>) /// is executed. /// </remarks> public static DObject GetUninitializedInstance(string /*!*/ typeName, ScriptContext /*!*/ context) { // resolve the specified type DTypeDesc type = context.ResolveType(typeName); if (type == null || type.IsAbstract) { PhpCallback callback = context.Config.Variables.DeserializationCallback; if (callback != null && !callback.IsInvalid) { callback.Invoke(typeName); type = context.ResolveType(typeName); if (type == null || type.IsAbstract) { // unserialize_callback_func failed PhpException.Throw(PhpError.Warning, CoreResources.GetString("unserialize_callback_failed", ((IPhpConvertible)callback).ToString())); } } } if (type == null || type.IsAbstract) { // type not found -> create __PHP_Incomplete_Class __PHP_Incomplete_Class pic = new __PHP_Incomplete_Class(context, false); pic.__PHP_Incomplete_Class_Name.Value = typeName; pic.__PHP_Incomplete_Class_Name.IsSet = true; return(pic); } else { // create the instance return(type.New(context) as DObject); } }
/// <summary> /// Parses the <B>O</B> and <B>C</B> tokens. /// </summary> /// <param name="serializable">If <B>true</B>, the last token eaten was <B>C</B>, otherwise <B>O</B>.</param> object ParseObject(bool serializable) { Debug.Assert(_ctx != null); var seq = AddSeq(); // :{length}:"{classname}": Consume(Tokens.Colon); // : string class_name = ReadString().AsString(); // <length>:"classname" var tinfo = _ctx?.GetDeclaredType(class_name, true); // :{count}: Consume(Tokens.Colon); // : var count = (unchecked ((int)ReadInteger())); if (count < 0) { ThrowInvalidLength(); } Consume(Tokens.Colon); // bind to the specified class object obj; if (tinfo != null) { obj = tinfo.CreateUninitializedInstance(_ctx); if (obj == null) { throw new ArgumentException(string.Format(LibResources.class_instantiation_failed, class_name)); } } else { // TODO: DeserializationCallback // __PHP_Incomplete_Class obj = new __PHP_Incomplete_Class(); throw new NotImplementedException("__PHP_Incomplete_Class"); } // { Consume(Tokens.BraceOpen); if (serializable) { // check whether the instance is PHP5.1 Serializable if (!(obj is global::Serializable)) { throw new ArgumentException(string.Format(LibResources.class_has_no_unserializer, class_name)); } PhpString serializedBytes; if (count > 0) { // add serialized representation to be later passed to unserialize var buffer = new byte[count]; if (_stream.Read(buffer, 0, count) < count) { ThrowEndOfStream(); } serializedBytes = new PhpString(buffer); } else { serializedBytes = PhpString.Empty; } // Template: Serializable::unserialize(data) ((global::Serializable)obj).unserialize(serializedBytes); } else { var __unserialize = tinfo.RuntimeMethods[TypeMethods.MagicMethods.__unserialize]; var __unserialize_array = __unserialize != null ? new PhpArray(count) : null; // parse properties while (--count >= 0) { var key = Parse(); var value = Parse(); // if (key.TryToIntStringKey(out var iskey)) { if (__unserialize_array != null) { __unserialize_array[iskey] = value; } else { // set property SetProperty(obj, tinfo, iskey.ToString(), value, _ctx); } } else { this.ThrowInvalidDataType(); } } if (__unserialize != null) { __unserialize.Invoke(_ctx, obj, __unserialize_array); } else { // __wakeup var __wakeup = tinfo.RuntimeMethods[TypeMethods.MagicMethods.__wakeup]; if (__wakeup != null) { __wakeup.Invoke(_ctx, obj); } } } // } Consume(Tokens.BraceClose); // seq.Value = PhpValue.FromClass(obj); return(obj); }
/// <summary> /// Parses the <B>O</B> and <B>C</B> tokens. /// </summary> /// <param name="serializable">If <B>true</B>, the last token eaten was <B>C</B>, otherwise <B>O</B>.</param> object ParseObject(bool serializable) { // :{length}:"{classname}": Consume(Tokens.Colon); // : string class_name = ReadString().AsString(); // <length>:"classname" var tinfo = _ctx.GetDeclaredType(class_name, true); // :{count}: Consume(Tokens.Colon); // : var count = (unchecked ((int)ReadInteger())); if (count < 0) { ThrowInvalidLength(); } Consume(Tokens.Colon); // bind to the specified class object obj; if (tinfo != null) { obj = tinfo.GetUninitializedInstance(_ctx); if (obj == null) { throw new ArgumentException(string.Format(LibResources.class_instantiation_failed, class_name)); } } else { // TODO: DeserializationCallback // __PHP_Incomplete_Class obj = new __PHP_Incomplete_Class(); throw new NotImplementedException("__PHP_Incomplete_Class"); } Consume(Tokens.BraceOpen); if (serializable) { // check whether the instance is PHP5.1 Serializable if (!(obj is global::Serializable)) { throw new ArgumentException(string.Format(LibResources.class_has_no_unserializer, class_name)); } PhpString serializedBytes; if (count > 0) { // add serialized representation to be later passed to unserialize var buffer = new byte[count]; if (_stream.Read(buffer, 0, count) < count) { ThrowEndOfStream(); } serializedBytes = new PhpString(buffer); } else { serializedBytes = PhpString.Empty; } // Template: Serializable::unserialize(data) ((global::Serializable)obj).unserialize(serializedBytes); } else { // parse properties while (--count >= 0) { // parse property name var nameval = Parse(); var pname = nameval.ToStringOrNull(); if (pname == null) { if (!nameval.IsInteger()) { ThrowInvalidDataType(); } pname = nameval.ToStringOrThrow(_ctx); } // parse property value var pvalue = Parse(); // set property SetProperty(obj, tinfo, pname, pvalue, _ctx); } // __wakeup var __wakeup = tinfo.RuntimeMethods[TypeMethods.MagicMethods.__wakeup]; if (__wakeup != null) { __wakeup.Invoke(_ctx, obj); } } Consume(Tokens.BraceClose); // return(obj); }
/// <summary> /// Returns an unitialized instance of the specified type or <see cref="__PHP_Incomplete_Class"/>. /// </summary> /// <param name="typeName">The type name.</param> /// <param name="context">Current <see cref="ScriptContext"/>.</param> /// <returns>The newly created instance or <B>null</B> if <paramref name="typeName"/> denotes /// a primitive type.</returns> /// <remarks> /// If the <paramref name="typeName"/> denotes a CLR type, no constructor is executed. If the /// <paramref name="typeName"/> denotes a PHP type, no user constructor (e.g. <c>__construct</c>) /// is executed. /// </remarks> public static DObject GetUninitializedInstance(string/*!*/ typeName, ScriptContext/*!*/ context) { // resolve the specified type DTypeDesc type = context.ResolveType(typeName); if (type == null || type.IsAbstract) { PhpCallback callback = context.Config.Variables.DeserializationCallback; if (callback != null && !callback.IsInvalid) { callback.Invoke(typeName); type = context.ResolveType(typeName); if (type == null || type.IsAbstract) { // unserialize_callback_func failed PhpException.Throw(PhpError.Warning, CoreResources.GetString("unserialize_callback_failed", ((IPhpConvertible)callback).ToString())); } } } if (type == null || type.IsAbstract) { // type not found -> create __PHP_Incomplete_Class __PHP_Incomplete_Class pic = new __PHP_Incomplete_Class(context, false); pic.__PHP_Incomplete_Class_Name.Value = typeName; pic.__PHP_Incomplete_Class_Name.IsSet = true; return pic; } else { // create the instance return type.New(context) as DObject; } }