Пример #1
0
		private PhpCallback/*!*/ GetOrCreateFilterCallback(ScriptContext/*!*/ context)
		{
			if (filterCallback == null)
				filterCallback = new PhpCallback(new RoutineDelegate(Filter), context);

			return filterCallback;
		}
Пример #2
0
        /// <summary>
        /// Invoke the specified method and args.
        /// </summary>
        /// <param name="method">Method.</param>
        /// <param name="args">Arguments.</param>
        /// <param name="func">Func.</param>
        public override object Invoke(string func, params object[] args)
        {
            try
            {
                if (State == PluginState.Loaded && Globals.Contains(func))
                {
                    object result = (object)null;

                    using (new Stopper(Name, func))
                    {
                        var caller = new PhpCallback(Class, func);
                        result = caller.Invoke(args);
                    }
                    return result;
                }
                else
                {
                    Logger.LogWarning("[Plugin] Function: " + func + " not found in plugin: " + Name + ", or plugin is not loaded.");
                    return null;
                }
            }
            catch (Exception ex)
            {
                string fileinfo = (String.Format("{0}<{1}>.{2}()", Name, Type, func) + Environment.NewLine);
                Logger.LogError(fileinfo + FormatException(ex));
                return null;
            }
        }
Пример #3
0
        static void Main(string[] args)
        {
            ScriptContext context = ScriptContext.InitApplication(ApplicationContext.Default, null, null, null);

            var sb = new StringBuilder();
            using (TextWriter tw = new StringWriter(sb))
            {
                context.Output = tw;
                context.OutputStream = Console.OpenStandardOutput(); //TODO: Should also redirect binary output.

                context.Include("main.php", true);

                var klass = (PhpObject)context.NewObject("Klass", new object[] { "yipppy" });
                var foo = new PhpCallback(klass, "foo");
                foo.Invoke(null, new object[] { "param" });

                tw.Close();
            }

            string output = sb.ToString();
            const string EXPECTED = "yipppyparam";
            if (output != EXPECTED)
            {
                Console.WriteLine("FAIL");
                Console.Write("Expected: " + EXPECTED);
                Console.Write("Got: ");
                Console.WriteLine(output);
            }
            else
            {
                Console.WriteLine("PASS");
            }
        }
Пример #4
0
		public static object CallUserFunction(DTypeDesc caller, PhpCallback function, params object[] args)
		{
			if (function == null)
			{
				PhpException.ArgumentNull("function");
				return null;
			}
			if (function.IsInvalid) return null;

			// invoke the callback:
			return PhpVariable.Dereference(function.Invoke(caller, args));
		}
Пример #5
0
        internal static void InvokeHeaderFunction(this HttpWebResponse response, PhpCurlResource curlResource, PhpCallback headerFunction)
        {
            StringBuilder builder = new StringBuilder(HTTP_HEADER_ROW_LENGTH);
            int startIndex = 0;

            IterateHtppHeaders(response, ref builder,
                delegate(ref StringBuilder sb)
                {
                    headerFunction.Invoke(curlResource, sb.ToString(startIndex, sb.Length - startIndex));
                    startIndex = sb.Length;
                }
                );

        }
Пример #6
0
		public static bool CreateClrThread(ScriptContext/*!*/context, PhpCallback/*!*/ callback, params object[] args)
		{
			if (callback == null)
				PhpException.ArgumentNull("callback");

			if (!callback.Bind())
				return false;

			object[] copies = (args != null) ? new object[args.Length] : ArrayUtils.EmptyObjects;

			for (int i = 0; i < copies.Length; i++)
				copies[i] = PhpVariable.DeepCopy(args[i]);

            return ThreadPool.QueueUserWorkItem(new Worker(context, copies).Run, callback);
		}
Пример #7
0
        public static object CallUserFunctionArray(DTypeDesc caller, PhpCallback function, PhpArray args)
		{
			object[] args_array;

            if (args != null)
            {
                args_array = new object[args.Count];
                args.CopyValuesTo(args_array, 0);
            }
            else
            {
                args_array = ArrayUtils.EmptyObjects;
            }

			return CallUserFunction(caller, function, args_array);
		}
Пример #8
0
            public void BindOrBiteMyLegsOff(DTypeDesc caller, NamingContext namingContext)
            {
                if (Callback != null)
                {
                    if (Callback.TargetInstance == null && Parser._handlerObject != null)
                        _currentCallback = new PhpCallback(Parser._handlerObject, Callback.RoutineName);
                    else
                        _currentCallback = Callback;

                    Bound = _currentCallback.Bind(true, caller, namingContext);
                }
                else
                {
                    Bound = false;
                }
            }
Пример #9
0
        public string Highlight(string code, string language)
        {
            ScriptContext context = ScriptContext.CurrentContext;

            // redirect PHP output to the console:
            context.Output = Console.Out; // Unicode text output
            context.OutputStream = Console.OpenStandardOutput(); // byte stream output

            context.Include("geshi.php", true);

            var geshi = (PhpObject)context.NewObject("GeSHi", code, language);
            var result = new PhpCallback(geshi, "parse_code").Invoke();
            var error = new PhpCallback(geshi, "error").Invoke();
            new PhpCallback(geshi, "enable_keyword_links").Invoke(false);

            return result.ToString();
        }
Пример #10
0
        public static int Apply(ScriptContext/*!*/context, PHP.Core.Reflection.DTypeDesc caller, Iterator/*!*/iterator, PhpCallback function, PhpArray args)
        {
            // check parameters:
            Debug.Assert(context != null);
            Debug.Assert(iterator != null, "Phalanger should not pass a null here.");

            if (function == null)
            {
                PhpException.ArgumentNull("function");
                return -1;
            }

            // copy args into object array:
            object[] args_array;

            if (args != null)
            {
                args_array = new object[args.Count];
                args.Values.CopyTo(args_array, 0);
            }
            else
            {
                args_array = ArrayUtils.EmptyObjects;
            }

            // iterate through the iterator:
            int n = 0;
            
            iterator.rewind(context);
            
            while (PHP.Core.Convert.ObjectToBoolean(iterator.valid(context)))
            {
                if (!PHP.Core.Convert.ObjectToBoolean(function.Invoke(caller, args_array)))
                    break;
		        n++;

		        iterator.next(context);
	        }

            // return amount of iterated elements:
            return n;
        }
Пример #11
0
        public static void LoadFile(string path, PhpCallback function)
        {
            string file = string.Empty;

            if (function == null)
            {
                PhpException.ArgumentNull("function");
                return;
            }
            if (function.IsInvalid) return;

            WebClient webclient = new WebClient();
            webclient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(
                delegate(object sender, DownloadStringCompletedEventArgs downEventArgs)
                {
                    var canvas = ((ClrObject)ScriptContext.CurrentContext.AutoGlobals.Canvas.Value).RealObject as System.Windows.Controls.Canvas;

                    canvas.Dispatcher.BeginInvoke(() =>
                        {
                            function.Invoke(downEventArgs.Result);

                        });
                }
                );

            var source_root = ((ClrObject)ScriptContext.CurrentContext.AutoGlobals.Addr.Value).RealObject as string;

            Uri baseUri = new Uri(source_root + "/", UriKind.Absolute);
            Uri uriFile = new Uri(path, UriKind.RelativeOrAbsolute);
            Uri uri = new Uri(baseUri, uriFile);


            webclient.DownloadStringAsync(uri);

            //downloadFinished.WaitOne();

            //return XamlReader.Load(file);

        }
Пример #12
0
		/// <summary>
		/// Visits an entyr of array which <see cref="Walk"/> or <see cref="WalkRecursive"/> is walking through.
		/// </summary>
		private static void VisitEntryOnWalk(PHP.Core.Reflection.DTypeDesc caller, KeyValuePair<IntStringKey, object> entry, IDictionary<IntStringKey, object> array,
			PhpCallback callback, object[] args)
		{
			PhpReference ref_item = entry.Value as PhpReference;

			// fills arguments for the callback:
			((PhpReference)args[0]).Value = (ref_item != null) ? ref_item.Value : entry.Value;
			args[1] = entry.Key.Object;

			// invoke callback:
            Core.Convert.ObjectToBoolean(callback.Invoke(caller, args));

			// loads a new value from a reference:
			if (ref_item != null)
			{
				ref_item.Value = ((PhpReference)args[0]).Value;
			}
			else
			{
				array[entry.Key] = ((PhpReference)args[0]).Value;
			}
		}
Пример #13
0
		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;
		}
Пример #14
0
		public static bool WalkRecursive(PHP.Core.Reflection.DTypeDesc caller, [PhpRw] PhpHashtable array, PhpCallback callback, object data)
		{
			object[] args = PrepareWalk(array, callback, data);
			if (args == null) return false;

			using (PhpHashtable.RecursiveEnumerator iterator = array.GetRecursiveEnumerator(true,false))
			{
				while (iterator.MoveNext())
				{
					// visits the item unless it is an array or a reference to an array:
					PhpReference ref_value = iterator.Current.Value as PhpReference;
					if (!(iterator.Current.Value is PhpHashtable || (ref_value != null && ref_value.Value is PhpHashtable)))
						VisitEntryOnWalk(caller, iterator.Current, iterator.CurrentTable, callback, args);
				}
			}
			return true;
		}
Пример #15
0
		/// <summary>
		/// Prepares a walk for <see cref="Walk"/> and <see cref="WalkRecursive"/> methods.
		/// </summary>
        /// <exception cref="PhpException"><paramref name="callback"/> or <paramref name="array"/> are <B>null</B> references.</exception>
		private static object[] PrepareWalk(IDictionary array, PhpCallback callback, object data)
		{
			if (callback == null) { PhpException.ArgumentNull("callback"); return null; }
			if (array == null) { PhpException.ArgumentNull("array"); return null; }

			// prepares an array of callback's arguments (no deep copying needed because it is done so in callback):
			if (data != null)
				return new object[3] { new PhpReference(), null, data };
			else
				return new object[2] { new PhpReference(), null };
		}
Пример #16
0
        public static object Replace(ScriptContext/*!*/context, object pattern, PhpCallback callback, object data, int limit, out int count)
		{
			count = 0;
			return Replace(context, null, null, pattern, null, callback, data, limit, ref count);
		}
Пример #17
0
		public static bool WalkRecursive(PHP.Core.Reflection.DTypeDesc caller, [PhpRw] PhpHashtable array, PhpCallback callback)
		{
			return WalkRecursive(caller, array, callback, null);
		}
Пример #18
0
		public static void RegisterTickFunction(PhpCallback function, object arg)
		{
			PhpException.FunctionNotSupported();
		}
Пример #19
0
		/// <summary>
		/// Private mehtod implementing all replace methods. Just one of <paramref name="replacement"/> or <paramref name="callback" /> should be used.
		/// </summary>
        /// <param name="context">Current <see cref="ScriptContext"/>. Must not be null.</param>
        /// <param name="self">Instance of object that called the replace method (replace pattern may contain $this)</param>
        /// <param name="definedVariables"></param>
        /// <param name="pattern"></param>
        /// <param name="replacement"></param>
        /// <param name="callback"></param>
        /// <param name="data"></param>
        /// <param name="limit"></param>
        /// <param name="count"></param>
		/// <returns>String or an array.</returns>
		private static object Replace(ScriptContext/*!*/context, DObject self, Dictionary<string, object> definedVariables, object pattern, object replacement, PhpCallback callback,
			object data, int limit, ref int count)
		{
			// if we have no replacement and no callback, matches are deleted (replaced by an empty string)
			if (replacement == null && callback == null)
				replacement = String.Empty;

			// exactly one of replacement or callback is valid now
			Debug.Assert(replacement != null ^ callback != null);

			// get eval info if it has been captured - is needed even if we do not need them later
            SourceCodeDescriptor descriptor = context.GetCapturedSourceCodeDescriptor();

			// PHP's behaviour for undocumented limit range
			if (limit < -1)
				limit = 0;
            
            PhpArray replacement_array = replacement as PhpArray;

			string replacement_string = null;
			if (replacement_array == null && replacement != null)
				replacement_string = Core.Convert.ObjectToString(replacement);

			// we should return new array, if there is an array passed as subject, it should remain unchanged:
			object data_copy = PhpVariable.DeepCopy(data);

            PhpArray pattern_array = pattern as PhpArray;
            if (pattern_array == null)
            {
                // string pattern
                // string replacement

                if (replacement_array != null)
                {
                    // string pattern and array replacement not allowed:
                    PhpException.InvalidArgument("replacement", LibResources.GetString("replacement_array_pattern_not"));
                    return null;
                }

                // pattern should be treated as string and therefore replacement too:
                return SimpleReplace(self, definedVariables, pattern, replacement_string, callback, data_copy, limit, descriptor, ref count);
            }
            else if (replacement_array == null)
            {
                // array  pattern
                // string replacement

                using (var pattern_enumerator = pattern_array.GetFastEnumerator())
                    while (pattern_enumerator.MoveNext())
                    {
                        data_copy = SimpleReplace(self, definedVariables, pattern_enumerator.CurrentValue, replacement_string,
                                    callback, data_copy, limit, descriptor, ref count);
                    }
            }
            else //if (replacement_array != null)
            {
                // array pattern
                // array replacement

                var replacement_enumerator = replacement_array.GetFastEnumerator();
                bool replacement_valid = true;

                using (var pattern_enumerator = pattern_array.GetFastEnumerator())
                    while (pattern_enumerator.MoveNext())
                    {
                        // replacements are in array, move to next item and take it if possible, in other case take empty string:
                        if (replacement_valid && replacement_enumerator.MoveNext())
                        {
                            replacement_string = Core.Convert.ObjectToString(replacement_enumerator.CurrentValue);
                        }
                        else
                        {
                            replacement_string = string.Empty;
                            replacement_valid = false;  // end of replacement_enumerator, do not call MoveNext again!
                        }

                        data_copy = SimpleReplace(self, definedVariables, pattern_enumerator.CurrentValue, replacement_string,
                                    callback, data_copy, limit, descriptor, ref count);
                    }
            }
            
			// return resulting array or string assigned to data
			return data_copy;
		}
Пример #20
0
        public static PhpArray Map(PHP.Core.Reflection.DTypeDesc caller, PhpCallback map, [PhpRw] params PhpArray[] arrays)
		{
			if (!PhpArgument.CheckCallback(map, caller, "map", 0, true)) return null;
			if (arrays == null || arrays.Length == 0)
			{
				PhpException.InvalidArgument("arrays", LibResources.GetString("arg:null_or_emtpy"));
				return null;
			}

			// if callback has not been specified uses the default one:
			if (map == null)
				map = new PhpCallback(new RoutineDelegate(MapIdentity), ScriptContext.CurrentContext);

			int count = arrays.Length;
			bool preserve_keys = count == 1;
			PhpReference[] args = new PhpReference[count];
			IEnumerator<KeyValuePair<IntStringKey, object>>[] iterators = new IEnumerator<KeyValuePair<IntStringKey, object>>[count];
			PhpArray result;

			// initializes iterators and args array, computes length of the longest array:
			int max_count = 0;
			for (int i = 0; i < arrays.Length; i++)
			{
                var array = arrays[i];

                if (array == null)
                {
                    PhpException.Throw(PhpError.Warning, LibResources.GetString("argument_not_array", i + 2));// +2 (first arg is callback) 
                    return null;
                }

				args[i] = new PhpReference();
                iterators[i] = array.GetEnumerator();
                if (array.Count > max_count) max_count = array.Count;
			}

			// keys are preserved in a case of a single array and re-indexed otherwise:
			if (preserve_keys)
				result = new PhpArray(arrays[0].IntegerCount, arrays[0].StringCount);
			else
				result = new PhpArray(max_count, 0);

			for (; ; )
			{
				// fills args[] with items from arrays:
				for (int i = 0; i < arrays.Length; i++)
				{
					if (iterators[i] != null)
					{
						// an element is available:
						if (iterators[i].MoveNext())
						{
							// note: deep copy is not necessary since a function copies its arguments if needed:
                            object value = iterators[i].Current.Value;
                            PhpReference valueref = (value != null) ? value as PhpReference : null;
                            args[i].Value = (valueref != null) ? valueref.value : value;
                            //args[i].Value = iterators[i].Current.Value; // TODO: throws if the current Value is PhpReference
						}
						else
						{
							// the i-th iterator has stopped:
							count--;
							iterators[i] = null;
							args[i].Value = null;
						}
					}
				}

				if (count == 0) break;

				// invokes callback:
				object return_value = map.Invoke(args);

				// return value is not deeply copied:
				if (preserve_keys)
					result.Add(iterators[0].Current.Key, return_value);
				else
					result.Add(return_value);

				// loads new values (callback may modify some by ref arguments):
				for (int i = 0; i < arrays.Length; i++)
				{
					if (iterators[i] != null)
					{
						object item = iterators[i].Current.Value;
						PhpReference ref_item = item as PhpReference;
						if (ref_item != null)
						{
							ref_item.Value = args[i].Value;
						}
						else
						{
							arrays[i][iterators[i].Current.Key] = args[i].Value;
						}
					}
				}
			}

			return result;
		}
Пример #21
0
		/// <summary>
		/// There have to be at least 1 value in <paramref name="vars"/>.
		/// The last is converted to callback, the rest to arrays.
		/// </summary>
		private static bool SplitArraysAndComparers(int comparerCount, PhpArray array, object[] vars,
		  out PhpArray[] arrays, out PhpCallback cmp1, out PhpCallback cmp2)
		{
			arrays = null;
			cmp1 = cmp2 = null;

			if (vars == null || vars.Length == 0)
			{
				PhpException.InvalidArgumentCount(null, null);
				return false;
			}

			// the first callback:
			cmp1 = Core.Convert.ObjectToCallback(vars[vars.Length - comparerCount]);
            if (!PhpArgument.CheckCallback(cmp1, PHP.Core.Reflection.UnknownTypeDesc.Singleton/*(J): TBD pass caller from library func when this will be performance issue*/, null, vars.Length - comparerCount + 3, false))
				return false;

			// the second callback:
			if (comparerCount > 1)
			{
				cmp2 = Core.Convert.ObjectToCallback(vars[vars.Length - 1]);
                if (!PhpArgument.CheckCallback(cmp2, PHP.Core.Reflection.UnknownTypeDesc.Singleton/*(J): TBD pass caller from library func when this will be performance issue*/, null, vars.Length - comparerCount + 3, false))
					return false;
			}

			// remaining arguments should be arrays:
			arrays = new PhpArray[vars.Length - comparerCount + 1];
			arrays[0] = array;
			for (int i = 0; i < vars.Length - comparerCount; i++)
			{
				arrays[i + 1] = vars[i] as PhpArray;
				if (arrays[i + 1] == null)
				{
					PhpException.Throw(PhpError.Warning, LibResources.GetString("argument_not_array", i + 3));
					return false;
				}
			}

			return true;
		}
Пример #22
0
        public static bool UserKeySort(PHP.Core.Reflection.DTypeDesc caller, [PhpRw] PhpArray array, PhpCallback compare)
		{
			if (array == null) { PhpException.ReferenceNull("array"); return false; }
            if (!PhpArgument.CheckCallback(compare, caller, "compare", 0, false)) return false;

			array.Sort(new KeyComparer(new PhpUserComparer(compare), false));

            return true;
		}
Пример #23
0
        public static bool UserAssocSort(PHP.Core.Reflection.DTypeDesc caller, [PhpRw] PhpArray array, PhpCallback compare)
		{
			if (array == null) { PhpException.ReferenceNull("array"); return false; }
			if (!PhpArgument.CheckCallback(compare, caller, "compare", 0, false)) return false;

			// sorts array using callback for comparisons:
			array.Sort(new ValueComparer(new PhpUserComparer(compare), false));

            return true;
		}
Пример #24
0
		/// <summary>
		/// Takes a regular expression <paramref name="pattern"/> and one of <paramref name="replacement"/> or 
		/// <paramref name="callback"/>. Performs replacing on <paramref name="data"/>, which can be
		/// <see cref="PhpArray"/>, in other cases it is converted to string.
		/// If <paramref name="data"/> is <see cref="PhpArray"/>, every value is converted to string and
		/// replacement is performed in place in this array.
		/// Either <paramref name="replacement"/> or <paramref name="callback"/> should be null.
		/// </summary>
		/// <param name="self">Instance of object that called the replace method (replace pattern may contain $this)</param>
		/// <param name="definedVariables">Array with local variables - can be used by replace pattern</param>
		/// <param name="pattern">Regular expression to search.</param>
		/// <param name="replacement">Regular replacement expression. Should be null if callback is specified.</param>
		/// <param name="callback">Callback function that should be called to make replacements. Should be null
		/// if replacement is specified.</param>
		/// <param name="data">Array or string where pattern is searched.</param>
		/// <param name="limit">Max count of replacements for each item in subject.</param>
		/// <param name="descriptor"><see cref="SourceCodeDescriptor"/> for possible lambda function creation.</param>
		/// <param name="count">Cumulated number of replacements.</param>
		/// <returns></returns>
		private static object SimpleReplace(DObject self, Dictionary<string, object> definedVariables, object pattern, 
			string replacement, PhpCallback callback, object data, int limit, SourceCodeDescriptor descriptor, ref int count)
		{
			Debug.Assert(limit >= -1);

			// exactly one of replacement or callback is valid:
			Debug.Assert(replacement != null ^ callback != null);

			PerlRegExpConverter converter = ConvertPattern(pattern, replacement);
			if (converter == null) return null;

			// get types of data we need:
			PhpArray data_array = data as PhpArray;
			string data_string = (data_array == null) ? ConvertData(data, converter) : null;

			// data comprising of a single string:
            if (data_array == null)
            {
                return ReplaceInternal(self, definedVariables, converter, callback, data_string, limit, descriptor, ref count);
            }
            else
            {
                // data is array, process each item:
                var enumerator = data_array.GetFastEnumerator();
                while (enumerator.MoveNext())
                {
                    enumerator.CurrentValue = ReplaceInternal(self, definedVariables, converter, callback,
                        ConvertData(enumerator.CurrentValue, converter), limit, descriptor, ref count);
                }
                enumerator.Dispose();

                // return array with items replaced:
                return data;
            }
		}
Пример #25
0
		public static void RegisterShutdownFunction(PhpCallback/*!*/ function, params object[] parameters)
		{
			if (function == null)
			{
				PhpException.ArgumentNull("function");
				return;
			}

			ScriptContext.CurrentContext.RegisterShutdownCallback(function, parameters);
		}
Пример #26
0
        public static object Reduce(PHP.Core.Reflection.DTypeDesc caller, [PhpRw] PhpArray array, PhpCallback function, [PhpDeepCopy] object initialValue)
		{
			if (array == null) { PhpException.ReferenceNull("array"); return null; }
			if (!PhpArgument.CheckCallback(function, caller, "function", 0, false)) return null;
			if (array.Count == 0) return initialValue;

			object[] args = new object[] { initialValue, null };
			PhpReference holder = new PhpReference();

			foreach (KeyValuePair<IntStringKey, object> entry in array)
			{
				object item = entry.Value;
				PhpReference ref_item = item as PhpReference;

				// array item is a reference:
				if (ref_item != null)
				{
					args[1] = item;
					args[0] = function.Invoke(args);
				}
				else
				{
					// array item is not a reference:

					holder.Value = item;
					args[1] = holder;
					args[0] = function.Invoke(args);

					// updates an item if it has been changed:
					if (item != holder.Value)
						array[entry.Key] = holder.Value;
				}
			}

			// dereferences the last returned value:
			return PhpVariable.Dereference(args[0]);
		}
Пример #27
0
		public static void UnregisterTickFunction(PhpCallback function)
		{
			PhpException.FunctionNotSupported();
		}
Пример #28
0
        public static bool Walk(PHP.Core.Reflection.DTypeDesc caller, [PhpRw] PhpHashtable array, PhpCallback function)
		{
			return Walk(caller, array, function, null);
		}
Пример #29
0
        public static object Reduce(PHP.Core.Reflection.DTypeDesc caller, [PhpRw] PhpArray array, PhpCallback function)
		{
			return Reduce(caller, array, function, null);
		}
Пример #30
0
        public static bool Walk(PHP.Core.Reflection.DTypeDesc caller, [PhpRw] PhpHashtable array, PhpCallback callback, object data)
		{
			object[] args = PrepareWalk(array, callback, data);
			if (args == null) return false;

			foreach (KeyValuePair<IntStringKey, object> entry in array)
			{
				VisitEntryOnWalk(caller, entry, array, callback, args);
			}

			return true;
		}