php 如何在自身内部调用函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1612200/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to call a function inside itself?
提问by rebellion
I have a function that generates a key of 4 characters that has to be unique for each time. In order to do that, the function first generates a key, and then checks a database table to see if it's in use by someone else.
我有一个函数可以生成一个 4 个字符的键,每次都必须是唯一的。为此,该函数首先生成一个密钥,然后检查数据库表以查看它是否正在被其他人使用。
If it's not in use, it returns the key, else, it calls itself again, but this causes the function to do an infinite loop, which is a no-no. Here's the whole function:
如果它不在使用中,它返回键,否则,它再次调用自己,但这会导致函数执行无限循环,这是一个禁忌。这是整个功能:
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);
}
}
What is the correct way to call the function again?
再次调用该函数的正确方法是什么?
By the way, I'm using CodeIgniter, hence $this.
顺便说一句,我正在使用 CodeIgniter,因此$this.
回答by Blixt
I would not use recursive functions for retry-scenarios (since you don't reuse the result of the function, it's pointless to use recursion)... It adds a lot of unnecessary overhead. Do something like this:
我不会在重试场景中使用递归函数(因为你不重用函数的结果,所以使用递归是没有意义的)......它增加了很多不必要的开销。做这样的事情:
do {
$key = ...; // Generate your key here...
} while (!$this->user_model->valid_key($key));
return $key;
If you're near the maximum number of keys, this will result in very long loop times, so you might want to put some kind of max limit.
如果您接近最大键数,这将导致非常长的循环时间,因此您可能需要设置某种最大限制。
Oh, and if this is occurring on multiple threads simultaneously and you're checking a database, you should implement table write locking so that the same key can't be inserted twice. Preferably the function that checks whether a key is available should lock, check, and if available writein the same transaction to avoid any collisions.
哦,如果这同时发生在多个线程上并且您正在检查数据库,则应该实现表写锁定,以便不能两次插入相同的键。最好检查密钥是否可用的函数应该lock、check和 if available在同一个事务中写入以避免任何冲突。
回答by drewm
You need to return the result of the self-call, otherwise the valid key won't get returned once it recurses.
您需要返回自调用的结果,否则一旦递归,将不会返回有效密钥。
return $this->key_generator($length);
回答by Valentin Jacquemin
but this causes the function to do an infinite loop,
但这会导致函数无限循环,
If you absolutely want to keep your recursive strategy you have to define an end case. For example you may define a counter, like this:
如果你绝对想保持你的递归策略,你必须定义一个最终案例。例如,您可以定义一个计数器,如下所示:
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));
}
}
It is however also possible to do your code iteratively...
然而,也可以迭代地执行您的代码......
回答by conny
If you include enough uniquenessin your key generation routine, you might be able to avoid this situation in the first place. E.g. have the routine take into account the current timestamp and the local hostname and/or PID.
如果您在密钥生成例程中包含足够的唯一性,您或许可以首先避免这种情况。例如,让例程考虑当前时间戳和本地主机名和/或 PID。
Looping in such a non-deterministic fashion is generally proof of some part being too naive. That's not good. :-)
以这种非确定性方式循环通常证明某些部分过于天真。这不好。:-)
Anyhow, it would at least be good practice to catch it and log some sort of error as opposed to hanging the request and finally timing out:
无论如何,捕获它并记录某种错误至少是一个好习惯,而不是挂起请求并最终超时:
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;
}
回答by Svante
Why don't you just scan the key value space for the first unused key? Needs the key to fulfill additional constraints on top of being four characters long and unique?
为什么不直接扫描第一个未使用的键的键值空间?除了四个字符长且唯一之外,还需要密钥来满足其他限制吗?
You could remember the last returned key to resume scanning from there on subsequent calls.
您可以记住上次返回的键,以便在后续调用时从那里恢复扫描。
If you want subsequent calls not to return similar keys, you could shuffle your key database first. This would mean that you need to hold a 456976, 1679616, 7311616, or 14776336 element array somewhere (depending on whether the alphabet used are single- or double-cased characters, with or without digits).
如果您希望后续调用不返回类似的密钥,您可以先洗牌您的密钥数据库。这意味着您需要在某处保存 456976、1679616、7311616 或 14776336 元素数组(取决于使用的字母表是单大小写还是双大小写字符,带或不带数字)。
回答by Daniel Rikowski
You could put your code into a loop and determine the key iterativelyinstead of recursively.
您可以将代码放入循环中,并以迭代方式而不是 递归方式确定密钥。
Example:
例子:
function key_generator($length = 4)
{
do {
$key = 'xxxx'; //TODO
if (timeOutReached()) return InvalidKey;
} while (!$this->user_model->valid_key($key))
return $key;
}
The loop itself does not prevent an infinte loop, but unlike a function call, this doesn't eat up stack space, so you don't risk a stack overflow.
循环本身不会阻止无限循环,但与函数调用不同,这不会占用堆栈空间,因此您不会冒堆栈溢出的风险。
Also it simplifies things a little bit. Depending on the type of the key you can also adapt the key generation method, for example with numbered keys you can increase exponentially with each iteration.
它也简化了一些事情。根据密钥的类型,您还可以调整密钥生成方法,例如,您可以在每次迭代中以指数方式增加编号的密钥。
Remarks:If it is possible, use a database's auto-increment feature instead of rolling your own key generation feature.
备注:如果可能,请使用数据库的自动增量功能,而不是滚动您自己的密钥生成功能。
Also make sure you protect your code against concurrent access. What if two instances of this function try to generate a key and they both determine the same? Use critical sections or transactions to make sure nothing bad happens.
还要确保您保护您的代码免受并发访问。如果此函数的两个实例尝试生成一个密钥并且它们都确定相同,该怎么办?使用临界区或事务来确保没有任何不好的事情发生。
回答by karthikeyan ganesan
Using a function inside itself
在自身内部使用函数
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

