在网上看到一篇关于php对象在内存中分配的博文,特地记录下来,再稍微修饰下。
对像在PHP 里面和整型、浮点型一样,也是一种数据类,都是存储不同类型数据用的, 在运行的时候都要加载到内存中去用,那么对象在内存里面是怎么体现的呢?
内存从逻 辑上 说大体上是分为4 段,栈空间段、堆空间段、代码段、初始化静态段,程序里面不同的声明 放在不同的内存段里面。
数据段(data segment)通常是指用来存放程序中已初始化且不为0的全局变量如:静态变量和常量;
代码段(code segment / text segment)通常是指用来存放程序执行代码的一块内存区域,比如函数和方法;
栈空间段是
存储占用相同空间长度并且占用空间小的数据类型的地方,比如说整型1,10,100,1000,10000,100000
等等,在内存里面占用空间是等长的,都是64 位4
个字节。
堆内存 数据长度不定长,而且占有空间很大的数据类型的数据。如下图:
栈内存是可以直接存取的,而堆内存不可以直接存取。对于我们的对象来数就是一种大的数据类型而且是占用空间不定长的类型,所以说对象是放在堆里面的,但对象名称是放在栈里面的,这样通过对象名称就可 以使用对象了。
/*
* 下面三个变量都是独立的,相互之间没有关系
* $p1,$p2,$p3放在栈内存里,new出来的Person放在对内存里面,通过$p1,$p2,$p3可以访问各自new出来的Person
**/
$p1=new Person(); $p2=new Person(); $p3=new Person();
对于我们的对象来说就是一种大的数据类型而且是占用空间不定长的类型,所以说对象是放在堆里面的,但对象名称是放在栈里面的,这样通过对象名称就可以使用对象了。
$p1 就是我们实例出来的对象名称,同理,$p2,$p3
也是我们实例出来的对象名称,一个类可以实例出多个对象,每个对象都是独立的,
上面的代码相当于实例出来3
个人来,每个人之间是没有联系的,只能说明他们都是人类,每 个人都有自己的姓名,性别和年龄的属性,每个人都有说话和走路的方法,只要是类里面体现出来的成员属性和成员方法,实例化出来的对象里面就包含了这些属性和方法。
请看下图:
从上图可以看到,等号右边是真正的实例对象,是存储在堆内存中的对象实体。
上图一共有三个new Person,所以会在堆内存中开辟出三个独立的空间,产生3个实例对象,每个实例对象都是独立的,独享自己的空间。
每个在堆里面的实例对象是存储属性的,比如说,现在堆里面的实例对象里面都存有姓名、性别和年龄。每个属性又都有一个地址。
$p1=new Person();
等号的左边$p1 是一个引用变量,通过赋值运算符“=”把对象的首地址 赋给“$p1”这个引用变量,所以$p1 是存储对象首地址的变量,$p1 放在栈内存里边,$p1 相当 于一个指针指向堆里面的对象,所以我们可以通过$p1 这个引用变量来操作对象,通常我们也称对象引用为对象。
最后来做一个容易混淆的验证:
class Person{ public $name; } $obj1 = new Person(); $obj1->name = "test1"; echo $obj1->name; $obj2 = $obj1; $obj2->name = "test2"; echo $obj1->name; echo $obj2->name;
$p1 是对象的指针而不是对象本身, obj2和 obj1都指向同一块内存,同一个对象。这一点和OOP语言是一样
object(Person)[2]
public 'name' => string 'test2' (length=5)
object(Person)[2]
public 'name' => string 'test2' (length=5)
可见对象的ID号是一个
如果想得到一个对象的副本,用$obj2 =clone $obj1; 用了clone后会产生一个新对象,分配内存,独立于原来的obj1
$obj2 = $obj1;
$obj2 = &$obj1;
一样的效果,一样的解释?
对于object来说,是一样的。 对于普通的变量是不一样的。
$a = 1;
$b = $a;
$c = &$a;
不一样的