Рекурсивная функция PHP не возвращает ожидаемое значение

Я пытаюсь создать функцию, которая создаст уникальное имя пользователя для каждого пользователя, хранящегося в базе данных.

Мой план состоял в том, чтобы создать имя пользователя, объединив имя и фамилию, а затем проверить, занято ли это имя пользователя. Если бы это было не просто сохранить его в базе данных, а если бы это было так, то добавить число в конце.

Например, если ConnorAtherton был занят, функция затем будет проверять ConnorAtherton1, ConnorAtherton2, пока не найдет уникальное имя пользователя.

Вот функция (я добавил несколько операторов эха для отладки)

    function createUserName($username, $counter){

        global $fname, $lname;

        echo "\t\t\tUsername at Start - " . $username . "\n";

        // connect to database
        require($_SERVER['DOCUMENT_ROOT'] . "/inc/db.connect.php");

        $stmt = $conn->prepare('SELECT * FROM users WHERE username = ?');
        $stmt->bind_param('s', $username); 
        $stmt->execute();
        $stmt->store_result();

        echo "\t\t\tUsername before loop - " . $username . "\n";

            if( $stmt->num_rows > 0){

                //construct original name and try again
                $username = ucfirst($fname) . ucfirst($lname) . $counter;
                $counter++;
                createUserName($username, $counter);

            }

            echo "\t\t\tUsername after loop - " . $username . "\n\n";

            return $username;
    }

Вот что он возвращает в консоль

    Username at Start - ConnorAtherton
    Username before loop - ConnorAtherton
    Username at Start - ConnorAtherton1
    Username before loop - ConnorAtherton1
    Username at Start - ConnorAtherton2
    Username before loop - ConnorAtherton2
    Username after loop - ConnorAtherton2

    Username after loop - ConnorAtherton1

Он возвращает правильное значение после цикла (ConnorAtherton2) для начала, но я не знаю, почему после цикла должно быть второе значение.

Он возвращает ConnorAtherton1, и мне нужно, чтобы он возвращал ConnorAtherton2.

Любая помощь приветствуется.


person Connor Atherton    schedule 08.03.2013    source источник
comment
Возможно, это не тот ответ, который вы ищете, но я бы подумал об изменении вашего sql для использования WHERE username LIKE "ConnorAtherton%", а затем подстроке последних цифр и добавлении 1 :)   -  person Julien    schedule 08.03.2013


Ответы (2)


Код выполняется, как и ожидалось. То, что вы видите, это просто раскручивание стека от рекурсивных вызовов.

Вы должны изменить свою функцию, чтобы выйти после рекурсивного вызова, возвращая результат рекурсивного вызова

     //...
    $counter++;
    return createUserName($username, $counter);
 }
 //... Rest of fn omitted
person Mike Dinescu    schedule 08.03.2013
comment
Большой. Я рад, что смог помочь! В связи с этим, как указывали другие, вы можете добиться того же без рекурсии, но понимание рекурсивных функций всегда может пригодиться;) - person Mike Dinescu; 08.03.2013

Вы можете достичь того, чего хотите, без рекурсии намного проще. Основная логика будет выглядеть так:

$counter = '';
do {
    $username = ucfirst($fname) . ucfirst($lname) . ($counter++);
} while(!doesNameExist($username));

Вам нужно будет только реализовать метод doesNameExist(). Там вы выполняете запрос к БД и возвращаете true, если имя уже существует.

Часть ($counter++) добавит пустую строку при первой итерации (суффикс ++ увеличивает переменную после оценки значения).

person Michael Härtl    schedule 08.03.2013
comment
Эй, Майкл, я согласен с вами, что это можно сделать без рекурсии, и ваше решение отлично работает. Я создал этот сценарий программирования, чтобы лучше понять, как работает рекурсия :) - person Connor Atherton; 08.03.2013
comment
Я понимаю. Но имейте в виду, что вам следует по возможности избегать рекурсивных вызовов — они обычно намного дороже, чем простой цикл. - person Michael Härtl; 08.03.2013
comment
@Michael - в качестве общего заявления я не могу с вами согласиться. Это действительно зависит от языка и задачи. В этом случае да, это излишество, но в других случаях рекурсия может быть действительно отличной! - person Mike Dinescu; 08.03.2013
comment
@Miky: Ты прав. Это зависит от того, является ли это линейным или итеративным рекурсивным процессом. Поэтому я должен перефразировать свое утверждение: в PHP я бы избегал этого, если есть более простое решение на основе цикла (что имеет место здесь). Но опять же, что проще ;) - person Michael Härtl; 08.03.2013