PHP中的惰性函数定义-可能吗?
在JavaScript中,您可以使用来优化对函数的第二次-第n次调用,方法是仅对函数的第一次调用执行昂贵的一次性操作 我想在PHP5中做同样的事情,但是不允许重新定义函数,也不允许重载函数 实际上,我想做的是如下所示,只是进行了优化,以便第2-n次呼叫(比如25-100次)不需要重新检查它们是否是第一次呼叫PHP中的惰性函数定义-可能吗?,php,design-patterns,optimization,Php,Design Patterns,Optimization,在JavaScript中,您可以使用来优化对函数的第二次-第n次调用,方法是仅对函数的第一次调用执行昂贵的一次性操作 我想在PHP5中做同样的事情,但是不允许重新定义函数,也不允许重载函数 实际上,我想做的是如下所示,只是进行了优化,以便第2-n次呼叫(比如25-100次)不需要重新检查它们是否是第一次呼叫 $called = false; function foo($param_1){ global $called; if($called == false){ doExpens
$called = false;
function foo($param_1){
global $called;
if($called == false){
doExpensiveStuff($param_1);
$called = true;
}
echo '<b>'.$param_1.'</b>';
}
$called=false;
函数foo($param_1){
全球美元;
如果($called==false){
doExpensiveStuff($param_1);
$called=true;
}
回显“.$param_1.”;
}
PS我曾考虑过使用include_once()或require_once()作为函数的第一行,以便只执行一次外部代码,但我听说这些也很昂贵
有什么想法吗?或者有更好的方法来解决这个问题吗?您实际分析过这段代码吗?我怀疑额外的布尔测试是否会对页面呈现时间产生任何可测量的影响。您可以执行条件函数定义
if( !function_exists('baz') )
{
function baz( $args ){
echo $args;
}
}
但目前,函数在定义时会变成一块砖块
您可以使用create_函数
,但我建议您不要,因为它速度慢,占用大量内存,在php退出之前无法释放(),并且是一个与eval()一样大的安全漏洞
等到PHP5.3,我们有“闭包”
那你就可以这样做了
if( !isset( $baz ) )
{
$baz = function( $args )
{
echo $args;
}
}
$baz('hello');
$baz = function( $args )
{
echo $args + "world";
}
$baz('hello');
进一步阅读后,这就是你想要的效果
$fname = 'f_first';
function f_first( $even )
{
global $fname;
doExpensiveStuff();
$fname = 'f_others';
$fname( $even );
/* code */
}
function f_others( $odd )
{
print "<b>".$odd."</b>";
}
foreach( $blah as $i=>$v )
{
$fname($v);
}
然而,你可能无法做到这一点,但你没有给予足够的空间来澄清。但是,如果你能做到这一点,那么简单的答案通常是最好的:)如果你最终发现额外的布尔测试过于昂贵,你可以将变量设置为函数名并调用它:
$func = "foo";
function foo()
{
global $func;
$func = "bar";
echo "expensive stuff";
};
function bar()
{
echo "do nothing, i guess";
};
for($i=0; $i<5; $i++)
{
$func();
}
$func=“foo”;
函数foo()
{
全球$func;
$func=“bar”;
呼应“昂贵的东西”;
};
功能条()
{
回声“我想什么也不做”;
};
对于($i=0;$i有什么原因让你选择函数式模式吗?尽管有匿名函数和闭包计划,PHP实际上不是一种函数式语言。在这里,类和对象似乎是更好的解决方案
Class SomeClass{
protected $whatever_called;
function __construct(){
$this->called = false;
}
public function whatever(){
if(!$this->whatever_called){
//expensive stuff
$this->whatever_called = true;
}
//rest of the function
}
}
如果你想变得有趣,你可以使用神奇的方法来避免预定义被调用的布尔值。如果你不想实例化一个对象,就去静态。请不要使用include()
或include_once()
,除非你不在乎include()
失败。如果您包含代码,那么您会在意。始终使用require\u once()
使用本地静态变量:
function foo() {
static $called = false;
if ($called == false) {
$called = true;
expensive_stuff();
}
}
避免为此使用全局名称空间。它会使全局名称空间变得混乱,并使函数的封装程度降低。如果函数内部以外的其他地方需要知道是否调用了该函数,那么将该函数放入Alan Storm指出的类中是值得的。PHP没有词法作用域,因此无法执行您想要的操作然而,PHP有一些类,这些类在概念上与函数的工作方式完全相同
在javascript中,您可以执行以下操作:
var cache = null;
function doStuff() {
if (cache == null) {
cache = doExpensiveStuff();
}
return cache;
}
class StuffDoer {
function doStuff() {
if ($this->cache == null) {
$this->cache = $this->doExpensiveStuff();
}
return $this->cache;
}
}
使用类(在PHP中),您可以执行以下操作:
var cache = null;
function doStuff() {
if (cache == null) {
cache = doExpensiveStuff();
}
return cache;
}
class StuffDoer {
function doStuff() {
if ($this->cache == null) {
$this->cache = $this->doExpensiveStuff();
}
return $this->cache;
}
}
是的,基于类的oop比函数式编程更冗长,但在性能方面,它们应该差不多
除此之外,PHP5.3可能会获得词法作用域/闭包支持,因此当它出现时,您可以使用更流畅的函数式编程风格来编写。有关详细信息,请参阅PHPRFC wiki。使用局部静态变量如何
function doStuff($param1) {
static $called = false;
if (!$called) {
doExpensiveStuff($param1);
$called = true;
}
// do the rest
}
如果您只需要为给定的参数值执行一次昂贵的操作,则可以使用数组缓冲区:
function doStuff($param1) {
static $buffer = array();
if (!array_key_exists($param1, $buffer)) {
doExpensiveStuff($param1);
$buffer[$param1] = true;
}
// do the rest
}
局部静态变量在函数调用中是持久的。它们在返回后会记住值。代码正在记忆中。bool测试(尽管可能更容易编写,就像(!$called))决定是否执行缓慢的代码,使其只运行一次。@Kent:阅读scunliffe的链接。他试图在函数第一次运行后重新定义函数,以便在($called)
test时跳过该函数。PHP确实不是一种功能性语言。FWIW,类是相对“新的”在php5之前,它们几乎都不是类。类也有开销,你的代码在逻辑上与原始代码完全相同。是的,都是真的,但php在过去的两三年里一直朝着一个经典的OOP概念发展,php中的函数抽象也有自己的开销。只是另一个嗯,这看起来可能是可行的,当然是一个配置文件,谢谢。但是它仍然是一个函数调用,它本身可能相当昂贵。这是一个复杂的、复杂的解决方案,甚至还不可用。本地静态VAR是简单的解决方案。结束于最初需要做多少工作来处理它。这不完全正确;尽管我能想到的唯一情况是非常具体的:如果您使用DOMPDF及其hack来更改PDF生成(如在PDF上添加标题),那么您可以在PDFHeader.php(或类似)文件中编写代码(从而保留任何编辑器的好处)并且仅当所述PDF负责人在场时才将其包括在内。