Php 如何调用内部函数?

Php 如何调用内部函数?,php,function,codeigniter,recursion,Php,Function,Codeigniter,Recursion,我有一个函数,生成一个4个字符的键,每次都必须是唯一的。为了做到这一点,函数首先生成一个键,然后检查一个数据库表,看看是否有其他人在使用它 如果它不在使用中,它将返回键,否则,它将再次调用自身,但这会导致函数执行无限循环,这是一个禁忌。下面是整个函数: function key_generator($length = 4) { // I've subsequently left out the generating code, // which is not necesarry

我有一个函数,生成一个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

您可以将代码放入一个循环中,以迭代方式确定键,而不是 递归地

示例:

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

  return $key;
}
循环本身并不阻止infinte循环,但与函数调用不同,它不会占用堆栈空间,因此不会出现堆栈溢出的风险

它还简化了一些事情。根据密钥的类型,您还可以调整密钥生成方法,例如,对于编号的密钥,您可以在每次迭代中以指数方式增加

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

还要确保保护代码不受并发访问。如果此函数的两个实例尝试生成一个键,并且它们都确定相同的键,该怎么办?使用关键部分或事务来确保没有坏事情发生

但这会导致函数执行无限循环

如果你绝对想要保持你的递归策略,你必须定义一个结束案例。例如,您可以定义一个计数器,如下所示:

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));
    }
}
do {
    $key = ...; // Generate your key here...
} while (!$this->user_model->valid_key($key));

return $key;

但是,也可以迭代地执行代码…

我不会在重试场景中使用递归函数(因为您不重用函数的结果,所以使用递归是毫无意义的)。。。这会增加很多不必要的开销。这样做:

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));
    }
}
do {
    $key = ...; // Generate your key here...
} while (!$this->user_model->valid_key($key));

return $key;
如果您接近最大键数,这将导致非常长的循环时间,因此您可能需要设置某种最大限制


哦,如果这同时发生在多个线程上,并且您正在检查一个数据库,那么您应该实现表写锁定,这样同一个键就不能插入两次。最好是检查密钥是否可用的函数应锁定检查,如果可用,则在同一事务中写入,以避免任何冲突。

您需要返回自调用的结果,否则有效密钥将在其再次出现时无法返回

return $this->key_generator($length);
如果在密钥生成例程中包含足够多的唯一性,那么首先就可以避免这种情况。例如,让例程考虑当前时间戳和本地主机名和/或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;
    }
功能键\u生成器($length=4)
{
/*剩下的美元显然取决于信任程度
将密钥生成代码与密钥空间大小相结合*/
$trunts_left=pow(16,$length)*2;
/*…如果您的密钥基数为16,例如[0-9a-z],请仅进行猜测*/
做{
//…密钥生成在这里进行。。。
$key='xxxx';
}while($this->user\u model->valid\u key($key)=false&&$truments\u left-->0);
如果($u左<1)
返回false;
其他的
返回$key;
}

为什么不在键值空间中扫描第一个未使用的键?除了四个字符的长度和唯一性外,还需要密钥来满足其他限制条件吗

您可以记住最后一个返回的键,以便在随后的调用中从那里恢复扫描


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

使用内部函数

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

好的方面=)不过我不建议他在这种情况下使用递归。另外,$这不是CodeIgniter独有的。我想他只是在解释$this的来源以及为什么它没有在代码段中定义。$this用于对象/类范围。只要你的函数在一个类中,并且你正在调用它,那么你必须使用$this->functionName()。。或者self::functionName(),如果它是静态函数。等等,你是对的。这似乎是最好(也是最简单)的解决方案。谢谢在许多情况下,理想的解决方案只是小心地放置一些机制,以防止过长的循环。