手冊目錄: 語言參考---變量---變量范圍
參考詳情: https://secure.php.net/manual/zh/language.variables.scope.php
評論部分:
1. by warhog@warhog.net
提出一些有趣的代碼,在類函數里面使用static變量,如:
public functionfunc_having_static_var($x=NULL)
{
static$var=
0;
if ($x===NULL)
{ return$var; }$var=$x;
}
}$a= newsample_class();$b= newsample_class();
echo$a->func_having_static_var()."\n";
echo$b->func_having_static_var()."\n";// this will output (as expected):
// 0
// 0
$a->func_having_static_var(3);
echo$a->func_having_static_var()."\n";
echo$b->func_having_static_var()."\n";// this will output:
// 3
// 3
// maybe you expected:
// 3
// 0?>
本來我們期望的可能是輸出3.0,因為兩個不同的實例,調用public非static方法,應該是互不干擾的.但是結果卻告訴我們並非如此,方法中的static變量會作用於整個類方法以及所有的類實例,而不僅僅針對某一個實例.如果你想得到期望的輸出,你應該放棄使用方法內static變量,像這樣:
functionfunc($x=NULL)
{$this->var=$x; }
}
?>
我覺得正常的行為情況下是不應該像第一個例子那樣使用static變量的,但也許你會用到(比如我),希望這些能對你有用.
你也可以通過類的實例來動態添加該實例的內部public變量,就像$instance->$param = $value 就會向$instance中動態添加了public的$param,當然這只針對該實例有效,不會對類及其他實例造成影響,其實該用法沒什么卵用,只是想說php真特么強,笑尿.
2.by dodothedreamer@gmial.com
與java和C++不同的是,在循環塊和if塊語句中的變量可以在塊外訪問,如:
{
if($j==1)$a=4;
}
echo$a; //輸出 4?>
3. by Stephen Dewey
對於嵌套函數,global始終指明的是最外層的全局變量,而不是指上一層的范圍,如下將不會按照預期輸出:
functionb(){
global$var1;
echo$var1;
// there is no var1 in the global scope so nothing to echo}b();
}a('hello');?>
如果此時在function之上添加$var1 = 'some',將會得到輸出結果'some'.
4. by emartin@sigb.net
如果你有一個php文件里聲明了全局變量,當你在另一個文件的方法中包含這個php文件時,你將會發現包含進來的文件里的全局變量變成了只作用於方法內的局部變量,如下是解決辦法:
main_file.php :
functionsome_function() {//Some variables that we don't want out of the function$saucisse=
"saucisse";$jambon="jambon";//Let's include another file$evalt="require_once 'anothertest_include.php';";$before_eval_vars=get_defined_vars();
eval($evalt);//Let's extract the variables that were defined AFTER the call to 'eval'$function_variable_names= array("function_variable_names"=>0,"before_eval_vars"=>0,"created"=>0);//We can generate a list of the newly created variables by substracting the list of the variables of the function and the list of the variables which existed before the call to the list of current variables at this point$created=array_diff_key(get_defined_vars(),$GLOBALS,$function_variable_names,$before_eval_vars);//Now we globalize themforeach ($created
as$created_name=>$on_sen_fiche)
global $$created_name;//And we affect themextract($created);
}some_function();print_r(get_defined_vars());?>
included_file.php :
如此,你將可以在some_function 之外訪問global變量$included_var_one,two,three.同時需要注意的一點:
function test(){
$a = 4;
global $a;
} //這樣聲明是錯誤的,必須先聲明,所以正確的寫法是將global $a放在$a = 4的前面.
5. by danno@wpi.edu
他提出一段有趣的代碼,經過我的修正之后,大致如下:
class obj{
public function __destruct(){
echo 'destruct';
}
}
function foo ()
{
global $testvar;
$localvar = new obj();
$testvar = &$localvar;
}
foo ();
var_dump($testvar);
?>
輸出
destruct
NULL
因為對象引用是引用同一標識符,所以當方法結束后,相當於unset($localvar),此時沒有其他標識符指向類實例,所以調用destruct,同時$testvar也相當於被unset了,為NULL,如果修改function如下:
function foo ()
{
global $testvar;
$localvar = new obj();
$testvar = $localvar; //此處將引用改為賦值
}
輸出
object(obj)#1 (0) {
}
destruct
可以看到,賦值跟引用是有區別的,賦值會copy一份標識符指向類實例,所以對$localvar的釋放並不會影響$testvar,所以直到程序的最后才會調用destruct.
具體的賦值與引用的區別可以參見:http://segmentfault.com/a/1190000002928594
6. by jinxidoru@byu.net
關於類內方法使用static變量,1中已經提到過,這里指出,static變量不支持繼承,如下:
functionZ() {
static$count=0;printf("%s: %d\n",get_class($this),
++$count);
}
}
classBextends
A{}$a= newA();$b= newB();$a->Z();$a->Z();$b->Z();$a->Z();?>
輸出:
A: 1
A: 2
B: 1
A: 3
可以看到,類A和類B使用了不同的靜態變量,即使他們使用的是同一個方法,而且就算function Z是靜態方法,結果也是一樣.
7. by moraesdno@gmail.com
這里提一下,使用超全局$GLOBALS數組比使用global關鍵字更快.
8. by Anonymous
Anonymous提出如果static變量是一個數組,並且返回它的某個元素的時候,會返回該元素的引用,於是有了如下的測試代碼:
return$int++;
}
functionreturn_copyof_scalar() {
static$v;
if (!$v)$v=1;
return($v);
}
functionreturn_copyof_arrayelement() {
static$v;
if (!$v) {$v= array();$v[0] =1;
}
return($v[0]);
}
echo"scalar: ".incr(return_copyof_scalar()).incr(return_copyof_scalar())."\n";
echo"arrayelement: ".incr(return_copyof_arrayelement()).incr(return_copyof_arrayelement())."\n";?>
期望輸出:
scalar:11
array element:11
他測試的結果:
scalar:11
array emelent:12
但是我在php7上進行了同樣的測試,發現結果跟期望輸出是一樣的,所以這里的數組元素並沒有按照引用返回,如果我們要使用引用,應該像&function這樣聲明函數,也需要像&function一樣調用它,但是有一個例外,就是當incr(return_copyof_scalar())這樣作為參數調用的時候,不需要添加&,如此只需要在上述例子中的函數聲明部分各自添加&就可以得到輸出結果:
scalar:12
array element:12
9. by info@SyPlex.net
有時候你需在在其他多個函數中訪問同一個static,同時這個static的可見范圍也是非全局的,這里有一個簡單的方法解決這個問題:
static$staticVar;
return$staticVar;
}// Now we can access the static in any method by using it's referencefunctionfooCount() {$ref2static= &
getStatic();
echo$ref2static++;
}fooCount();// 0fooCount();// 1fooCount();// 2?>
10. by Jack@soinsincere.com
你不可以將方法里的static與傳入進來的引用參數關聯,但是你可以使用數組的形式對引用進行保存與操作,如下:
static$my;
if(!$arr)return$my[0];
$my =$arr;
}
$you ='hello';
test(array(&$you));
$you ='world';
var_dump(test());
?>輸出 world
再考慮我自己添加的一段代碼:
static$num =0;
static$t =2;
if($num !=0){
var_dump($t);
}
$t = &$test;
$t =3;
$num++;
}
$a =1;
tst($a);
tst($a);
?>
預期輸出1或者3
實際輸出 2 可以這樣推斷,static在堆中有一個固定的內存塊,在function中第一次賦值為2的時候,該內存塊就保存了2的值,之后的一系列引用,賦值修改操作只是將static當做一個指針使用,當function執行完之后,static還是回歸指向堆中固定的那塊內存,所以,如果之前的一系列操作沒有對該固定內存進行值修改,下次再訪問static的時候,依然會是之前的值2,而不是預期的指向新的內存地址,所以當使用array數組保存引用並將array保存到static的固定內存塊中,才會對下次的static調用造成影響,進而訪問到array中保存的引用.個人愚見,有錯誤的地方還請指正.
11. by ppo@beeznest.net
即使某個被include進來的file使用return返回一個value,該value仍然與include的文件中的同名value保持同一個訪問范圍,如:
$foo='aaa';$bar= include('include.php');
echo($foo.' / '.$bar);?>
where include.php is
$foo='bbb';
return$foo;?>
期望輸出:aaa/bbb
實際輸出:bbb/bbb
12. by mod
mod提出一個比較有意思的代碼,如下:
function__destruct()
{
global$g_Obj;
echo"
#step 2: ";var_dump($g_Obj);
}
functionstart()
{
global$g_Obj;
echo"
#step 1: ";var_dump($g_Obj);
}
};$g_Obj= newA();// start here$g_Obj->start();
?>
mod得到的輸出是:
#step 1: object(A)#1 (0) { }
#step 2: object(A)#1 (0) { }
但是我在php7上測試的結果是:
#step 1: object(A)#1 (0) { }
#step 2: NULL
可以知道,php中class的destruct最先操作的是將類實例變量置為空值,然后再調用destruct里面的代碼.為了證明這一點,我們可以在上述的例子最后添加一句代碼:
$g_Obj = true
得到的輸出將變成:
#step 1: object(A)#1 (0) { }
#step 2:bool(true)
13. by huntsbox@pacbell.net
嵌套函數需要注意重復聲明以及第一次聲明,如下例子:
static$first_time = true;
if($first_time) {
functionsquare($x)
{
return$x*$x;
}
$first_time = false;
}
returnsqrt(square($a) +square($b));
}
printnorm(5,4);
print"
";
printsquare(4);
print"
";
printnorm(6,5);
print"
";
?>該例子能正確輸出結果,如果將function中的判斷語句if($first_time)去掉,就會造成重復聲明的錯誤,同時,如果
在語句print norm(5,4)之前調用square函數,將會導致undefined function 的錯誤,必須先執行一遍外部的norm函數,告訴外部存在其內部定義聲明的square函數.
14. by tomek@pluton.pl
當定義一個static變量時,你可以這樣聲明:
static$var= array(1,'a',3);//array construct?>但是你不可以這樣聲明(error):
static$var= (some_function('arg'));
static$var=2+3;//any expressionstatic$var= newobject;?>
15. by jochen_burkhard@web.de
jochen提出當使用遠程調用php文件時,遠程文件中的變量將不能在調用文件中使用,如;
remotefile.php:
$paramVal=10;?>
localfile.php:
echo"remote-value=$paramVal"; //將不會得到預期值?>這里提一下,本人沒有親自測試過,需要的自己測試下真偽.
本人水平有限,如有錯誤的地方,請及時指正並及時改正.