Pergunta

Eu tenho uma função que gera uma chave de 4 caracteres que devem ser únicos para cada vez. Para fazer isso, a função gera primeiro uma chave e depois verifica uma tabela de banco de dados para ver se está em uso por outra pessoa.

Se não estiver em uso, ele retorna a chave, caso contrário, ele se chama novamente, mas isso faz com que a função faça um loop infinito, que é um não-não. Aqui está toda a função:

function key_generator($length = 4)
{
    // 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
    {
        $this->key_generator(4);
    }
}

Qual é a maneira correta de chamar a função novamente?

A propósito, estou usando o CodeIgniter, daí $this.

Foi útil?

Solução

Eu não usaria funções recursivas para scenarios de repetição (como você não reutiliza o resultado da função, é inútil usar recursão) ... ela adiciona muita sobrecarga desnecessária. Faça algo assim:

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

return $key;

Se você estiver perto do número máximo de chaves, isso resultará em tempos de loop muito longos, portanto, você pode querer colocar algum tipo de limite máximo.

Ah, e se isso estiver ocorrendo em vários threads simultaneamente e você estiver verificando um banco de dados, você deve implementar o bloqueio de gravação da tabela para que a mesma chave não possa ser inserida duas vezes. De preferência a função que verifica se uma chave está disponível deve trancar, Verifica, e se disponível Escreva na mesma transação para evitar colisões.

Outras dicas

Você precisa devolver o resultado do auto-calmo; caso contrário, a chave válida não será retornada assim que for recusar.

return $this->key_generator($length);

Mas isso faz com que a função faça um loop infinito,

Se você absolutamente deseja manter sua estratégia recursiva, deve definir um caso final. Por exemplo, você pode definir um contador, assim:

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));
    }
}

No entanto, também é possível fazer seu código iterativamente ...

Se você incluir o suficiente singularidade Na sua rotina de geração -chave, você poderá evitar essa situação em primeiro lugar. Por exemplo, a rotina leva em consideração o registro de data e hora atual e o nome do host local e/ou o PID.

O loop de maneira tão não determinística geralmente é a prova de alguma parte ser muito ingênua. Isso não é bom. :-)


De qualquer forma, seria pelo menos uma boa prática pegá -lo e registrar algum tipo de erro, em vez de pendurar a solicitação e, finalmente, o tempo:

    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;
    }

Por que você não apenas digitaliza o espaço de valor -chave para a primeira chave não utilizada? Precisa da chave para cumprir restrições adicionais além de ter quatro caracteres de comprimento e único?

Você pode se lembrar da última chave devolvida para retomar a digitalização a partir daí em chamadas subsequentes.

Se você deseja que as chamadas subsequentes não retornem chaves semelhantes, poderá embaralhar seu banco de dados de chave primeiro. Isso significaria que você precisa segurar uma matriz de elementos 456976, 1679616, 7311616 ou 14776336 em algum lugar (dependendo se o alfabeto usado são caracteres de seleção única ou dupla, com ou sem dígitos).

Você pode colocar seu código em um loop e determinar a chave iterativamente ao invés derecursivamente.

Exemplo:

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

  return $key;
}

O loop em si não evita um loop de infinte, mas, diferentemente de uma chamada de função, isso não consome espaço para pilha, para que você não arrisque um transbordamento de pilha.

Também simplifica um pouco as coisas. Dependendo do tipo de chave, você também pode adaptar o método de geração de chaves, por exemplo, com teclas numeradas, você pode aumentar exponencialmente a cada iteração.

Observações: Se for possível, use o recurso de incremento automático de um banco de dados em vez de rolar seu próprio recurso de geração de chaves.

Também certifique -se de proteger seu código contra acesso simultâneo. E se duas instâncias dessa função tentarem gerar uma chave e ambas determinam o mesmo? Use seções ou transações críticas para garantir que nada de ruim aconteça.

Usando uma função dentro de si mesma

function test($val) {
    /*initialize return value by using the conditions*/
    if($val>=5){
        /*do something with return statement*/
        return $val+10;
    } else {
        /*set the return default value for avoid the error throwing*/
        return "default value";
    }
    /*return the function used for check the condition*/
    return test($val);
}

echo test(4);  // output "default value";
echo test(6);  //output 16
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top