The flag parameter of preg_match_all is complicated and confusing. The official document says the default value of flag is 0, which is wrong.

In fact, the flag parameter is defaulted to 1, i.e., PREG_PATTERN_ORDER. The matching result $matches in this case is an array. The first member of $matches is the array of strings that are matched by the parameter $pattern. The second member of $matches is the array of strings that are matched by the first sub-pattern. What is a sub-pattern? A sub-pattern is what is in brackets in the pattern parameter. There may be multiple pairs of brackets in the pattern so there may be multiple sub-patterns. The third member of $matches stores the matched strings by the second sub-pattern, and so on and so forth. So the $matches produced by the following code is:
preg_match_all("/(ab)c/s","abcdefgabchijabklm",$matches);
array(2) { [0]=> array(2) { [0]=> string(3) "abc" [1]=> string(3) "abc" } [1]=> array(2) { [0]=> string(2) "ab" [1]=> string(2) "ab" } }
There are 2 “abc”s in $matches[0](for the pattern), and there are two “ab”s in $matches[1](for the unique sub-pattern).
Another value of flag is PREG_SET_ORDER. This flag instructs preg_match_all to store the first matched content to the first member of $matches, the second matched content to the second member of $matches. Where do sub-patterns go? The content that match sub-patterns also go to the member of $matches, with the first match going to the first member of $matches, the second match going to the second match, etc.
In summary, for PREG_PATTERN_ORDER, the first member of result is for the first pattern, while for PREG_SET_ORDER, the first member of result is for the first occurrence of pattern.