Чистое рекурсивное решение
У вас уже есть один, но я сделаю еще один поворот, который выглядит "чище" для моих глаз, а также объясню, как я туда попал.
Вот код:
function create_all_dirs($directory, $map) {
// 1: TERMINATION CONDITION
if (empty($map)) {
mkdir($directory, 0755, true);
return;
}
// 2: PROCESS PART OF DATA, PREPARE DATA TO PASS ON RECURSION
$parts = explode('/', $map);
$partLength = strlen(array_shift($parts));
$dirCount = pow(16, $partLength);
$map = implode('/', $parts);
// 3: RECURSE
for($i = 0; $i < $dirCount; ++$i) {
$dir = $directory.DIRECTORY_SEPARATOR
.sprintf('%0'.$partLength.'s', dechex($i));
create_all_dirs($dir, $map);
}
}
Объяснение
Хотя я даже не буду предполагать, что есть один хороший способ достижения решения для рекурсивных функций, я могу объяснить подход, который хорошо сработал для меня на практике.
Шаг 1: Подумайте, какие данные вам нужно будет передать при повторении.
В этом случае каждый уровень функции будет отвечать за создание одного уровня структуры каталогов. Так что имеет смысл, что если вы позвоните
create_all_dirs('c:/', '#/#')
тогда в какой-то момент функция сделает рекурсивный вызов, который выглядит следующим образом:
create_all_dirs('c:/0', '#')
Это все, что вам нужно определить на этом этапе. Вы можете сказать, что это имеет смысл и что после последовательности таких вызовов функция будет (каким-то образом, мы ее еще не написали) выполнить свою работу.
Шаг 2: Условие завершения
Обладая этими знаниями, определите условие завершения вашей функции. В нашем случае, учитывая вышеизложенное, разумным условием завершения будет «когда вторым параметром является пустая строка». Так что бы сделала функция, если бы она вызывалась с каталогом и пустой строкой «map»?
function create_all_dirs($directory, $map) {
if(empty($map)) {
mkdir($directory, 0755, true);
return;
}
// ???
}
Очевидно, это должно создать каталог. Я звоню mkdir
таким образом, что он будет рекурсивно создавать все каталоги на пути, если они еще не существуют, потому что окончательное решение должно работать, но это не обязательно. Вы уже знаете, как это сделать без этого удобства.
Шаг 3: Подготовьте параметры, общие для всех рекурсивных вызовов
ОК, так что нам нужно сделать рекурсивный вызов? Вы уже знаете, что на каждом уровне нам нужно вытолкнуть часть строки $map
и несколько раз вызвать функцию рекурсивно. Нам также нужно передать ему новую, более глубокую строку каталога и новую, более короткую строку карты (все это вы можете узнать из завершения шага 1, даже если вы еще не создали решение).
Итак, мы имеем:
// cut off part of $map; we also need the length of the part we cut
// off, to know how many times we need to recursively call at this level
$parts = explode('/', $map);
$partLength = strlen(array_shift($parts));
// how many recursive calls?
$dirCount = pow(16, $partLength);
// this will be the $map parameter for all recursive calls
$map = implode('/', $parts);
Шаг 4. Вызов функции рекурсивно
На данный момент я не думаю, что есть что-то еще, чтобы объяснить. Мы вычисляем значение $directory
, которое отличается для каждого рекурсивного вызова, и делаем его:
for($i = 0; $i < $dirCount; ++$i) {
$dir = $directory.DIRECTORY_SEPARATOR
.sprintf('%0'.$partLength.'s', dechex($i));
create_all_dirs($dir, $map);
}