最近项目中,出于内存效率考虑,对函数的返回值采取了值引用的方式。在control层的函数中,声明某变量为global的,然后调用该值引用函数进行初始化。然后在view层中,试图使用该global的变量失败,其值为NULL。

而如果函数直接返回值,而非引用方式,则正常。

简化代码如下:

function &fun(){
        $arr = array(
                        'a' => 1,
                        'b' => 2
                        );
        return $arr;
}

function child(){
        global $product;
        $product =& fun();
}

function child2(){
        $GLOBALS['product'] =& fun();
}

child();
global $product;
var_dump($product);

child2();
global $product;
var_dump($product);

调用child函数后,product为NULL,而调用child2函数后,product有值。

在两个global $product之后,分别调用xdebug_debug_zval函数,可以看到以下输出:

product: (refcount=1, is_ref=1)=NULL
product: (refcount=1, is_ref=1)=array (‘a’ => (refcount=1, is_ref=0)=1, ‘b’ => (refcount=1, is_ref=0)=2)

即child之后,product变量存在,但是其值为NULL;而child2之后,product变量和其值都存在。

在php手册里看到这么一句话:

在一个函数域内部用 global 语句导入的一个真正的全局变量实际上是建立了一个到全局变量的引用

这意味着,在child函数中,声明了一个指向global product”指针”的引用,并且改变了改引用的值。翻译成C语言即(注意:PHP的引用不是指针地址的引用,是符号表别名,后面会介绍。所以这里翻译成C代码,仅仅是表述其意。):

char * product = null;
void init(char*product){
    product = (char*)malloc(10);
}

那么很明显该product不会被初始化。

进一步查看php的引用原理,发现如下解释:

如果在一个函数内部给一个声明为 global 的变量赋于一个引用,该引用只在函数内部可见。可以通过使用 $GLOBALS 数组避免这一点

把 global $var; 当成是 $var =& $GLOBALS[‘var’]; 的简写。从而将其它引用赋给 $var 只改变了本地变量的引用。

<?php
$var1
= “Example variable”;
$var2 = “”;

function global_references($use_globals)
{
global
$var1, $var2;
if (!
$use_globals) {
$var2 =& $var1; // visible only inside the function
} else {
$GLOBALS[“var2″] =& $var1; // visible also in global context
}
}

global_references(false);
echo
“var2 is set to ‘$var2‘\n”; // var2 is set to ”
global_references(true);
echo
“var2 is set to ‘$var2‘\n”; // var2 is set to ‘Example variable’
?>

从php手册上可以看到,php的引用区别于C等语言,它不是指针,是“符号表别名”。

php引用与C引用的区别

php引用与C引用的区别

图画的简陋了点 :( ,在php中如果$q=&$p,则它们指向同一块地址,但是p和q之间没有直接关系。而c中,如果q=&p,则q是指向指针的指针,改变**q才会改变*p的值。

参考:

引用计数基本知识  http://php.net/manual/zh/features.gc.refcounting-basics.php

回收周期(Collecting Cycles) http://php.net/manual/zh/features.gc.collecting-cycles.php

变量范围 http://php.net/manual/zh/language.variables.scope.php

Leave a Reply