preg_match_all('/\[.*?\]/', $string, $matches);
или
preg_match_all('/\[[^\[\]]*\]/', $string, $matches);
Первый прекращает сопоставление, как только видит закрывающую скобку, но он совпадает с открывающей скобкой, если видит первую То есть он будет соответствовать "[ [foo]"
, если он присутствует на входе.
Второй более надежный, потому что найдет только правильно сбалансированные квадратные скобки; т.е. они не могут содержать квадратные скобки. Если скобки могут быть вложенными, ни одно регулярное выражение не будет работать; это гораздо более сложная проблема.