类定义是以关键字 class 开头,后跟类的名称。类的主体是包含在一对花括号中,里面有类的属性与方法的定义。
类属性存在于数据段,类方法存在于代码段,对于一个类来说,类的方法不占用类的空间,占空间的只有类的属性。
要创建一个类的实例,必须使用 new 关键字。当创建新对象时该对象总是被赋值,除非该对象定义了构造函数并且在出错时抛出了一个异常。类应在被实例化之前定义(某些情况下则必须这样)。
如果在 new 之后跟着的是一个包含有类名的字符串,则该类的一个实例被创建。如果该类属于一个名字空间,则必须使用其完整名称。
//创建一个实例 <?php $instance = new SimpleClass(); // 也可以这样做: $className = 'Kin'; $instance = new $className(); // Kin() ?>
如果一个脚本中想要调用之前一个脚本的变量,但是前一个脚本已经执行完毕,所有的变量和内容释放掉了,我们要如何操作呢?
serialize和unserialize就是解决这一问题的存在,serialize可以将变量转换为字符串,并且在转换中可以保存当前变量的值;而unserialize则可以将serialize生成的字符串变换回变量。
所有php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示。序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。
可以这么理解:
在程序执行结束时,内存数据便会立即销毁,变量所储存的数据便是内存数据,而文件、数据库是“持久数据”,因此 PHP序列化就是将内存的变量数据“保存”到文件中的持久数据的过程。
举个栗子:
<?php class User { public $age = 0; public $name = ''; public function PrintData() { echo 'User '.$this->name.' is'.$this->age.' years old. <br />'; } } //创建一个对象 $user = new User(); // 设置数据 $user->age = 17; $user->name = 'kinyoobi'; //输出数据 $user->PrintData(); //输出序列化之后的数据 echo serialize($user); ?>
结果:
O 表示对象类型,4 表示对象名长度为4,User 为类名,2 表示有两个参数;
{} 里面是参数的key和value:s 表示是string类型,3 表示长度,age 是key;i 表示是integer类型,17 是value。
a | array | b | boolean |
d |
double | i | integer |
o | common object | r | reference |
s | string | C | custom object |
O | class | N | null |
R | pointer reference | U | unicode string |
反序列化就是将序列化格式化存储好的的字符还原成对象的过程。
注意:在解序列化一个对象前,这个对象的类必须在解序列化之前定义。否则会报错
举个栗子:
<?php class User { public $age = 0; public $name = ''; public function PrintData() { echo 'User '.$this->name.' is '.$this->age.' years old. <br />'; } } //重建对象 $user = unserialize('O:4:"User":2:{s:3:"age";i:17;s:4:"name";s:8:"kinyoobi";}'); $user->PrintData(); ?>
结果:
PHP 将所有以 __(两个下划线)开头的类方法保留为魔术方法,在特定的情况下会被调用。
__construct | 构造函数 |
__destruct | 对象被销毁时触发,析构函数 |
__toString | 把类当作字符串使用时触发 |
__wakeup() | unserialize前调用,用于预先准备对象资源 |
__sleep() | serialize前调用 |
__call() | 在对象上下文中调用不可访问的方法时触发 |
__callStatic() | 在静态上下文中调用不可访问的方法时触发 |
__get() | 试图读取一个并不存在的属性的时候被调用 |
__set() | 用于将数据写入不可访问的属性 |
__isset() | 在不可访问的属性上调用isset()或empty()触发 |
__unset() | 在不可访问的属性上使用unset()时触发 |
__invoke() | 脚本尝试将对象调用为函数时触发 |
1)__sleep()
serialize()函数会检查类中是否存在一个魔术方法 __sleep()。如果存在__sleep(),该魔术方法会先被调用,然后才执行序列化操作。
此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。如果该方法未返回任何内容,则 NULL 被序列化,并产生一个 E_NOTICE 级别的错误。
2)__wakeup()
unserialize()函数会检查是否存在一个 __wakeup()方法。如果存在,则会先调用 __wakeup 方法,预先准备对象需要的资源。
__wakeup() 经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。
举个栗子:
<?php class test{ public $varr1="abc"; public $varr2="123"; public function echoP(){ echo $this->varr1."<br>"; } public function __construct(){ echo "__construct<br>"; } public function __destruct(){ echo "__destruct<br>"; } public function __toString(){ return "__toString<br>"; } public function __sleep(){ echo "__sleep<br>"; //return array('varr1','varr2'); return array('varr1'); } public function __wakeup(){ echo "__wakeup<br>"; } } $obj = new test(); //实例化对象,调用__construct()方法,输出__construct $obj->echoP(); //调用echoP()方法,输出"abc" echo $obj; //obj对象被当做字符串输出,调用__toString()方法,输出__toString $s =serialize($obj); //obj对象被序列化,调用__sleep()方法,输出__sleep var_dump($s); echo "<br>"; $u = unserialize($s); //$s首先会被反序列化,会调用__wake()方法 var_dump($u); echo "<br>"; // 脚本结束又会调用__destruct()方法,输出__destruct ?>
结果:
其中在序列化时,__sleep返回了varr1,达到了清理数据的目的;而在反序列化时,即类恢复成对象的时候,类本身的类属性是不能被销毁的,所以最后会打印出来varr1和varr2。
参考:
https://www.cnblogs.com/ichunqiu/p/10484832.html
https://www.php.cn/php-weizijiaocheng-454909.html