Как вызвать функцию в себе?

Поскольку все они являются положительными целыми числами, большая часть повторений может быть удалена:

Таким образом, в качестве первого шага

(((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) || (b - (a + p) > 1))

становится

((a+p) <= b) && (a != 1) && (b >= p)) && ((b - (a + p) != 1) 

Для для ясности, это просто замена паттерна (foo == 0 || foo > 1) на foo != 1

Этот паттерн появляется дважды выше, один раз с foo = a и один раз с foo = (b - (a+p))

8
задан Josh Leitzel 23 October 2009 в 09:14
поделиться

6 ответов

Я бы не использовал рекурсивные функции для сценариев повтора (поскольку вы не используете повторно результат функции, бессмысленно использовать рекурсию) ... Это добавляет много ненужных накладных расходов. Сделайте что-нибудь вроде этого:

do {
    $key = ...; // Generate your key here...
} while (!$this->user_model->valid_key($key));

return $key;

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

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

25
ответ дан 5 December 2019 в 04:58
поделиться

Вам необходимо вернуть результат самовызова, иначе действительный ключ не будет возвращен после рекурсии.

return $this->key_generator($length);
5
ответ дан 5 December 2019 в 04:58
поделиться

но это заставляет функцию выполнять бесконечный цикл,

Если вы абсолютно хотите сохранить свою рекурсивную стратегию, вы должны определить конечный регистр. Например, вы можете определить счетчик, например так:

function key_generator($length = 4, $limit=5)
{
    if($limit === 0) {
         throw new YourException();
    }

    // I've subsequently left out the generating code,
    // which is not necesarry in this case

    $key = 'xxxx';

    if ($this->user_model->valid_key($key) == true)
    {
        return $key;
    }
    else
    {
        return $this->key_generator(4, ($limit-1));
    }
}

Однако также можно выполнять свой код итеративно ...

3
ответ дан 5 December 2019 в 04:58
поделиться

Если вы включите достаточно уникальности в подпрограмму генерации ключей, вы сможете в первую очередь избежать этой ситуации. Например, пусть процедура принимает во внимание текущую метку времени и локальное имя хоста и / или PID.

Такое недетерминированное зацикливание обычно свидетельствует о том, что какая-то часть слишком наивна. Это не хорошо. : -)


В любом случае, было бы неплохо поймать его и зарегистрировать какую-то ошибку, а не зависать и, наконец, отключиться:

    function key_generator($length = 4)
    {
        /* The $attempts_left clearly depends on how much trust 
           you give your key generation code combined with the key space size. */
        $attempts_left = pow(16, $length) * 2;
        /* ... just guessing, in case your key base is 16, i.e. [0-9a-z] for example */

        do {
            // ... key generation goes here ...
            $key = 'xxxx';
        } while ( $this->user_model->valid_key($key) == false && $attempts_left-- > 0 );

        if( $attempts_left < 1 )
            return false;
        else
            return $key;
    }
2
ответ дан 5 December 2019 в 04:58
поделиться

Почему бы вам просто не просканировать пространство значений ключа на предмет первого неиспользованного ключа? Требуется ключ для выполнения дополнительных ограничений помимо четырех символов длиной и уникальностью?

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

Если вы хотите, чтобы последующие вызовы не возвращали аналогичные ключи, вы можете сначала перетасовать базу данных ключей. Это будет означать, что вам нужно где-то хранить массив элементов 456976, 1679616, 7311616 или 14776336 (в зависимости от того, используется ли алфавит в виде символов с одним или двумя регистрами, с цифрами или без них).

1
ответ дан 5 December 2019 в 04:58
поделиться

Вы можете поместить свой код в цикл и определить ключ итеративно вместо рекурсивно .

Пример:

function key_generator($length = 4)
{
  do {
    $key = 'xxxx'; //TODO
    if (timeOutReached()) return InvalidKey;
  } while (!$this->user_model->valid_key($key))

  return $key;
}

Сам цикл не предотвращает бесконечный цикл, но, в отличие от вызова функции, он не занимает место в стеке, поэтому вы не рискуете переполнением стека .

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

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

Также убедитесь, что вы защищаете свой код от одновременного доступа. Что, если два экземпляра этой функции попытаются сгенерировать ключ и оба определят одно и то же? Используйте критические разделы или транзакции, чтобы ничего плохого не случилось.

1
ответ дан 5 December 2019 в 04:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: