首先,要理解变量名存储在内存栈中,它是指向堆中具体内存的地址,通过变量名查找堆中的内存;
普通传值,传值以后,是不同的地址名称,指向不同的内存实体;
引用传值,传引用后,是不同的地址名称,但都指向同一个内存实体;改变其中一个,另外一个就也被改变;

以下我将通过三个列子来详细讲解这两个传值的区别:

Example1:

  1. <?php
  2. //普通传值
  3. $param1=1;
  4. $param2=2;
  5. $param2 = $param1;
  6. $param1 = 5; //变量1和变量2是两块内存,互不影响;
  7. echo $param2; //所以此处还是显示为1
  8.  
  9. //引用传值 ↓↓
  10. $param1=1;
  11. $param2=2;
  12. $param2 = &$param1; //把变量1的内存地址赋给变量2;此时的变量2和变量1全等;
  13. echo $param2;// 1
  14. $param1 = 5; //变量1和变量2是一处内存,改变其中一个,另外一个也被改变;
  15. echo $param2; //显示为5
  16. ?>

Example2:

  1. <?php
  2. //函数中的普通传值 ↓↓
  3. $param1 = 1;
  4. function add($param2){
  5. $param2=3;
  6. }
  7. $param3=add($param1); //调用方法add,并将变量1传给变量2,此处是普通传值,所以变量1和变量2是两处内存,互不影响;
  8. echo '<br>$param1=='.$param1.'<br>'; //显示为$param1==1
  9. echo '<br>$param2=='.$param2.'<!-- <br> -->'; //显示为$param2== 因为$param2是局部变量,函数运行完了以后就自动销毁,其不能影响全局
  10.  
  11. //函数中的引用传值 ↓↓ 注意,php不建议这样使用,并且php.in里面设置其会报错;
  12. $param1 = 1;
  13. function add($param2){
  14. $param2=3;
  15. return $param2;
  16. }
  17. $param3=add(&$param1); //调用方法add,并将变量1的引用传给变量2,此时两个地址指向同一内存,改变其中一个,另外一个也要被改变;
  18. echo $param1; //3,内存已在函数内部改变;
  19. echo $param3; //3
  20. ?>

Example3:

  1. <?php
  2. //给数组里面的键值各增加10;
  3. $arr = array(3,5);
  4.  
  5. foreach($arr as $k=>$v){
  6. $v+=10;//1.更改无效,相当于遍历出的键值扔给变量$v,然后更改变量$v的值,跟数组无关;
  7. echo $v." ";//输出13 15;
  8. }
  9.  
  10. foreach($arr as $k=>$v){
  11. $arr[$k]+=10;//2.更改有效,直接更改键名里面的值;
  12. echo $v;//输出3,5;
  13. }
  14.  
  15. foreach($arr as &$v){
  16. $v+=10;//3.更改有效,遍历的键值直接给了$v的地址,这个地址其实就是键名..$v+10就等于$arr[$k]+10;
  17. }
  18. ?>

然后我们来看一下这道题:

  1. $a = 1;
  2. $b = &$a;
  3. unset($a);
  4. echo $b; //??
  1. 当时我的回答是这样的: 会报一个notice的错误,因为$b$a共用一处内存,unset就把这处内存销毁掉了,然后输出$b变量的时候找不内存,所以应该是Notice: Undefined variable: b in

但是要注意: unset并没有真正销毁变量的作用...仅仅是切断了变量与内存之间的关系,内存只要还被引用着就不会被释放;

$b和$a同时指向1,切断其中$a的关系,$b还是指向1,所以上题不报错,照样输出1。

另外补充一点: 在PHP中对象的传值默认是引用传值

再看一题:
在做这题之前我们回顾一下什么是析构函数,而PHP中对象销毁的方式有哪些:

析构函数:对象销毁时执行;注意在隐式销毁中是在是所有php代码执行完最后一行代码的时候才销毁,还有要注意在单入口文件下的MVC模式

对象的销毁

  1. 显试销毁: 当对象没有被引用时就会被销毁,所以我们可以unset或为其赋值NULL;
  2. 隐试销毁:PHP是脚本语言,在代码执行完最后一行时,所有申请的内存都要释放掉.

Example1:

  1. class Human {
  2. public $name = '张三';
  3. public $gender = null;
  4. public function __destruct() {
  5. echo '死了!<br />';
  6. }
  7. }
  8. $a = new Human();
  9. $b = $c = $d = $a;
  10. unset($a);
  11. echo '<hr />'; //析构函数究竟是触发了几次,是在线上触发,还是在线下触发?
  1.  

答案:

  1. $b = $c = $d = $a;默认引用传值,四个变量指向同一处内存,unset的时候对象还是被还是其它三个变量使用,所以对象并没有被销毁,所以析构函数是在线下触发的(代码执行完了,内存自动释放)

Example2:

  1. class Human {
  2. public $name = '张三';
  3. public $gender = null;
  4.  
  5. public function __destruct() {
  6. echo '死了!<br />';
  7. }
  8. }
  9. $e = $f = $g = new Human();
  10. unset($e);
  11. unset($f);
  12. unset($g);
  13. echo '<hr />'; //同样的问题: 析构函数是在线上触发还是线下触发?

我相信通过Example1的讲解,应该很快知道答案是在线上触发;在代码运行完自动释放内存之前由于对象已经没有被任何变量引用所以就自动释放了内存....

原文地址: https://www.cnblogs.com/nixi8/p/4925094.html

php普通传值和引用传值 (相当通俗易懂的一篇讲解)的更多相关文章

  1. 从一次面试经历谈PHP的普通传值与引用传值以及unset

    关于这个概念一般都会在PHP的第一堂课说变量的时候给介绍,并且我以前还给其他PHPer介绍这个概念.但是作为一个工作一段时间的PHPer的我,竟然在面试的时候一下子拿不定主意最后还答错了,很觉得丢脸( ...

  2. PHP的普通传值与引用传值以及unset

    首先,要理解变量名存储在内存栈中,它是指向堆中具体内存的地址,通过变量名查找堆中的内存; 普通传值,传值以后,是不同的地址名称,指向不同的内存实体; 引用传值,传引用后,是不同的地址名称,但都指向同一 ...

  3. JS 拷贝传值和引用传值

    1.拷贝传值:基本数据类型都是“拷贝传值”. 拷贝传值,就是将一个变量的值“拷贝”一份,传给了另一个变量. 拷贝传值中,两个变量之间没有任何联系,修改其中一个变量的值,另一个不会改变. 这两个变量之间 ...

  4. PHP变量的传值和引用

    问题: 1.PHP变量的存储.取值方式如何? 2.变量赋值时,普通传值和引用传值分别是什么意思?有何区别? 3.unset被赋值的变量会对两种赋值后原值和新值的影响?   变量的存储.取值形式: 变量 ...

  5. Java基础必备 -- 堆栈、引用传值、垃圾回收等

     在Java中,对象作为函数参数的传递方式是值传递还是引用传递?String str = "abc" 与 String str = new String("abc&quo ...

  6. PHP和CS的引用传值

    PHP的引用传值 function change_value($num){ $num+=2; } $age = 3; change_value(&$age); echo $age; CS的引用 ...

  7. Js 赋值传值和引用传址

    赋值传值和引用传址 在JavaScript中基本数据类型都是赋值传值,复合数据类型都是引用传址(传地址) 基本数据类型的变量名和数据是直接存在"快速内存"(栈内存)中,而复合数据类 ...

  8. Python引用传值总结

    Python函数的参数传值使用的是引用传值,也就是说传的是参数的内存地址值,因此在函数中改变参数的值,函数外也会改变. 这里需要注意的是如果传的参数类型是不可改变的,如String类型.元组类型,函数 ...

  9. PHP引用传值规范问题

    在我上一篇:  shopnc 商城源码阅读笔记--开篇概述   中,遇到了一个PHP引用传值导致的错误,情况大致如下: 在我查阅PHP官方文档  的中文版的时候   http://php.net/ma ...

随机推荐

  1. C#使用FileSystemWatcher控件实现的文件监控功能示例

    本文实例讲述了C#使用FileSystemWatcher控件实现的文件监控功能.分享给大家供大家参考,具体如下: FileSystemWatcher 可以使用FileSystemWatcher组件监视 ...

  2. Innodb与Myisam引擎的区别与应用场景

    1. 区别: (1)事务处理: MyISAM是非事务安全型的,而InnoDB是事务安全型的(支持事务处理等高级处理): (2)锁机制不同: MyISAM是表级锁,而InnoDB是行级锁: (3)sel ...

  3. 《团队作业第一周》五小福团队作业——UNO

    <团队作业第一周>团队作业--UNO 一.团队展示 队员学号 队名:五小福 (真是个红红火火恍恍惚惚的队名)> 拟作的团队项目描述 基于安卓开发的有趣味性的UNO纸牌小游戏 队员风采 ...

  4. Pytorch学习(一)基础语法篇

    how to use pytorch 1.Tensor we can create a tensor just like creating a matrix the default type of a ...

  5. http连接基础类,负责底层的http通信

    /// <summary> /// http连接基础类,负责底层的http通信 /// </summary> public class HttpService { public ...

  6. CodeForces - 1025C 字符串处理,画一个圆。。。

    题目链接: https://vjudge.net/problem/1810469/origin 题目大意: 给你一个字符串,中间切一刀,左右两边均反转,然后右边的串拼接到左边上. 思路: 比如  aa ...

  7. JAVA时间工具类,在维护的项目里的

    package com.inspur.jobSchedule.util; import org.apache.commons.lang3.time.DateUtils; import org.apac ...

  8. SpringCloud教程 | 第六篇: 分布式配置中心(Spring Cloud Config)

    一.简介 在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件.在Spring Cloud中,有分布式配置中心组件spring cloud config ...

  9. SD卡

    一.SD卡接口 SD 卡的接口可以支持两种操作模式:主机系统可以选择以上其中任一模式, SD 卡模式允许 4 线的高速数据传输. SPI 模式允许简单通用的 SPI 通道接口, 这种模式相对于 SD ...

  10. angular.isDate()

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...