public static PhpArray BuildErrorInfo(string sqlstate, object driver_error, string message) { PhpArray arr = new PhpArray(); arr.Add(0, sqlstate); arr.Add(1, driver_error); arr.Add(2, message); return arr; }
public static PhpArray PrintFunctions() { PhpArray result = new PhpArray(); result.Add("name", new PhpArray()); result.Add("type", new PhpArray()); result.Add("method", new PhpArray()); Assembly assembly = typeof(PhpDocumentation).Assembly; //PhpLibraryModule.EnumerateFunctions(assembly, new PhpLibraryModule.FunctionsEnumCallback(FunctionsCallback), result); return result; }
public static PhpArray GetFunctions() { var context = ScriptContext.CurrentContext; if (context.IsSplAutoloadEnabled) { PhpArray result = new PhpArray(); foreach (var func in context.SplAutoloadFunctions) result.Add(func.ToPhpRepresentation()); return result; } else { return null; } }
private static object BindObject(object obj, Type type) { FieldInfo[] fi = type.GetFields(BindingFlags.Public | BindingFlags.Instance); var runtimeFields = new PhpArray(fi.Length); object value; bool specified = true; FieldInfo field; for (int i = 0; i < fi.Length; ++i) { field = fi[i]; specified = true; if (i + 1 < fi.Length && Attribute.IsDefined(fi[i + 1], typeof(XmlIgnoreAttribute))) { value = fi[i + 1].GetValue(obj); if (value == null) specified = false; else specified = (bool)value; i++; } if (specified) { value = Bind(field.GetValue(obj), field); if (value != null) runtimeFields.Add(field.Name, value); } } return new stdClass() { RuntimeFields = runtimeFields }; }
/// <summary> /// Gets an array of modifier names contained in modifiers flags. /// </summary> //[ImplementsMethod] public static PhpArray getModifierNames(int modifiers) { PhpArray result = new PhpArray(); Modifiers flags = (Modifiers)modifiers; if ((flags & (Modifiers.Abstract | Modifiers.AbstractClass)) != 0) result.Add("abstract"); if ((flags & (Modifiers.Abstract | Modifiers.AbstractClass)) != 0) result.Add("final"); switch (flags & Modifiers.VisibilityMask) { case Modifiers.Public: result.Add("public"); break; case Modifiers.Protected: result.Add("protected"); break; case Modifiers.Private: result.Add("private"); break; } if ((flags & Modifiers.Static) != 0) result.Add("static"); return result; }
/// <summary> /// Default callback for <see cref="Map"/>. /// </summary> /// <param name="instance">Unused.</param> /// <param name="stack">A PHP stack.</param> /// <returns>A <see cref="PhpArray"/> containing items on the stack (passed as arguments).</returns> private static object MapIdentity(object instance, PhpStack stack) { PhpArray result = new PhpArray(stack.ArgCount, 0); for (int i = 1; i <= stack.ArgCount; i++) { result.Add(PhpVariable.Copy(stack.PeekValueUnchecked(i), CopyReason.PassedByCopy)); } stack.RemoveFrame(); return result; }
public static PhpArray Filter(PHP.Core.Reflection.DTypeDesc _, PhpArray array) { var _result = new PhpArray(); using (var enumerator = array.GetFastEnumerator()) while (enumerator.MoveNext()) if (Core.Convert.ObjectToBoolean(enumerator.CurrentValue)) _result.Add(enumerator.CurrentKey, enumerator.CurrentValue); return _result; }
public static PhpArray Unique(PhpArray array, ArrayUniqueSortFlags sortFlags /*= String*/) { if (array == null) { PhpException.ArgumentNull("array"); return null; } IComparer comparer; switch(sortFlags) { case ArrayUniqueSortFlags.Regular: comparer = PhpComparer.Default; break; case ArrayUniqueSortFlags.Numeric: comparer = PhpNumericComparer.Default; break; case ArrayUniqueSortFlags.String: comparer = PhpStringComparer.Default; break; case ArrayUniqueSortFlags.LocaleString: default: PhpException.ArgumentValueNotSupported("sortFlags", (int)sortFlags); return null; } PhpArray result = new PhpArray(array.Count); HashSet<object>/*!*/identitySet = new HashSet<object>(new ObjectEqualityComparer(comparer)); // get only unique values - first found using (var enumerator = array.GetFastEnumerator()) while (enumerator.MoveNext()) { if (identitySet.Add(PhpVariable.Dereference(enumerator.CurrentValue))) result.Add(enumerator.Current); } result.InplaceCopyOnReturn = true; return result; }
/// <summary> /// Adds items of "array" to "result" merging those whose string keys are the same. /// </summary> private static bool MergeRecursiveInternal(PhpArray/*!*/ result, PhpArray/*!*/ array, bool deepCopy) { foreach (KeyValuePair<IntStringKey, object> entry in array) { if (entry.Key.IsString) { if (result.ContainsKey(entry.Key)) { // the result array already contains the item => merging take place object xv = result[entry.Key]; object yv = entry.Value; // source item: object x = PhpVariable.Dereference(xv); object y = PhpVariable.Dereference(yv); PhpArray ax = x as PhpArray; PhpArray ay = y as PhpArray; // if x is not a reference then we can reuse the ax array for the result // since it has been deeply copied when added to the resulting array: PhpArray item_result = (deepCopy && x == xv && ax != null) ? ax : new PhpArray(); if (ax != null && ay != null) { if (ax != item_result) ax.AddTo(item_result, deepCopy); if (ax.Visited && ay.Visited) return false; ax.Visited = true; ay.Visited = true; // merges ay to the item result (may lead to stack overflow, // but only with both arrays recursively referencing themselves - who cares?): bool finite = MergeRecursiveInternal(item_result, ay, deepCopy); ax.Visited = false; ay.Visited = false; if (!finite) return false; } else { if (ax != null) { if (ax != item_result) ax.AddTo(item_result, deepCopy); } else { /*if (x != null)*/ item_result.Add((deepCopy) ? PhpVariable.DeepCopy(x) : x); } if (ay != null) ay.AddTo(item_result, deepCopy); else /*if (y != null)*/ item_result.Add((deepCopy) ? PhpVariable.DeepCopy(y) : y); } result[entry.Key] = item_result; } else { // PHP does no dereferencing when items are not merged: result.Add(entry.Key, (deepCopy) ? PhpVariable.DeepCopy(entry.Value) : entry.Value); } } else { // PHP does no dereferencing when items are not merged: result.Add((deepCopy) ? PhpVariable.DeepCopy(entry.Value) : entry.Value); } } return true; }
/// <summary> /// Creates an array containing range of characters from the [low;high] interval with arbitrary step. /// </summary> /// <param name="low">Lower bound of the interval.</param> /// <param name="high">Upper bound of the interval.</param> /// <param name="step">The step.</param> /// <returns>The array.</returns> /// <exception cref="PhpException">Thrown if the <paramref name="step"/> argument is zero.</exception> public static PhpArray RangeOfChars(char low, char high, int step) { if (step == 0) { PhpException.InvalidArgument("step", LibResources.GetString("arg:zero")); step = 1; } if (step < 0) step = -step; PhpArray result = new PhpArray(Math.Abs(high - low) / step + 1, 0); if (high >= low) { for (int i = 0; low <= high; i++, low = unchecked((char)(low + step))) result.Add(i, low.ToString()); } else { for (int i = 0; low >= high; i++, low = unchecked((char)(low - step))) result.Add(i, low.ToString()); } return result; }
/// <summary> /// Ensures a specified array item is an instance of <see cref="PhpArray"/>. /// </summary> /// <param name="array">The <see cref="PhpArray"/> which item should be an array.</param> /// <param name="key">The key identifying which item should be an array.</param> /// <remarks> /// A new instance of <see cref="PhpArray"/> is assigned to the item if it is not an array yet. /// Array is expected to contain no <see cref="PhpReference"/>. /// Treats empty key as a missing key. /// </remarks> internal static PhpArray EnsureItemIsArraySimple(PhpArray/*!*/ array, string key) { Debug.Assert(array != null); Debug.Assert(!(array is PhpArrayString) && !(array is Library.SPL.PhpArrayObject)); // treats empty key as a missing key: if (key == String.Empty) { PhpArray array_item = new PhpArray(); array.Add(array_item); return array_item; } IntStringKey array_key = Core.Convert.StringToArrayKey(key); return array.table._ensure_item_array(ref array_key, array); //element = array.GetElement(array_key); //// creates a new array if an item is not one: //array_item = (element != null) ? element.Value as PhpArray : null; //if (array_item == null) //{ // array_item = new PhpArray(); // if (element != null) // { // if (array.table.IsShared) // { // // we are going to change the internal array, it must be writable // array.EnsureWritable(); // element = array.table.dict[array_key]; // get the item again // } // element.Value = array_item; // } // else // array.Add(array_key, array_item); //} //return array_item; }
private static void SetItemEpilogue(object value, ref object var) { Debug.Assert(var == null || var.GetType() != typeof(PhpArray)); PhpArray array; // creates a new array and stores it into a new item which is added to the array: if (IsEmptyForEnsure(var)) { array = new PhpArray(1, 0); array.Add(value); var = array; return; } // PhpArray derivates: if ((array = var as PhpArray) != null) { if (array.Add(value) == 0) PhpException.Throw(PhpError.Warning, CoreResources.GetString("integer_key_reached_max_value")); return; } // object behaving as array: DObject dobj = var as DObject; if (dobj != null && dobj.RealObject is Library.SPL.ArrayAccess) { //PhpStack stack = ScriptContext.CurrentContext.Stack; //stack.AddFrame(null, value); //dobj.InvokeMethod(Library.SPL.PhpArrayObject.offsetSet, null, stack.Context); ((Library.SPL.ArrayAccess)dobj.RealObject).offsetSet(ScriptContext.CurrentContext, null, value); return; } // errors: PhpException.VariableMisusedAsArray(var, false); }
public static PhpReference GetItemRef(ref object var) { Debug.Assert(!(var is PhpReference)); // PhpArray: if (var != null && var.GetType() == typeof(PhpArray)) // fast check for PhpArray, not derived types return ((PhpArray)var).GetArrayItemRef(); // creates a new reference and adds it to an a new array: if (IsEmptyForEnsure(var)) { PhpArray array; var = array = new PhpArray(1, 0); PhpReference result = new PhpReference(); array.Add(result); return result; } return GetItemRefEpilogue(null, ref var); }
public static void SetVariable(ScriptContext/*!*/ context, Dictionary<string, object> locals, string/*!*/ name, object value) { Debug.Assert(name != null && !(value is PhpReference)); if (locals != null) { // included in method // object item; PhpReference ref_item; if (locals.TryGetValue(name, out item) && (ref_item = item as PhpReference) != null) ref_item.Value = value; else locals[name] = value; } else { // true global code // PhpArray globals = context.AutoGlobals.Globals.Value as PhpArray; if (globals == null) { context.AutoGlobals.Globals.Value = globals = new PhpArray(); globals.Add(name, value); return; } object item; PhpReference ref_item; if (globals.TryGetValue(name, out item) && (ref_item = item as PhpReference) != null) ref_item.Value = value; else globals[name] = value; } }
public static PhpArray GetHandlers() { BufferedOutput bo = ScriptContext.CurrentContext.BufferedOutput; PhpArray result = new PhpArray(bo.Level, 0); for (int i = 0; i < bo.Level; i++) { result.Add(bo.GetLevelName(i)); } return result; }
/// <summary> /// Creates an array containing range of long integers from the [low;high] interval with arbitrary step. /// </summary> /// <param name="low">Lower bound of the interval.</param> /// <param name="high">Upper bound of the interval.</param> /// <param name="step">The step. An absolute value is taken if step is zero.</param> /// <returns>The array.</returns> public static PhpArray RangeOfLongInts(long low, long high, long step) { if (step == 0) { PhpException.InvalidArgument("step", LibResources.GetString("arg:zero")); return null; } if (step < 0) step = -step; PhpArray result = new PhpArray(unchecked((int)(Math.Abs(high - low) / step + 1))); if (high >= low) { for (int i = 0; low <= high; i++, low += step) result.Add(i, low); } else { for (int i = 0; low >= high; i++, low -= step) result.Add(i, low); } return result; }
/// <summary> /// Creates an array containing range of doubles from the [low;high] interval with arbitrary step. /// </summary> /// <param name="low">Lower bound of the interval.</param> /// <param name="high">Upper bound of the interval.</param> /// <param name="step">The step. An absolute value is taken if step is less than zero.</param> /// <returns>The array.</returns> /// <exception cref="PhpException">Thrown if the <paramref name="step"/> argument is zero.</exception> public static PhpArray RangeOfDoubles(double low, double high, double step) { if (step == 0) { PhpException.InvalidArgument("step", LibResources.GetString("arg:zero")); return null; } if (step < 0) step = -step; PhpArray result = new PhpArray(System.Convert.ToInt32(Math.Abs(high - low) / step) + 1); if (high >= low) { for (int i = 0; low <= high; i++, low += step) result.Add(i, low); } else { for (int i = 0; low >= high; i++, low -= step) result.Add(i, low); } return result; }
/// <summary> /// Converts a W3C .NET object to the corresponding W3C PHP object. /// </summary> public static object DotNetToPhp(object arg) { // Result Tree Fragment (XSLT) / Node (XPath) XPathNavigator nav = arg as XPathNavigator; if (nav != null) return DOMNode.Create(nav.UnderlyingObject as XmlNode); // Node Set (XPath) - XPathNavigator[] XPathNavigator[] navs = arg as XPathNavigator[]; if (navs != null) { PhpArray array = new PhpArray(navs.Length, 0); for (int i = 0; i < navs.Length; i++) { IXmlDomNode node = DOMNode.Create(navs[i].UnderlyingObject as XmlNode); if (node != null) array.Add(node); } return array; } // Node Set (XPath) - XPathNodeIterator XPathNodeIterator iter = arg as XPathNodeIterator; if (iter != null) { PhpArray array = new PhpArray(); foreach (XPathNavigator navigator in iter) { IXmlDomNode node = DOMNode.Create(navigator.UnderlyingObject as XmlNode); if (node != null) array.Add(node); } return array; } // Number (XPath), Boolean (XPath), String (XPath) return arg; }
public static PhpArray Merge(params PhpArray[] arrays) { // "arrays" argument is PhpArray[] => compiler generates code converting any value to PhpArray. // Note, PHP does reject non-array arguments. if (arrays == null || arrays.Length == 0) { PhpException.InvalidArgument("arrays", LibResources.GetString("arg:null_or_empty")); return null; } PhpArray result = new PhpArray(arrays[0].IntegerCount, arrays[0].StringCount); for (int i = 0; i < arrays.Length; i++) { if (arrays[i] != null) { using (var enumerator = arrays[i].GetFastEnumerator()) while (enumerator.MoveNext()) { if (enumerator.CurrentKey.IsString) result[enumerator.CurrentKey] = enumerator.CurrentValue; else result.Add(enumerator.CurrentValue); } } } // results is inplace deeply copied if returned to PHP code: result.InplaceCopyOnReturn = true; return result; }
/// <summary> /// Returns an associative array containing the date information. /// </summary> /// <param name="utc">UTC date time.</param> /// <returns>Associative array with date information.</returns> public static PhpArray GetDate(DateTime utc) { PhpArray result = new PhpArray(1, 10); var zone = PhpTimeZone.CurrentTimeZone; DateTime local = TimeZoneInfo.ConvertTimeFromUtc(utc, zone); result.Add("seconds", local.Second); result.Add("minutes", local.Minute); result.Add("hours", local.Hour); result.Add("mday", local.Day); result.Add("wday", (int)local.DayOfWeek); result.Add("mon", local.Month); result.Add("year", local.Year); result.Add("yday", local.DayOfYear - 1); // PHP: zero based day count result.Add("weekday", local.DayOfWeek.ToString()); result.Add("month", local.ToString("MMMM", DateTimeFormatInfo.InvariantInfo)); result.Add(0, DateTimeUtils.UtcToUnixTimeStamp(utc)); return result;
/// <summary> /// Internal version of <see cref="Chunk"/> with deep-copy option. /// </summary> internal static PhpArray ChunkInternal(PhpArray array, int size, bool preserveKeys, bool deepCopy) { if (array == null) { PhpException.ArgumentNull("array"); return null; } if (size <= 0) { PhpException.InvalidArgument("array", LibResources.GetString("arg:negative_or_zero")); return null; } // nothing to do: if (array.Count == 0) return new PhpArray(); // number of chunks: int count = (array.Count - 1) / size + 1; // = ceil(Count/size): PhpArray chunk; PhpArray result = new PhpArray(count, 0); IEnumerator<KeyValuePair<IntStringKey, object>> iterator; // if deep-copies are required, wrapp iterator by enumerator making deep copies: if (deepCopy) iterator = PhpVariable.EnumerateDeepCopies(array).GetEnumerator(); else iterator = array.GetEnumerator(); iterator.MoveNext(); // all chunks except for the last one: for (int i = 0; i < count - 1; i++) { chunk = new PhpArray(size, 0); if (preserveKeys) { for (int j = 0; j < size; j++, iterator.MoveNext()) chunk.Add(iterator.Current.Key, iterator.Current.Value); } else { for (int j = 0; j < size; j++, iterator.MoveNext()) chunk.Add(iterator.Current.Value); } result.Add(chunk); } // the last chunk: chunk = new PhpArray((size <= array.Count) ? size : array.Count, 0); if (preserveKeys) { do { chunk.Add(iterator.Current.Key, iterator.Current.Value); } while (iterator.MoveNext()); } else { do { chunk.Add(iterator.Current.Value); } while (iterator.MoveNext()); } result.Add(chunk); // no deep copy is needed since it has already been done on chunks: return result; }
public static PhpArray Grep(object pattern, PhpArray input, GrepFlags flags) { if (input == null) return null; PerlRegExpConverter converter = ConvertPattern(pattern, null); if (converter == null) return null; PhpArray result = new PhpArray(); foreach (KeyValuePair<IntStringKey, object> entry in input) { string str = ConvertData(entry.Value, converter); Match m = converter.Regex.Match(str); // move a copy to return array if success and not invert or // not success and invert if (m.Success ^ (flags & GrepFlags.GrepInvert) != 0) result.Add(entry.Key, str); } return result; }
public static PhpArray Each([PhpRw] IPhpEnumerable array) { if (array == null) { //PhpException.ReferenceNull("array"); return null; } if (array.IntrinsicEnumerator.AtEnd) return null; DictionaryEntry entry = array.IntrinsicEnumerator.Entry; array.IntrinsicEnumerator.MoveNext(); // dereferences result since enumerator doesn't do so: object key = ((IntStringKey)entry.Key).Object; object value = PhpVariable.Dereference(entry.Value); // creates the resulting array: PhpArray result = new PhpArray(); result.Add(1, value); result.Add("value", value); result.Add(0, key); result.Add("key", key); // keys and values should be inplace deeply copied: result.InplaceCopyOnReturn = true; return result; }
public static PhpArray Split(object pattern, object data, int limit, SplitFlags flags) { if (limit == 0) // 0 does not make sense, php's behavior is as it is -1 limit = -1; if (limit < -1) // for all other negative values it seems that is as limit == 1 limit = 1; PerlRegExpConverter converter = ConvertPattern(pattern, null); if (converter == null) return null; string str = ConvertData(data, converter); Match m = converter.Regex.Match(str); bool offset_capture = (flags & SplitFlags.OffsetCapture) != 0; PhpArray result = new PhpArray(); int last_index = 0; while (m.Success && (limit == -1 || --limit > 0) && last_index < str.Length) { // add part before match int length = m.Index - last_index; if (length > 0 || (flags & SplitFlags.NoEmpty) == 0) result.Add(NewArrayItem(str.Substring(last_index, length), last_index, offset_capture)); if (m.Value.Length > 0) { if ((flags & SplitFlags.DelimCapture) != 0) // add all captures but not whole pattern match (start at 1) { List<object> lastUnsucessfulGroups = null; // value of groups that was not successful since last succesful one for (int i = 1; i < m.Groups.Count; i++) { Group g = m.Groups[i]; if (g.Length > 0 || (flags & SplitFlags.NoEmpty) == 0) { // the value to be added into the result: object value = NewArrayItem(g.Value, g.Index, offset_capture); if (g.Success) { // group {i} was matched: // if there was some unsuccesfull matches before, add them now: if (lastUnsucessfulGroups != null && lastUnsucessfulGroups.Count > 0) { foreach (var x in lastUnsucessfulGroups) result.Add(x); lastUnsucessfulGroups.Clear(); } // add the matched group: result.Add(value); } else { // The match was unsuccesful, remember all the unsuccesful matches // and add them only if some succesful match will follow. // In PHP, unsuccessfully matched groups are trimmed by the end // (regexp processing stops when other groups cannot be matched): if (lastUnsucessfulGroups == null) lastUnsucessfulGroups = new List<object>(); lastUnsucessfulGroups.Add(value); } } } } last_index = m.Index + m.Length; } else // regular expression match an empty string => add one character { // always not empty result.Add(NewArrayItem(str.Substring(last_index, 1), last_index, offset_capture)); last_index++; } m = m.NextMatch(); } // add remaining string (might be empty) if (last_index < str.Length || (flags & SplitFlags.NoEmpty) == 0) result.Add(NewArrayItem(str.Substring(last_index), last_index, offset_capture)); return result; }
public static PhpArray Filter(PHP.Core.Reflection.DTypeDesc caller, PhpArray array, PhpCallback callback) { if (callback == null) { PhpException.ArgumentNull("callback"); return null; } if (array == null) { PhpException.ArgumentNull("array"); return null; } PhpArray result = new PhpArray(); object[] args = new object[1]; foreach (KeyValuePair<IntStringKey, object> entry in array) { // no deep copying needed because it is done so in callback: args[0] = entry.Value; // adds entry to the resulting array if callback returns true: if (Core.Convert.ObjectToBoolean(callback.Invoke(caller, args))) { result.Add(entry.Key, entry.Value); } } // values should be inplace deeply copied: result.InplaceCopyOnReturn = true; return result; }
public static PhpArray Fill(int startIndex, int count, object value) { if (count <= 0) { PhpException.InvalidArgument("count", LibResources.GetString("arg:negative_or_zero")); return null; } PhpArray result = new PhpArray(count, 0); int last = startIndex + count; for (int i = startIndex; i < last; i++) result.Add(i, value); // makes deep copies of all added items: result.InplaceCopyOnReturn = true; return result; }
public static PhpArray Slice(PhpArray array, int offset, int length, bool preserveKeys) { if (array == null) { PhpException.ArgumentNull("array"); return null; } // absolutizes range: PhpMath.AbsolutizeRange(ref offset, ref length, array.Count); var iterator = array.GetBaseEnumerator(); // moves iterator to the first item of the slice; // starts either from beginning or from the end (which one is more efficient): if (offset < array.Count - offset) { for (int i = -1; i < offset; i++) iterator.MoveNext(); } else { for (int i = array.Count; i > offset; i--) iterator.MovePrevious(); } // copies the slice: PhpArray result = new PhpArray(length); int ikey = 0; for (int i = 0; i < length; i++) { KeyValuePair<IntStringKey, object> entry = iterator.Current; // integer keys are reindexed if preserveKeys is false, string keys are not touched: if (entry.Key.IsString) { result.Add(entry.Key, entry.Value); } else { if (!preserveKeys) result.Add(ikey++, entry.Value); else result.Add(entry.Key, entry.Value); } iterator.MoveNext(); } result.InplaceCopyOnReturn = true; return result; }
public static PhpArray FillKeys(PhpArray keys, object value) { if (keys == null) { PhpException.ArgumentNull("keys"); return null; } var result = new PhpArray(keys.Count); foreach (var x in keys) { IntStringKey key; if (Core.Convert.ObjectToArrayKey(x.Value, out key) && !result.ContainsKey(key)) { result.Add(key, value); } } // makes deep copies of all added items: result.InplaceCopyOnReturn = true; return result; }
public static PhpArray GetGenericArgs() { DTypeDesc[] type_descs = ScriptContext.CurrentContext.Stack.GetTypeArguments(); if (type_descs == null) return null; PhpArray result = new PhpArray(type_descs.Length, 0); foreach (DTypeDesc type_desc in type_descs) result.Add(type_desc.MakeFullName()); result.InplaceCopyOnReturn = true; return result; }
public static PhpArray Pad(PhpArray array, int length, object value) { if (array == null) { PhpException.ArgumentNull("array"); return null; } // number of items to add: int remains = Math.Abs(length) - array.Count; // returns unchanged array (or its deep copy if called from PHP): if (remains <= 0) return array; PhpArray result = new PhpArray(array.IntegerCount + remains, array.StringCount); // prepends items: if (length < 0) { while (remains-- > 0) result.Add(value); } // inserts items from source array // if a key is a string inserts it unchanged otherwise inserts value with max. integer key: foreach (KeyValuePair<IntStringKey, object> entry in array) { if (entry.Key.IsString) result.Add(entry.Key.String, entry.Value); else result.Add(entry.Value); } // appends items: if (length > 0) { while (remains-- > 0) result.Add(value); } // the result is inplace deeply copied on return to PHP code: result.InplaceCopyOnReturn = true; return result; }