2009-10-23 50 views
7

我有一个函数可以生成一个必须每次都是唯一的4个字符的密钥。为此,函数首先生成一个密钥,然后检查数据库表以查看其他人是否正在使用它。如何在自己内部调用函数?

如果它没有被使用,它会返回键,否则它会再次调用它自己,但是这会导致函数做一个无限循环,这是一个不允许的。这是整个功能:

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

什么是再次调用函数的正确方法?

顺便说一句,我使用CodeIgniter,因此$this

+2

它被称为递归 – Makach 2009-10-23 09:07:24

+1

此外,$这不是独家笨。 – 2009-10-23 09:14:18

+1

我想他只是解释$ this的来源以及为什么它没有在代码片段中定义。 – JAL 2009-10-24 03:59:52

回答

25

我不会用递归函数重试,场景(因为你不”不重用函数的结果,使用递归没有意义)...它增加了很多不必要的开销。做这样的事情:

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

return $key; 

如果你靠近按键的最大数量,这将导致很长的循环时间,所以你可能想要把某种最大限制。

哦,如果这是同时发生在多个线程上,并且您正在检查数据库,则应该实现表写入锁定,以便相同的密钥不能被插入两次。优选地,检查钥匙是否可用的功能应该是,检查,并且如果可用在相同的交易中写以避免任何冲突。

+0

你说得对。这似乎是最好的(也是最简单的)解决方案。谢谢! – 2009-10-23 09:19:39

+0

在许多情况下,理想的解决方案就是小心地放置一些机制来防止过长的循环。 – Stuart 2014-03-19 20:54:53

1

你可以把你的代码放到一个循环,并确定关键反复代替 递归

例子:

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

    return $key; 
} 

循环本身并不能阻止infinte环,但不像一个函数调用,这并不吃起来堆栈空间,所以你不要冒险堆栈溢出。

此外它简化了一些事情。根据密钥的类型,您还可以调整密钥生成方法,例如使用编号的密钥,每次迭代可以指数级增加。

备注:如果可能,请使用数据库的自动增量功能,而不是滚动您自己的密钥生成功能。

此外请确保您的代码不受并发访问的影响。如果这个函数的两个实例试图产生一个密钥并且它们都确定一致,会怎样?使用关键部分或交易来确保没有不好的事情发生。

2

,但是这会导致功能做一个无限循环,

如果你绝对要保持你的递归策略,你必须定义一个结束的情况下。例如,你可以定义一个计数器,就像这样:

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

然而,也有可能反复做你的代码...

5

您需要返回自我调用的结果,否则有效密钥一旦递归就不会返回。

return $this->key_generator($length); 
+0

好点=)我不会推荐他在这种情况下使用递归。 – Blixt 2009-10-23 09:08:02

2

如果您在您的密钥生成程序的足够独特,你也许能避免在首位这种情况。例如。例程会考虑当前时间戳和本地主机名和/或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; 
    } 
1

为什么不你只需扫描第一个未使用密钥的密钥值空间?需要在四个字符长和独特的基础上完成附加限制的关键?

您可以记住上次返回的密钥,以便在随后的调用中从此处继续进行扫描。

如果您希望后续调用不返回类似的密钥,则可以先洗牌您的密钥数据库。这意味着您需要在某处放置456976,1679616,7311616或14776336元素数组(取决于所使用的字母表是单字还是双字还是带或不带数字)。

0

内用自身的函数

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