在 PHP 进行序列化时会用到__sleep()和__wakeup()这两个构造函数.
序列化即将一个变量或者一个对象转换成字节流的过程. 序列化有效的解决了对象的保存和传输问题, 例如:在使用 session 并使用了 session_register() 函数来注册对象, 这些对象会在每个 PHP 页面结束时被自动序列化, 并在接下来的每个页面中自动解序列化, 这样在每个 PHP 页面中都可以使用这些对象
01 | //整型 |
02 | $var
= 23; |
03 | echo
serialize( $var ). "\n" ; //i:23;
|
04 | |
05 | //浮点型 |
06 | $var
= 1.23; |
07 | echo
serialize( $var ). "\n" ; //d:1.229999999999999982236431605997495353221893310546875; |
08 | |
09 | //字符串 |
10 | $var
= "This is a string" ; |
11 | echo
serialize( $var ). "\n" ; //s:16:"This is a string";
|
12 | |
13 | //布尔型 |
14 | $var
= true; |
15 | echo
serialize( $var ). "\n" ; //b:1;
|
16 | |
17 | //数组变量 |
18 | $var
= array ( "abc" , "def" ,
"xyz" , "123" );
|
19 | echo
serialize( $var ). "\n" ; //a:4:{i:0;s:3:"abc";i:1;s:3:"def";i:2;s:3:"xyz";i:3;s:3:"123";} |
20 | |
21 | $var
= array ( "index1" => "abc" , "index2" => "def" , "index3" => "xyz" , "index4" => "123" ); |
22 | echo
serialize( $var ). "\n" ; //a:4:{s:6:"index1";s:3:"abc";s:6:"index2";s:3:"def";s:6:"index3";s:3:"xyz";s:6:"index4";s:3:"123";} |
23 | |
24 | //对象序列化 |
25 | class
A{ |
26 | public $a
= "a string" ; |
27 | public $b
= 123; |
28 | public $c
= 123.12; |
29 | } |
30 | $obj
= new A;
|
31 | $str
= serialize( $obj ); |
32 | echo
$str . "\n" ; //O:1:"A":3:{s:1:"a";s:8:"a string";s:1:"b";i:123;s:1:"c";d:123.1200000000000045474735088646411895751953125;} |
33 | $obj2
= unserialize( $str ); //进行反序列化
|
34 | var_dump( $obj2 ==
$obj ); //bool(true) |
程序运行时, serialize() 检查类中是否有 __sleep() ,如果有,则该函数将在任何序列化之前运行. 该函数必须返回一个需要进行序列化保存的成员属性数组,并且只序列化该函数返回的这些成员属性. 该函数有两个作用: 第一. 在序列化之前,关闭对象可能具有的任何数据库连接等. 第二. 指定对象中需要被序列化的成员属性,如果某个属性比较大而不需要储存下来,可以不把它写进__sleep()要返回的数组中,这样该属性就不会被序列化
__sleep() 方法常被用于提交未提交的数据, 或者类似的操作.
与 __sleep() 方法相反的情况, unserialize() 函数会检测是否存在 __wakeup() 函数, 如果存在会先调用 __wakeup(), 预先准备对象数据. 在用 unserialize()时需要注意的一个问题: 在一个PHP页面中要 unserialize() 一个对象,需要该页面包含该对象的类的定义.也就是,如果序列化了 page1.php 中类 A 的对象 $a, 要在 page2.php 中将其反序列化重建类 A 的对象 $a, 则 page2.php 中必须要出现类 A 的定义. 这可以这样实现,将类 A 的定义放在一个包含文件中,并在 page1.php 和 page2.php 都包含此文件. 所以强烈建议在所有的页面中都包括这些注册的对象的类的定义, 即使并不是在所有的页面中都用到了这些类. 如果没有这样做, 一个对象被反序列化了但却没有其类的定义,它将失去与之关联的类并成为 stdClass 的一个对象而完全没有任何可用的函数。
01 | //classa.inc: |
02 | class
A |
03 | { |
04 | var $one
= 1; |
05 | |
06 | function show_one()
|
07 | {
|
08 | echo $this ->one;
|
09 | }
|
10 | } |
11 | |
12 | //page1.php: |
13 | include ( "classa.inc" ); |
14 | |
15 | $a
= new A; |
16 | $s
= serialize( $a ); |
17 | $fp
= fopen ( "store" , "w" );
// 将 $s 存放在某处使 page2.php 能够找到 |
18 | fputs ( $fp , $s );
|
19 | fclose( $fp ); |
20 | |
21 | //page2.php: |
22 | include ( "classa.inc" ); // 为了正常解序列化需要这一行
|
23 | |
24 | $s
= implode( "" , @file( "store" )); |
25 | $a
= unserialize( $s ); |
26 | |
27 | $a ->show_one(); // 现在可以用 $a 对象的 show_one() 函数了 |
__wakeup() 方法经常用在反序列化操作中, 例如重新建立数据库连接,或其他的初始化工作.
例子:
01 | class
Connection { |
02 | protected $link ;
|
03 | private $server ,
$username , $password ,
$db ; |
04 | |
05 | public function
__construct( $server , $username ,
$password ,
$db ) |
06 | {
|
07 | $this ->server = $server ;
|
08 | $this ->username = $username ;
|
09 | $this ->password = $password ;
|
10 | $this ->db = $db ;
|
11 | $this ->connect(); |
12 | }
|
13 | |
14 | private function
connect() |
15 | {
|
16 | $this ->link = mysql_connect( $this ->server, $this ->username, $this ->password); |
17 | mysql_select_db( $this ->db, $this ->link);
|
18 | }
|
19 | |
20 | public function
__sleep() |
21 | {
|
22 | return array ( 'server' , 'username' ,
'password' ,
'db' ); |
23 | }
|
24 | |
25 | public function
__wakeup() |
26 | {
|
27 | $this ->connect(); |
28 | }
|
29 | } |