Adding prefixes to headers in markdown
I may not be considering all fringe cases (please enlighten me if this breaks with any realistic input), but all of the logic can be packed into a single preg_replace_callback() call.


I start by declaring a 1-dimensional array which will contain all numeric counters.
My pattern ~^(#+)\K~m says:
From the start of each line, capture one or more hash symbols as capture group #1, then restart the fullstring match .  In doing so, my replacement string to be determined inside the custom function will not actually be replacing any characters, but adding new characters at the zero-length position marked by \K.  This spares you needing to match the rest of the line and adding that to the replacement.
Making $levels modifiable by reference with &amp; means that $level will be updated with each iteration of the regex matches.
After counting the elements in $levels and counting the length of the matched string, precise modifications can be done to $levels to provide the desired set of numbers.
The return value is a space followed by the dot-imploded $levels array.
array_slice() avoids poping in a loop.
I don't think your array_values() call is necessary.


Code: (Demo)

$headers = &lt;&lt;&lt;HEADERS
# Hello

## World

### Let's add

## Some headers

### Yay!

# Foo

## Bar

## Bar Again
HEADERS;

$levels = [];
echo preg_replace_callback(
        '~^(#+)\K~m',
        function($m) use (&amp;$levels) {
            $hashes = strlen($m[1]);
            $index = $hashes - 1;
            $reduction = sizeof($levels) - $hashes;
            if (!isset($levels[$index])) {
                $levels[$index] = 1;
            } else {
                ++$levels[$index];
            }
            if ($reduction &gt; 0) {
                $levels = array_slice($levels, 0, -$reduction);
            }
            return " " . implode('.', $levels);
        },
        $headers
    );


Output:

# 1 Hello

## 1.1 World

### 1.1.1 Let's add

## 1.2 Some headers

### 1.2.1 Yay!

# 2 Foo

## 2.1 Bar

## 2.2 Bar Again