1 (在右边木有& 符号的情况下) 先看左值 是否是引用 若是 直接将右值赋值给左变量。。左边引用计数不变
$a = 1;
$b = &$a;
$d = 2;
$e = &$d;
$b = $e;//输出 2 2 $b=&$e 输出 2 1
echo $b.PHP_EOL;
echo $a.PHP_EOL;
2 左值不是引用,且计数ref_count=1
左值==右值 则左值 经历一次减一 加一操作($a=&$a 则同时会设置is_ref=1)
左值!= 右值 则看右值 有无& 符号(注意有无此符号 和 此值 是否已经是 引用 并无直接关系。。如果右值 不是引用类型变量 此符号会将右值is_ref=1)
若无 且右值非引用变量(is_ref=0) 则将右值引用加一 左值销毁 否则 销毁左值 使用右变量值(is_ref=1)重新初始化生成一个ref_count=1的变量
(这里右变量是is_ref=1 则提前初始化一个新的左值)
若有 则将右值的ref_count+1 左值销毁 返回右值 (例如 $b = 1;&$b; $a=&b, 则a和b都是is_ref=1的变量)
3 左值ref_count>1 则减一即可 其他逻辑与2类似
来源php 内核深入理解
注意foreach($arr as $key=>&$val) 这来$val是引用 和 $a = &$b (a是引用) 注意这里区别
function a(&$a) {} ;
a($a);//已经是引用调用 a(&$a) 已经过 和赋值原理类似 这里和foreach 数组引用赋值类似 表示引用声明
php函数传递引用有运行时的引用和定义时引用的区别http://www.cunmou.com/phpbook/6.2.md
若一个函数 需要一个值类型大数组 硬是传递一个引用类型的 则传参时会发生大量的参数赋值过程 浪费时间
因为ZE2中所有的对象在当作函数参数的时候都是默认以引用的形式传递的。但是我们又必须把这个参数设置为数字1,除非你不想让你的扩展与PHP4兼容。在PHP4中,对象是传递的一个完整Copy,而非通过引用
对象默认的赋值操作时浅拷贝 数组是深度拷贝 即时clone 对象也只是里面的 值类型数据是拷贝http://www.cunmou.com/phpbook/7.2.md
<?php
//关于PHP语言中引用形式返回值的详述,请参考PHP手册。
$a = 'china';
function &return_by_ref()
{
global $a;
return $a;
}
$b = &return_by_ref();
$b = "php";
echo $a;
//此时程序输出php
</php>
在上面的代码中,$b其实是$a的一个引用,当最后一行代码执行后,$a和$b都开始寻找‘bar’这个字符串对应的zval,让我们以内核的角度重新观察这一切:
<code c>
#if (PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 0)
ZEND_FUNCTION(return_by_ref)
{
zval **a_ptr;
zval *a;
//检查全局作用域中是否有$a这个变量,如果没有则添加一个
//在内核中真的是可以胡作非为啊,:-)
if(zend_hash_find(&EG(symbol_table) , "a",sizeof("a"),(void **)&a_ptr ) == SUCCESS )
{
a = *a_ptr;
}
else
{
ALLOC_INIT_ZVAL(a);
zend_hash_add(&EG(symbol_table), "a", sizeof("a"), &a,sizeof(zval*), NULL);
}
//废弃return_value,使用return_value_ptr来接替它的工作
zval_ptr_dtor(return_value_ptr);
if( !a->is_ref__gc && a->refcount__gc > 1 )
{
zval *tmp;
MAKE_STD_ZVAL(tmp);
*tmp = *a;
zval_copy_ctor(tmp);
tmp->is_ref__gc = 0;
tmp->refcount__gc = 1;
zend_hash_update(&EG(symbol_table), "a", sizeof("a"), &tmp,sizeof(zval*), NULL);
a = tmp;
}
a->is_ref__gc = 1;
a->refcount__gc++;
*return_value_ptr = a;
}
#endif /* PHP >= 5.1.0 */