function countSheep($num) {
static $counter = 0;
$counter += sqrt($num);//imagine we need to take root of our sheep each time
echo "$counter sheep jumped over fence";
}
结果:
2 sheep jumped over fence
5 sheep jumped over fence
9 sheep jumped over fence
静态函数在对象的方法之间有点“共享”
同班。看下面的例子就很容易理解了:
class SomeClass {
public function foo() {
static $x = 0;
echo ++$x;
}
}
$object1 = new SomeClass;
$object2 = new SomeClass;
$object1->foo(); // 1
$object2->foo(); // 2 oops, $object2 uses the same static $x as $object1
$object1->foo(); // 3 now $object1 increments $x
$object2->foo(); // 4 and now his twin brother
尽管无法从外部访问在函数作用域内定义的变量,但这并不意味着您不能在该函数完成后使用它们的值。 PHP 有一个众所周知的
static关键字,在面向对象的 PHP 中广泛用于定义静态方法和属性,但应该记住static也可以在函数内部使用定义静态变量。什么是“静态变量”?
静态变量与函数作用域中定义的普通变量不同,当程序执行离开该作用域时,静态变量不会丢失值。让我们考虑以下使用静态变量的示例:
function countSheep($num) { static $counter = 0; $counter += $num; echo "$counter sheep jumped over fence"; } countSheep(1); countSheep(2); countSheep(3);结果:
如果我们定义的
$counter没有static那么每次回显的值将与传递给函数的$num参数相同。使用static可以构建这个简单的计数器,无需额外的解决方法。静态变量用例
技巧
静态变量仅存在于局部函数作用域中。它不可能是 在定义它的函数之外访问。所以你可以 确保它将保持其值不变,直到下次调用 该功能。
静态变量只能定义为标量或标量 表达式(自 PHP 5.6 起)。不可避免地为其分配其他值 至少在撰写本文时会导致失败。 不过,您可以在代码的下一行执行此操作:
function countSheep($num) { static $counter = 0; $counter += sqrt($num);//imagine we need to take root of our sheep each time echo "$counter sheep jumped over fence"; }结果:
静态函数在对象的方法之间有点“共享” 同班。看下面的例子就很容易理解了:
class SomeClass { public function foo() { static $x = 0; echo ++$x; } } $object1 = new SomeClass; $object2 = new SomeClass; $object1->foo(); // 1 $object2->foo(); // 2 oops, $object2 uses the same static $x as $object1 $object1->foo(); // 3 now $object1 increments $x $object2->foo(); // 4 and now his twin brother这只适用于同一类的对象。如果对象来自不同的类(甚至相互扩展),静态变量的行为将符合预期。
静态变量是在函数调用之间保留值的唯一方法吗?
在函数调用之间保留值的另一种方法是使用闭包。 PHP 5.3 中引入了闭包。简而言之,它们允许您将对函数作用域内的某些变量集的访问限制为另一个匿名函数,这将是访问它们的唯一方法。位于闭包变量中可能会模仿(或多或少成功)OOP 概念,例如结构化编程中的“类常量”(如果它们在闭包中按值传递)或“私有属性”(如果通过引用传递)。
后者实际上允许使用闭包而不是静态变量。使用什么始终由开发人员决定,但应该提到的是,静态变量在使用递归时绝对有用,值得开发人员注意。
什么是“变量范围”?
变量的“范围”或“可访问它们的位置”是有限的。仅仅因为您在应用程序中的某个某处编写了
$foo = 'bar';一次,并不意味着您可以从引用$foo>应用程序内的其他地方。变量$foo有一定的作用域,在该作用域内它是有效的,并且只有同一作用域内的代码才能访问该变量。PHP 中如何定义范围?
非常简单:PHP 有函数作用域。这是 PHP 中存在的唯一一种范围分隔符。函数内部的变量仅在该函数内部可用。函数外部的变量可以在函数外部的任何地方使用,但不能在任何函数内部使用。这意味着 PHP 中有一个特殊的作用域:全局 作用域。在任何函数外部声明的任何变量都在此全局范围内。
示例:
<?php $foo = 'bar'; function myFunc() { $baz = 42; }$foo位于 global 范围内,$baz位于内的local 范围内myFunc。只有myFunc中的代码才能访问$baz。只有myFunc外部的代码可以访问$foo。双方都无法访问对方:<?php $foo = 'bar'; function myFunc() { $baz = 42; echo $foo; // doesn't work echo $baz; // works } echo $foo; // works echo $baz; // doesn't work范围和包含的文件
文件边界不分隔范围:
a.php
b.php
适用于
include代码的规则与适用于任何其他代码的规则相同:仅函数的单独作用域。出于范围的目的,您可能会考虑包括复制和粘贴代码之类的文件:c.php
<?php function myFunc() { include 'a.php'; echo $foo; // works } myFunc(); echo $foo; // doesn't work!在上面的示例中,
a.php包含在myFunc中,a.php中的任何变量仅具有本地函数作用域。仅仅因为它们似乎位于a.php中的全局范围并不一定意味着它们确实如此,它实际上取决于代码包含/执行的上下文。函数和类中的函数怎么样?
每个新的
function声明都会引入一个新的作用域,就这么简单。(匿名)函数内的函数
function foo() { $foo = 'bar'; $bar = function () { // no access to $foo $baz = 'baz'; }; // no access to $baz }课程
$foo = 'foo'; class Bar { public function baz() { // no access to $foo $baz = 'baz'; } } // no access to $baz范围有什么用处?
处理作用域问题可能看起来很烦人,但是有限的变量作用域对于编写复杂的应用程序至关重要!如果您声明的每个变量都可以从应用程序内的其他任何地方使用,那么您将单步执行所有操作在你的变量上没有真正的方法来跟踪什么改变了什么。您可以为变量指定的合理名称有限,您可能希望在多个地方使用变量“
$name”。如果您的应用程序中只能使用一次这个唯一的变量名称,那么您必须采用非常复杂的命名方案来确保您的变量是唯一的,并且您不会从错误的代码段中更改错误的变量。观察:
function foo() { echo $bar; }如果没有作用域,上面的函数会做什么?
$bar从哪里来?它有什么状态?它甚至被初始化了吗?每次都要检查吗?这是不可维护的。这让我们...跨越范围边界
正确的方法:传入和传出变量
function foo($bar) { echo $bar; return 42; }变量
$bar作为函数参数显式进入此范围。只要看看这个函数,就可以清楚地知道它所使用的值来自哪里。然后它显式地返回一个值。调用者有信心知道函数将使用哪些变量以及其返回值来自哪里:将变量的范围扩展到匿名函数
$foo = 'bar'; $baz = function () use ($foo) { echo $foo; }; $baz();匿名函数显式包含其周围范围中的
$foo。请注意,这与全局范围不同。错误的方式:
全局如前所述,全局作用域有些特殊,函数可以显式地从中导入变量:
$foo = 'bar'; function baz() { global $foo; echo $foo; $foo = 'baz'; }该函数使用并修改全局变量
$foo。 不要这样做! (除非你真的真的真的知道自己在做什么,即使这样:也不要这样做!)这个函数的调用者看到的是这样的:
没有迹象表明此函数有任何副作用,但它确实有。这很容易变得混乱,因为某些函数不断修改并需要一些全局状态。您希望函数无状态,仅作用于它们的输入并返回定义的输出,无论您调用它们多少次。
您应该尽可能避免以任何方式使用全局作用域;最肯定的是,您不应该将变量从全局范围“拉”到局部范围。