php数组时按值传递还是按地址传递

一、总结

1、数组都是按值:php普通变量和数组的赋值(=)是按值传递,对象的赋值(=)是按址传递

2、对象和按值和按址对象的clone(用clone关键字)是按值传递

二、PHP 数组的拷贝是按值传递 or 按引用传递

在记忆中 PHP 简单变量的拷贝是按值传递,数组和对象的拷贝是按引用传递,即通过引用来实现。

简单变量和对象好理解:

<?php

// 简单变量的拷贝
$a = 'human';
$b = $a;
$b = 'cat';
var_dump($a); // string 'human' (length=5) // 对象的拷贝
class A{}
$a = new A();
$b = $a;
$b->name = 'jack';
var_dump($a); // object(A)[1] public 'name' => string 'jack' (length=4)

对象 $a 和 对象 $b 的内存地址指向了同一个地方,即针对 $a 和 $b 所做的操作都针对同一个实例。

PHP 中可以通过 clone 关键字按值拷贝对象:clone关键字让对象按值传递,因为clone就是拷贝

1
2
3
4
5
6
7
8
9
10
<?php
 
class A{
    public $name 'Vardy';
}<br>
$a new A();
$b clone $a;
$b->name = 'dee';
var_dump($a); // object(A)[1] public 'name' => string 'Vardy' (length=5)
var_dump($b); // object(A)[2] public 'name' => string 'dee' (length=3)

  

数组:

1
2
3
4
5
6
7
8
9
10
<?php
 
// 数组的拷贝
$a = ['human''orc'];
$b $a;
$b[0] = 'elve';
var_dump($a);
// array (size=2)
//   0 => string 'human' (length=5)
//   1 => string 'orc' (length=3)

这样看,数组的拷贝是按值传递的.

另一个例子 数组的迭代器:

1
2
3
4
5
6
7
8
9
<?php
 
$a = ['human''orc''elven''undead'];
next($a);
 
$b $a// 此时指针位置也随着数组的复制而复制
 
var_dump(current($a)); // string 'orc' (length=3)
var_dump(current($b)); // string 'orc' (length=3)

当数组拷贝时,数组的指针位置也随着复制。

(next:http://php.net/manual/zh/function.next.php

current:http://php.net/manual/zh/function.current.php

1
2
3
4
5
6
7
8
9
10
<?php
 
$a = ['human''orc''elven''undead'];
end($a);
next($a); // 数组指针非法,返回 FALSE
 
$b $a;
 
var_dump(current($a)); // string 'human' (length=5)
var_dump(current($b)); // boolean false

当数组在拷贝前,指针的位置是非法时,拷贝后分别打印两个数组指针所指向的当前单元时,出现了不一样的情况。

原因是数组变量发生拷贝后,两个变量中先发生写操作的,其指针被初始化,即指向第一个元素,而 current 方法也会产生写操作,因此 $a 的数组指针当前指向的是 'human',而 $b  current 方法则返回 FALSE。

以下代码同理, $b 首先发生了写操作:

1
2
3
4
5
6
7
8
9
10
11
12
<?php
 
$a = ['human''orc''elven''undead'];
end($a);
next($a);
 
$b $a;
 
$b[] = 'dwarf';
 
var_dump(current($a)); // boolean false
var_dump(current($b)); // string 'human' (length=5)

  

解析:数组的拷贝是值传递。PHP 在管理内存方面有一个机制叫写时复制(COW,Copy On Write),保证了变量间复制值不浪费内存:当一个变量的值复制到另一个变量时,PHP 没有为复制值使用更多的内存,相反,它会更新符号表来说明两个变量拥有相同的内存块,所以当执行下面的代码时并没有创建一个新的数组:

1
2
3
4
<?php
 
$a = ['human''orc''elven''undead'];
$b $a;

当修改了 $a 或 $b 任意一个副本时,PHP 将分配所需的内存来进行复制:

1
$b[] = 'dwarf';

  

 

参考:

php基础语法之数组和数组指针

php中引用&的真正理解-变量引用、函数引用、对象引用

Programming PHP 3rd Edition

参考:

PHP 数组的拷贝是按值传递 or 按引用传递 - 黄棣-dee - 博客园
https://www.cnblogs.com/dee0912/p/5605323.html

php数组时按值传递还是按地址传递的更多相关文章

  1. c语言进阶9-值传递与地址传递

    一.  函数的值传递 函数的值传递是指参数为基本类型时,如整型.浮点型.字符型(特指单字符型)时,参数传递时是从实参拷贝一份值传给形参,形参的变化不会影响实参的值. 1.        基本类型做参数 ...

  2. Java中不得不谈的值传递和地址传递

    个人的一些认识,希望能对初学Java的你,或者困惑于方法参数传递的你祈祷一丝帮助! 下面是一些作者的个人观点,如果有错,欢迎各位大牛指出错误,灰常感谢您的观看与支持... -------------- ...

  3. JavaScript中,按值传递与按地址(引用)传递。

    JavaScript中,数字型,字符串,布尔型等基本类型,传递给变量时,传递方式为按值传递,这个很好理解,不做多解释. 而令人有所疑惑的,是数组,对象等引用类型传递给变量是,传递方式为按地址传递.此处 ...

  4. JavaScript中函数参数的按值传递与按引用传递(即按地址传递)

    首先声明一句:JavaScript中所有函数的参数都是按值传递的!不存在按引用传递! 在讲传递参数之前我们先来讲一下指针. 学过C指针的应该都知道,指针变量中保存的是一个地址,程序可以根据所保存的地址 ...

  5. java学习——java按值传递和按址传递

    先复制一个面试/笔试的题: 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递? 答案: 是值传递.Java语言的方法调用只支持参 ...

  6. 按值传递 vs. 按指针传递

    按值传递还是指针传递? 变量赋值有两种方式:按值传递.按"指针"传递(指针也常称为"引用").不同的编程语言赋值的方式不一样,例如Python是按"指 ...

  7. C语言中数组名作为参数进行函数传递

    用数组名作函数参数与用数组元素作实参有几点不同. 1) 用数组元素作实参时,只要数组类型和函数的形参变量的类型一致,那么作为下标变量的数组元素的类型也和函数形参变量的类型是一致的.因此,并不要求函数的 ...

  8. C++中函数的形参为数组时,实质形参是指针

    C++中函数的形参如果为数组的话,那么进行实参传递时,实参实际上换转化成指针.参考下面的例子: #include<iostream> using namespace std; void f ...

  9. C语言 值传递和地址传递

    不少同学在学到C语言的指针部分时感到很困惑,对经常提到的"值传递"和"地址传递"两个概念弄不 明白.实际上,因为地址本身也可以作为一个特殊的"值&qu ...

随机推荐

  1. python中的类与继承

    Class 类的定义以及实例的建立 Python中,类通过 class 关键字定义. 例如最简单的一个类定义可以为: class Person(object): pass Python 的编程习惯,类 ...

  2. android系统又一次刷ROM简记(一)

    当须要对android系统进行大刀阔斧的改造的时候,应该清晰的了解android各个image的组成才干做到庖丁解牛. 首先在android烧写过程中须要烧写的文件主要包含uboot.bin\boot ...

  3. JAVA类库LinkList的基本实现

    写完调试了好久,边界不优点理,具体的请看JDK类库,下面仅仅是基本实现: import java.util.Iterator; /** * 类名:MyLinkedList 说明:LinkedList的 ...

  4. Redis封装之String

    RedisBase类 /// <summary> /// RedisBase类,是redis操作的基类,继承自IDisposable接口,主要用于释放内存 /// </summary ...

  5. 消息推送学习一、原生Socket的使用

    消息推送也是客户端和服务器连接然后进行交互的一种形式,但是不同于HTTP的连接,这种连接需要长时间的进行,当有消息时可以及时推送到客户端.除此之外还有多个用户,可能需要针对其身份进行不同的推送等等要求 ...

  6. SQL SERVER 新增表、新增字段、修改字段 判断表是否存在

    // 新增之前判断表是否存在 IF NOT EXISTS (SELECT NAME FROM SYSOBJECTS WHERE ID = OBJECT_ID('tb_MessageHistory')) ...

  7. 安装oracle常见问题分析

    1,之前已经安装过软件,卸载不完全 /tmp/.oracle /tmp/ora* /var/tmp/ora* /etc/ora* 2,安装介质权限或者本身就有问题 3,oracle用户 $/HOME/ ...

  8. SELinux 入门

    几乎可以肯定每个人都听说过 SELinux (更准确的说,尝试关闭过),甚至某些过往的经验让您对 SELinux 产生了偏见.不过随着日益增长的 0-day 安全漏洞,或许现在是时候去了解下这个在 L ...

  9. Mysql数据库常规操作(建表、查询)

    一.表单操作 1-1.创建表 create table tb_name( id in primary key auto_increment);    1-2.查看表 desc table_name; ...

  10. angularCli打包遇到的一些问题

    有时在运行项目或者打包项目的时候会遇到报错信息:found version 4, expected 3, 这个大概意思是说该插件需要的依赖当前不支持,需要提高依赖的版本. 比如:@angular/co ...