<?php
function mergeResult($a, $b, $needJoin = true) {
	// fixme: увы не хватает времени на допилку...
    if (!$needJoin) return array_merge($a, $b);
    return array_map(function ($r) use ($a) {
        return mergeResult($a, $r, false);
    }, $b);
}

function buildLevel(array $words, $level) {
    // с первым уровнем все просто
    if ($level === 1) return [implode(' ', $words)];

    // со вторым чуть по сложнее...
    $result = [];
    $chunk = [];
    while(count($words) >= $level) {
        // отделяем первое слово из "строки" и зановим его к первому "слагаемому"
        array_push($chunk, array_shift($words));
        $result[] = mergeResult(buildLevel($chunk, 1), buildLevel($words, $level-1), $level > 2);
    }
	return $result;
}

$words = explode(' ', 'a b c d');
// я торопился по сему вот так...
var_export(buildLevel($words, 3));
var_export(buildLevel($words, 4));