Frage

Ich habe eine Funktion, die einen Schlüssel mit 4 Zeichen erzeugt, der für jedes Mal einzigartig sein muss. Dazu generiert die Funktion zuerst einen Schlüssel und überprüft dann eine Datenbanktabelle, um festzustellen, ob sie von jemand anderem verwendet wird.

Wenn es nicht verwendet wird, gibt es den Schlüssel zurück, sonst ruft es sich wieder auf, aber dies führt dazu, dass die Funktion eine unendliche Schleife ausführt, die ein Nein-Nein ist. Hier ist die ganze Funktion:

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

Was ist der richtige Weg, um die Funktion erneut aufzurufen?

Übrigens verwende ich Codesigniter, daher $this.

War es hilfreich?

Lösung

Ich würde keine rekursiven Funktionen für den Wiederholungs-Szenarios verwenden (da Sie das Ergebnis der Funktion nicht wiederverwenden, ist es sinnlos, eine Rekursion zu verwenden) ... es fügt viel unnötiger Gemeinkosten hinzu. So etwas tun:

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

return $key;

Wenn Sie sich in der Nähe der maximalen Anzahl von Schlüssel befinden, führt dies zu sehr langen Schleifenzeiten, sodass Sie möglicherweise eine maximale Grenze festlegen möchten.

Oh, und wenn dies in mehreren Threads gleichzeitig stattfindet und Sie eine Datenbank überprüfen, sollten Sie die Tabellenschreibersperrung implementieren, damit der gleiche Schlüssel nicht zweimal eingefügt werden kann. Vorzugsweise die Funktion, die überprüft, ob ein Schlüssel verfügbar ist sperren, überprüfen, und falls vorhanden schreiben in derselben Transaktion, um Kollisionen zu vermeiden.

Andere Tipps

Sie müssen das Ergebnis des Selbstanhängers zurückgeben, andernfalls wird der gültige Schlüssel nicht zurückgegeben, sobald er wiederholt wird.

return $this->key_generator($length);

Dies führt jedoch dazu, dass die Funktion eine unendliche Schleife ausführt.

Wenn Sie Ihre rekursive Strategie unbedingt beibehalten möchten, müssen Sie einen Endfall definieren. Zum Beispiel können Sie einen Zähler wie folgt definieren:

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

Es ist jedoch auch möglich, Ihren Code iterativ zu machen ...

Wenn Sie genug einschließen Einzigartigkeit In Ihrer Routine für die wichtigste Generation können Sie diese Situation möglicherweise überhaupt vermeiden. ZB die Routine berücksichtigt den aktuellen Zeitstempel und den lokalen Hostnamen und/oder die PID.

Das Schleifen in einer so nicht deterministischen Weise ist im Allgemeinen ein Beweis dafür, dass ein Teil zu naiv ist. Das ist nicht gut. :-)


Wie auch immer, es wäre zumindest eine gute Praxis, es zu fangen und einen Fehler zu protokollieren, anstatt die Anfrage zu hängen und schließlich das Timing herauszufinden:

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

Warum scannen Sie nicht einfach den Schlüsselwertraum für den ersten nicht verwendeten Schlüssel? Benötigt der Schlüssel, um zusätzliche Einschränkungen zu erfüllen, um vier Charaktere lang und einzigartig zu sein?

Sie können sich an die zuletzt zurückgegebene Taste erinnern, um das Scannen von dort bei nachfolgenden Anrufen wieder aufzunehmen.

Wenn Sie nachfolgende Anrufe nicht mehr ähnliche Schlüssel zurückgeben möchten, können Sie zuerst Ihre Schlüsseldatenbank mischen. Dies würde bedeuten, dass Sie einen 456976, 1679616, 7311616 oder 14776336 irgendwo (je nachdem, ob das verwendete Alphabet ein- oder doppelt-casiertes Zeichen mit oder ohne Ziffern sind) abzuhalten.

Sie können Ihren Code in eine Schleife einfügen und den Schlüssel bestimmen iterativ Anstatt vonrekursiv.

Beispiel:

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

  return $key;
}

Die Schleife selbst verhindert keine InfinTE -Schleife, aber im Gegensatz zu einem Funktionsaufruf frisst dies keinen Stapelraum, sodass Sie keinen Stapelüberlauf riskieren.

Außerdem vereinfacht es die Dinge ein wenig. Abhängig vom Typ des Schlüssels können Sie auch die Schlüsselgenerierungsmethode anpassen, beispielsweise mit nummerierten Schlüssel, die Sie mit jeder Iteration exponentiell erhöhen können.

Bemerkungen: Wenn dies möglich ist, verwenden Sie die automatische Inkrementfunktion einer Datenbank, anstatt Ihre eigene Funktion für die Schlüsselgenerierung zu rollen.

Stellen Sie außerdem sicher, dass Sie Ihren Code vor dem gleichzeitigen Zugriff schützen. Was ist, wenn zwei Instanzen dieser Funktion versuchen, einen Schlüssel zu generieren und beide dasselbe bestimmen? Verwenden Sie kritische Abschnitte oder Transaktionen, um sicherzustellen, dass nichts Schlimmes passiert.

Verwenden einer Funktion in sich selbst

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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top