private StringBuilder build(StringBuilder buff, ForeachIterator it) {
        final Deque<Memory> nesting = this.nesting;
        final boolean hasNesting = nesting != null && !nesting.isEmpty();
        boolean pollNested = false;

        while (it.next()) {
            Memory k = it.getMemoryKey();
            Memory v = it.getValue();

            if (v.isArray()) {
                lazyInitNesting().add(k);

                build(buff, v.toValue(ArrayMemory.class).foreachIterator(false, false));
                continue;
            }

            if (hasNumericPrefix) {
                // nesting.peek() can't throw NPE, due guard variable hasNesting.
                //noinspection ConstantConditions
                if ((hasNesting && isNumeric(nesting.peek())) || (!hasNesting && isNumeric(k))) {
                    buff.append(numericPrefix);
                }
            }

            if (hasNesting) {
                // setting this flag to poll it after loop
                pollNested = true;
                // add current key
                nesting.offer(k);

                Iterator<Memory> nestedIt = nesting.iterator();
                buff.append(nestedIt.next());

                while (nestedIt.hasNext()) {
                    appendArrayKey(buff, nestedIt.next());
                }

                // remove current key
                nesting.pollLast();
            } else {
                buff.append(k.toString());
            }

            buff.append('=').append(v.isBoolean() ? v.toInteger() : encoder.apply(v)).append(argSeparator);
        }

        if (pollNested) {
            nesting.pollLast();
        }

        return buff;
    }
We should keep trace when traversing arrays.
exts/jphp-zend-ext/src/main/java/org/develnext/jphp/zend/ext/standard/HttpQueryBuilder.java