它们是PHP中的奇怪静态变量

免责声明:本文不会给您带来任何启示,也不会睁开您的第三只眼睛,但可以使您更详细地理解不太明显的问题。 至少当我写这本书时,她在这方面帮助了我。 如果您是php中的老狼,那么您将无法阅读它,我认为它不会伤害有经验的人通过他们的眼睛运行,刷新它们的内存,可以这么说,其余的都是正常的。


所以...


php中的静态变量是使用static关键字声明的一种特殊类型的变量。


static $foo = 3; 

它们与普通变量的不同之处在于(本文稍后将更详细地考虑以下几点):


  1. 只能分配常量和常量表达式
  2. 静态变量的生命周期不限于声明它的作用域的生命周期
  3. 只能在脚本中定义一次
  4. 直到脚本结束才销毁

现在按顺序。


1.只能分配常量和常量表达式


这意味着不能将任何函数或方法的运算结果赋给静态变量,或者通常不能将其分配给编译阶段的任何事物。 也就是说,这样的广告将无法正常工作


 static $var = foo(); 

但是很有可能


 static $var = 'some str'; static $varInt = 3 + 5; 

2.静态变量的生命周期不限于声明它的作用域的生命周期


我会在这里解释我的意思。 也许我会在术语上有些错误,但是我会尝试尽可能准确地传达其实质。 与常规变量比较。 如果在函数内部声明了变量,则默认情况下它是局部变量,即在局部作用域(此函数的作用域)中声明。 在这种情况下,此功能的上下文将是本地范围。 函数工作并返回结果后,将破坏其范围或上下文以及其中的所有变量。


如果我们在函数内部声明一个静态变量,那么它也在局部范围内声明,但是其上下文不是局部范围,而是函数本身。


(另外,最难解释的时刻是,我仅通过本质,没有任何细节,如何在php中声明函数,为它们分配了多少内存以及该内存中的内容)。 事实证明,调用函数时,解释器为其创建局部作用域,在该作用域中声明了所有局部变量和函数,并将它们附加到其上下文中。 通过使用static在局部作用域中声明变量,该函数本身将作为上下文分配给该变量,并且只要该函数本身存在,此变量就将存在。 当函数是可以向其中分配任意属性和方法的对象时,这类似于js。 在这里,同样,只有php中的函数才不是针对php的对象,而是针对较低语言的对象。


 function echoStaticVar() { static $var = 0; $var++; var_dump($var); }; echoStaticVar(); //1 echoStaticVar(); //2 echoStaticVar(); //3 

可以看出,函数终止后,收集器不会像使用常规变量那样破坏$ var变量。


这是一个示例,可以清楚地表明静态变量属于函数(它存储在函数中,或者其上下文是函数,所以对不起我不知道如何正确命名它)。


 $one = function ($i) { static $var = 0; $var += $i; var_dump($var); }; $two = $one; $one(1); //1 $one(5); //6 $one(5); //11 $two(5); //16 $two(5); //21 

一切都按预期进行,因为分配$ 2 = $ 1时; 函数本身不会被复制,但是这两个变量都将引用相同的存储区。 因此,静态变量$ var对于$ 1和$ 2均为1。


我们稍微修改一下示例,即不分配,但克隆


 // $two = $one; // $two = clone($one); 

 $one = function ($i) { static $var = 0; $var += $i; var_dump($var); }; $two = clone($one); $one(1); //1 $one(5); //6 $one(5); //11 $two(5); //5 $two(5); //10 

现在事实证明,$ one和$ 2不是使用一个静态变量$ var来引用同一函数,而是使用两个不同的函数,它们位于不同的内存区域,并且每个函数都有自己的静态变量$ var。 这并不是特别明显的一点,因此,如果您通常以程序化的方式编写代码(可能已经被认为是不好的形式,但这并不准确),那么您可能会迷失于此。


您所能做的就是一个函数调用计数器的经典示例。
但是就这种形式的OOP的传播而言,静态变量很少见,因为基本上您必须使用类和方法进行操作(我将在其中撰写有关静态实现的另一篇文章)


3.只能在脚本中定义一次


这意味着,如果已经声明了静态变量,并为其分配了一个值,则后续分配不会覆盖已分配的值,而是将返回现有的值。


 function staticVar($i) { static $var = 0; $var += $i; var_dump($var); }; staticVar(1); //1 staticVar(5); //6 staticVar(5); //11 

可以看到,如果每次将静态变量$ var 重新分配给静态变量$ var,我们总会得到结果1。但是由于重新分配不会覆盖它,所以我们得到了所得到的结果。
没错,有一件事可以摧毁一切。 在一个函数的框架内(更确切地说,是第一次调用该函数),可以根据需要多次重写这样的变量(在随后的情况下,所有内容将按所述方式工作)。 在我看来,这种行为很奇怪也很有趣,尤其是当您玩弄示例时。


 function staticVar($i) { static $var = 0; static $var = 5; $var += $i; var_dump($var); }; staticVar(1); //6 staticVar(5); //11 staticVar(5); //16 

在这里,在第一次调用staticVar函数的第一行中分配了变量$ var ,然后在第二行中将其覆盖。 但是已经在进一步的呼叫中,无论是在第一行还是在第二行中,她都已被重新分配,但是返回了先前呼叫中已经存在的内容


 function staticVar($i) { static $var = 0; // static $var = 5; //    $var += $i; static $var = 0; //    var_dump($var); }; staticVar(1); //1 staticVar(5); //6 staticVar(5); //11 

甚至在第一行中第一次调用staticVar时 ,即使是陌生人,也已对其进行了分配,然后在第二行中对其进行了重新分配(但未成功),然后对其执行了附加操作,此后,即使在第一个函数调用中尝试对其进行重新分配时,它也已返回了她的意思。


 function staticVarWrong($i) { static $var = 0; static $var = 5; $var += $i; var_dump($var); }; //  staticVarWrong(1); //6 staticVarWrong(5); //11 staticVarWrong(5); //16 function staticVarRight($i) { static $var = 0; static $var = 5; $var += $i; static $var = 0; //    var_dump($var); }; //  staticVarRight(1); //1 staticVarRight(5); //6 staticVarRight(5); //11 

也就是说,结果几乎是相同的方法,不同的行为。 此外,基于对静态变量应如何表现的描述,可以在staticVarRight中获得正确的结果。 在staticVarWrong中,根据函数的行为,可以发现在函数的第二行中已重新定义了变量。
这让我很开心。


4.直到脚本结束才销毁


在解释这一点时,我没有多大意义,尤其是因为示例中的所有内容都很清楚。 当脚本运行时,并且为某个函数声明了静态变量时,此变量存在。


按照计划,这是有关static的第一篇文章,有关OOP,静态字段和方法的信息。
好吧,当然,如果至少有人会对此感兴趣并且不难怪。

Source: https://habr.com/ru/post/zh-CN467489/


All Articles