仓酷云

标题: PHP教程之PHP 序列化(serialize)格局详解 [打印本页]

作者: 愤怒的大鸟    时间: 2015-2-4 00:09
标题: PHP教程之PHP 序列化(serialize)格局详解
怎么培养啊 别光说不练啊,好 ,比如新人入门自己步是配置环境,虽然现在都有很多的集成环境,但是真实的体验下配置环境还是会有很多帮助,不论是你以后工作还是在真实的linux下开发。详解   由 andot 写的十分经典引见PHP序列化的文章,原文来自: http://www.coolcode.cn/?p=170

1.媒介
PHP (从 PHP 3.05 入手下手)为保留对象供应了一组序列化和反序列化的函数:serialize、unserialize。不外在 PHP 手册中对这两个函数的申明仅限于若何利用,而对序列化了局的格局却没做任何申明。因而,这对在其他言语中完成 PHP 体例的序列化来讲,就对照费事了。固然之前也汇集了一些其他言语完成的 PHP 序列化的法式,不外这些完成都不完整,当序列化或反序列化一些对照庞杂的对象时,就会失足了。因而我决意写一份关于 PHP 序列化格局详解的文档(也就是这一篇文档),以便在编写其他言语完成的 php 序列化法式时能有一个对照完全的参考。这篇文章中所写的内容是我经由过程编写法式测试和浏览 PHP 源代码失掉的,所以,我不克不及 100% 包管一切的内容都是准确的,不外我会尽可能包管我所写下的内容的准确性,关于我还不太清晰的中央,我会在文中明白指出,也但愿人人可以赐与增补和完美。

2.概述
PHP 序列化后的内容是复杂的文本格局,然而对字母巨细写和空白(空格、回车、换行等)敏感,并且字符串是依照字节(或说是 8 位的字符)盘算的,因而,更适合的说法是 PHP 序列化后的内容是字撙节格局。因而用其他言语完成时,假如所完成的言语中的字符串不是字节贮存格局,而是 Unicode 贮存格局的话,序列化后的内容不合适保留为字符串,而应保留为字撙节对象或字节数组,不然在与 PHP 停止数据互换时会发生毛病。
PHP 对分歧类型的数据用分歧的字母停止标示,Yahoo 开辟网站供应的 Using Serialized PHP with Yahoo! Web Services 一文中给出一切的字母标示及其寄义:
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
N 暗示的是 NULL,而 b、d、i、s 暗示的是四种标量类型,今朝其它言语所完成的 PHP 序列化法式根基上都完成了对这些类型的序列化和反序列化,不外有一些完成中对 s (字符串)的完成存在成绩。
a、O 属于最经常使用的复合类型,大局部其他言语的完成都很好的完成了对 a 的序列化和反序列化,但对 O 只完成了 PHP4 中对象序列化格局,而没有供应对 PHP 5 中扩大的对象序列化格局的撑持。
r、R 分离暗示对象援用和指针援用,这两个也对照有效,在序列化对照庞杂的数组和对象时就会发生带有这两个标示的数据,前面咱们将具体解说这两个标示,今朝这两个标示尚没有发明有其他言语的完成。
C 是 PHP5 中引入的,它暗示自界说的对象序列化体例,虽然这关于其它言语来讲是没有需要完成的,由于很少会用到它,然而前面仍是会对它停止具体解说的。
U 是 PHP6 中才引入的,它暗示 Unicode 编码的字符串。由于 PHP6 中供应了 Unicode 体例保留字符串的才能,因而它供应了这类序列化字符串的格局,不外这个类型 PHP5、PHP4 都不撑持,而这两个版本今朝是主流,因而在其它言语完成该类型时,不保举用它来停止序列化,不外可以完成它的反序列化进程。在前面我也会对它的格局停止申明。
最初还有一个 o,这也是我独一还没弄清晰的一个数据类型标示。这个标示在 PHP3 中被引入用来序列化对象,然而到了 PHP4 今后就被 O 代替了。在 PHP3 的源代码中可以看到对 o 的序列化和反序列化与数组 a 根基上是一样的。然而在 PHP4、PHP5 和 PHP6 的源代码中序列化局部里都找不到它的影子,然而在这几个版本的反序列化法式源代码中却都有对它的处置,不外把它处置成甚么我还没弄清晰。因而对它临时不再作更多申明了。

3.NULL 和标量类型的序列化
NULL 和标量类型的序列化是最复杂的,也是组成合适类型序列化的基本。这局部内容信任很多 PHP 开辟者都已熟知。假如您感到已把握了这局部内容,可以直接跳过这一章。
3.1.NULL 的序列化
在 PHP 中,NULL 被序列化为:
N;
3.2.boolean 型数据的序列化
boolean 型数据被序列化为:
b:<digit>;
个中 <digit> 为 0 或 1,当 boolean 型数据为 false 时,<digit> 为 0,不然为 1。
3.3.integer 型数据的序列化
integer 型数据(整数)被序列化为:
i:<number>;
个中 <number> 为一个整型数,局限为:-2147483648 到 2147483647。数字前可以有正负号,假如被序列化的数字超越这个局限,则会被序列化为浮点数类型而不是整型。假如序列化后的数字超越这个局限(PHP 自己序列化时不会产生这个成绩),则反序列化时,将不会前往希冀的数值。
3.4.double 型数据的序列化
double 型数据(浮点数)被序列化为:
d:<number>;
个中 <number> 为一个浮点数,其局限与 PHP 中浮点数的局限一样。可以暗示成整数模式、浮点数模式和迷信手艺法模式。假如序列化后的数字局限超越 PHP 能暗示的最大值,则反序列化时前往无量大(INF),假如序列化后的数字局限超越 PHP 所能暗示的最小精度,则反序列化时前往 0。
3.5.string 型数据的序列化
string 型数据(字符串)被序列化为:
s:<length>:"<value>";
个中 <length> 是 <value> 的长度,<length> 长短负整数,数字前可以带有正号(+)。<value> 为字符串值,这里的每一个字符都是单字节字符,其局限与 ASCII 码的 0 - 255 的字符绝对应。每一个字符都暗示原字符寄义,没有本义字符,<value> 双方的引号("")是必需的,但不盘算在 <length> 傍边。这里的 <value> 相当于一个字撙节,而 <length> 是这个字撙节的字节个数。
4.复杂复合类型的序列化
PHP 中的复合类型无数组(array)和对象(object)两种,本章次要引见在复杂情形下这两品种型数据的序列化格局。关于嵌套界说的复合类型和自界说序列化体例的对象的序列化格局将在前面的章节具体会商。
4.1.数组的序列化
数组(array)凡是被序列化为:
a:<n>:{<key 1><value 1><key 2><value 2>...<key n><value n>}
个中 <n> 暗示数组元素的个数,<key 1>、<key 2>……<key n> 暗示数组下标,<value 1>、<value 2>……<value n> 暗示与下标绝对应的数组元素的值。
下标的类型只能是整型或字符串型,序列化后的格局跟整型和字符串型数据序列化后的格局不异。
数组元素值可所以恣意类型,其序列化后的格局与其所对应的类型序列化后的格局不异。
4.2.对象的序列化
对象(object)凡是被序列化为:
O:<length>:"<class name>":<n>:{<field name 1><field value 1><field name 2><field value 2>...<field name n><field value n>}
个中 <length> 暗示对象的类名 <class name> 的字符串长度。<n> 暗示对象中的字段1个数。这些字段包含在对象地点类及其先人类顶用 var、public、protected 和 private 声明的字段,然而不包含 static 和 const 声明的静态字段。也就是说只要实例(instance)字段。
<filed name 1>、<filed name 2>……<filed name n>暗示每一个字段的字段名,而 <filed value 1>、<filed value 2>……<filed value n> 则暗示与字段名所对应的字段值。
字段名是字符串型,序列化后格局与字符串型数据序列化后的格局不异。
字段值可所以恣意类型,其序列化后的格局与其所对应的类型序列化后的格局不异。
但字段名的序列化与它们声明的可见性是有关的,上面重点会商一下关于字段名的序列化。
4.3.对象字段名的序列化
var 和 public 声明的字段都是公共字段,因而它们的字段名的序列化格局是不异的。公共字段的字段名依照声明时的字段名停止序列化,但序列化后的字段名中不包含声明时的变量前缀符号 $。
protected 声明的字段为回护字段,在所声明的类和该类的子类中可见,但在该类的对象实例中不成见。因而回护字段的字段名在序列化时,字段名后面会加上
\0*\0
的前缀。这里的 \0 暗示 ASCII 码为 0 的字符,而不是 \0 组合。
private 声明的字段为公有字段,只在所声明的类中可见,在该类的子类和该类的对象实例中均不成见。因而公有字段的字段名在序列化时,字段名后面会加上
\0<declared class name>\0
的前缀。这里 <declared class name> 暗示的是声明该公有字段的类的类名,而不是被序列化的对象的类名。由于声明该公有字段的类纷歧定是被序列化的对象的类,而有多是它的先人类。
字段名被作为字符串序列化时,字符串值中包含依据其可见性所加的前缀。字符串长度也包含所加前缀的长度。个中 \0 字符也是盘算长度的。

--------------------------------------------------------------------------------
1注:在 PHP 手册中,字段被称为属性,而实践上,在 PHP 5 中引入的用 __set、__get 来界说的对象成员更合适叫做属性。由于用 __set、__get 来界说的对象成员与其它言语中的属性的行动是分歧,而 PHP 手册中所说的属性实践上在其他言语中(例如:C#)中被称为字段,为了不搅浑,这里同样成为字段,而不是属性。
5.嵌套复合类型的序列化
上一章会商了复杂的复合类型的序列化,人人会发明关于复杂的数组和对象其实也很轻易。然而假如碰到本人包括本人或 A 包括 B,B 又包括 A 这类的对象或数组时,PHP 又该若何序列化这类对象和数组呢?本章咱们就来会商这类情形下的序列化模式。
5.1.对象援用和指针援用
在 PHP 中,标量类型数据是值传递的,而复合类型数据(对象和数组)是援用传递的。然而复合类型数据的援用传递和用 & 符号明白指定的援用传递是有区分的,前者的援用传递是对象援用,尔后者是指针援用。
在注释对象援用和指针援用之前,先让咱们看几个例子。
<?php
echo "<pre>";
class SampleClass {
    var $value;
}
$a = new SampleClass();
$a->value = $a;

$b = new SampleClass();
$b->value = &$b;

echo serialize($a);
echo "\n";
echo serialize($b);
echo "\n";
echo "</pre>";
?>
这个例子的输入了局是如许的:
O:11:"SampleClass":1:{s:5:"value";r:1;}
O:11:"SampleClass":1:{s:5:"value";R:1;}
人人会发明,这里变量 $a 的 value 字段的值被序列化成了 r:1,而 $b 的 value 字段的值被序列化成了 R:1。
然而对象援用和指针援用究竟有甚么区分呢?
人人可以看上面这个例子:
echo "<pre>";
class SampleClass {
    var $value;
}
$a = new SampleClass();
$a->value = $a;

$b = new SampleClass();
$b->value = &$b;

$a->value = 1;
$b->value = 1;

var_dump($a);
var_dump($b);
echo "</pre>";
人人会发明,运转了局或许出乎你的意料:
object(SampleClass)#1 (1) {
  ["value"]=>
  int(1)
}
int(1)
改动 $a->value 的值仅仅是改动了 $a->value 的值,而改动 $b->value 的值却改动了 $b 自己,这就是对象援用和指针援用的区分。
不外很不幸的是,PHP 对数组的序列化犯了一个毛病,固然数组自己在传递时也是对象援用传递,然而在序列化时,PHP 仿佛健忘了这一点,看上面的例子:
echo "<pre>";
$a = array();
$a[1] = 1;
$a["value"] = $a;

echo $a["value"]["value"][1];
echo "\n";
$a = unserialize(serialize($a));
echo $a["value"]["value"][1];
echo "</pre>";
了局是:
1
人人会发明,将原数组序列化再反序列化后,数组布局变了。本来 $a["value"]["value"][1] 中的值 1,在反序列化以后丧失了。
缘由是甚么呢?让咱们输入序列化以后的了局来看一看:
$a = array();
$a[1] = 1;
$a["value"] = $a;

echo serialize($a);
了局是:
a:2:{i:1;i:1;s:5:"value";a:2:{i:1;i:1;s:5:"value";N;}}
本来,序列化以后,$a["value"]["value"] 酿成了 NULL,而不是一个对象援用。
也就是说,PHP 只对对象在序列化时才会生成对象援用标示(r)。对一切的标量类型和数组(也包含 NULL)序列化时都不会生成对象援用。然而假如明白利用了 & 符号作的援用,在序列化时,会被序列化为指针援用标示(R)。
5.2.援用标示后的数字
在下面的例子中人人能够已看到了,对象援用(r)和指针援用(R)的格局为:
r:<number>;
R:<number>;
人人必定很奇异前面这个 <number> 是甚么吧?本节咱们就来具体会商这个成绩。
这个 <number> 复杂的说,就是所援用的对象在序列化串中第一次呈现的地位,然而这个地位不是指字符的地位,而是指对象(这里的对象是泛指一切类型的量,而不但限于对象类型)的地位。
我想人人能够还不是很分明,那末我来举例申明一下:
class ClassA {
    var $int;
    var $str;
    var $bool;
    var $obj;
    var $pr;
}

$a = new ClassA();
$a->int = 1;
$a->str = "Hello";
$a->bool = false;
$a->obj = $a;
$a->pr = &$a->str;

echo serialize($a);
这个例子的了局是:
O:6:"ClassA":5:{s:3:"int";i:1;s:3:"str";s:5:"Hello";s:4:"bool";b:0;s:3:"obj";r:1;s:2:"pr";R:3;}
在这个例子中,起首序列化的对象是 ClassA 的一个对象,那末给它编号为 1,接上去要序列化的是这个对象的几个成员,第一个被序列化的成员是 int 字段,那它的编号就为 2,接上去被序列化的成员是 str,那它的编号就是 3,依此类推,到了 obj 成员时,它发明该成员已被序列化了,而且编号为 1,因而它被序列化时,就被序列化成了 r:1; ,在接上去被序列化的是 pr 成员,它发明该成员实践上是指向 str 成员的一个援用,而 str 成员的编号为 3,因而,pr 就被序列化为 R:3; 了。
PHP 是若何来编号被序列化的对象的呢?实践上,PHP 在序列化时,起首创立一个空表,然后每一个被序列化的对象在被序列化之前,都需求先盘算该对象的 Hash 值,然后判别该 Hash 值是不是已呈现在该表中了,假如没有呈现,就把该 Hash 值添加到这个表的最初,前往添加胜利。假如呈现了,则前往添加掉败,然而在前往掉败前先判别该对象是不是是一个援用(用 & 符号界说的援用),假如不是则也把 Hash 值添加到表后(虽然前往的是添加掉败)。假如前往掉败,则同时前往上一次呈现的地位。
在添加 Hash 值到表中以后,假如添加掉败,则判别添加的是一个援用仍是一个对象,假如是援用,则前往 R 标示,假如是对象,则前往 r 标示。由于掉败时,会同时前往上一次呈现的地位,因而,R 和 r 标示前面的数字,就是这个地位。
5.3.对象援用的反序列化
PHP 在反序列化处置对象援用时很成心思,假如反序列化的字符串不是 PHP 的 serialize() 自己生成的,而是工资机关或用其它言语生成的,即便对象援用指向的不是一个对象,它也能准确地依照对象援用所指向的数据停止反序列化。例如:
echo "<pre>";
class StrClass {
    var $a;
    var $b;
}

$a = unserialize('O:8:"StrClass":2:{s:1:"a";s:5:"Hello";s:1:"b";r:2;}');

var_dump($a);
echo "</pre>";
运转了局:
object(StrClass)#1 (2) {
  ["a"]=>
  string(5) "Hello"
  ["b"]=>
  string(5) "Hello"
}
人人会发明,下面的例子反序列化后,$a->b 的值与 $a->a 的值是一样的,虽然 $a->a 不是一个对象,而是一个字符串。因而假如人人用其它言语来完成序列化的话,纷歧定非要把 string 作为标量类型来处置,即便依照对象援用来序列化具有不异字符串内容的复合类型,用 PHP 一样可以准确的反序列化。如许可以更节俭序列化后的内容所占用的空间。

6.自界说对象序列化
TBD
7.Unicode 字符串的序列化
TBD
8.参考文献
PHP 3 中关于序列化和反序列化的源代码
PHP 4 中关于序列化的源代码
PHP 4 中关于反序列化的源代码
PHP 5 中关于序列化的源代码
PHP 5 中关于反序列化的源代码
PHP 6 中关于序列化的源代码
PHP 6 中关于反序列化的源代码
PHP 手册中关于序列化和反序列化的引见
Using Serialized PHP with Yahoo! Web Services
一些其他言语完成的 PHP serialize
JavaScript 版本(stable):http://www.devpro.it/code/102.html
Perl 版本(stable):http://hurring.com/code/perl/serialize/
另外一个 Perl 版本:http://www.cpan.org/modules/by-module/PHP/JBROWN/php-serialization/
Python 版本(beta):http://hurring.com/code/python/serialize/
Java 版本(pre-alpha):http://hurring.com/code/java/serialize/
Ruby 版本:http://www.aagh.net/files/ruby/php_serialize.rb
Flash/Actionscript 版本:http://sourceforge.net/projects/serializerclass/
C# 版本:http://sourceforge.net/projects/csphpserial/


不懂的问题有很多高手帮你解决。但不要认为你是新手,就不能帮助别人,比如今天你学会了怎样安装PHP,明天还可能有朋友会问这个问题,你就可以给他解答,不要认为这是浪费时间,忙别人其实就是帮助自己。
作者: 冷月葬花魂    时间: 2015-2-4 09:45
多看优秀程序员编写的代码,仔细理解他们解决问题的方法,对自身有很大的帮助。
作者: 因胸联盟    时间: 2015-2-4 13:43
这些中手常用的知识,当你把我说的这些关键字都可以熟练运用的时候,你可以选择自己
作者: 再现理想    时间: 2015-2-10 00:24
我要在声明一下:我是个菜鸟!!我对php这门优秀的语言也是知之甚少。但是我要在这里说一下php在网站开发中最常用的几个功能:
作者: 变相怪杰    时间: 2015-2-28 09:08
对于懒惰的朋友,我推荐php的集成环境xampp或者是wamp。这两个软件安装方便,使用简单。但是我还是强烈建议自己动手搭建开发环境。
作者: 兰色精灵    时间: 2015-3-1 02:19
要进行开发,搭建环境是首先需要做的事,windows下面我习惯把环境那个安装在C盘下面,因为我配的环境经常出现诡异事件,什么事都没做环境有的时候就不能用啦。
作者: 海妖    时间: 2015-3-10 12:11
多看优秀程序员编写的代码,仔细理解他们解决问题的方法,对自身有很大的帮助。
作者: 愤怒的大鸟    时间: 2015-3-17 06:12
其实没啥难的,多练习,练习写程序,真正的实践比看100遍都有用。不过要熟悉引擎
作者: 简单生活    时间: 2015-3-17 06:12
我要在声明一下:我是个菜鸟!!我对php这门优秀的语言也是知之甚少。但是我要在这里说一下php在网站开发中最常用的几个功能:
作者: 金色的骷髅    时间: 2015-3-23 23:15
在学习的过程中不能怕麻烦,不能有懒惰的思想。学习php首先应该搭建一个lamp环境或者是wamp环境。这是学习php开发的根本。虽然网络上有很多集成的环境,安装很方便,使用起来也很稳定、
作者: 灵魂腐蚀    时间: 2015-3-28 01:49
对于初学者来说不推荐去拿钱买的。当然如果一个网站你经常去用,而且里面的资料也比较有用,最好还是买个会员比较好,毕竟那些也是别人的工作成果。
作者: 蒙在股里    时间: 2015-4-1 00:25
微软最近出的新字体“微软雅黑”,虽然是挺漂亮的,不过firefox  支持的不是很好,所以能少用还是少用的好。
作者: 小魔女    时间: 2015-4-16 13:10
真正的方向了,如果将来要去开发团队,你一定要学好smarty ,phplib这样的模板引擎,
作者: 深爱那片海    时间: 2015-4-16 19:10
多看优秀程序员编写的代码,仔细理解他们解决问题的方法,对自身有很大的帮助。
作者: 飘灵儿    时间: 2015-4-16 23:10
有时候汉字的空格也能导致页面出错,所以在写代码的时候,要输入空格最好用引文模式。
作者: 若天明    时间: 2015-4-26 16:22
小鸟是第一次发帖(我习惯潜水的(*^__^*) 嘻嘻……),有错误之处还请大家批评指正,另外,前些日子听人说有高手能用php写驱动程序,真是学无止境,人外有人,天外有天。
作者: 透明    时间: 2015-5-6 10:10
首先我是坚决反对新手上来就用框架的,因为对底层的东西一点都不了解,造成知识上的真空,会对以后的发展不利。我的观点上手了解下框架就好,代码还是手写。当然啦如果是位别的编程语言的高手的话,这个就另当别论啦。
作者: 飘飘悠悠    时间: 2015-5-12 09:07
首推的搜索引擎当然是Google大神,其次我比较喜欢 百度知道。不过搜出来的结果往往都是 大家copy来copy去的,运气的的概率很大。
作者: 爱飞    时间: 2015-6-4 02:33
小鸟是第一次发帖(我习惯潜水的(*^__^*) 嘻嘻……),有错误之处还请大家批评指正,另外,前些日子听人说有高手能用php写驱动程序,真是学无止境,人外有人,天外有天。
作者: 老尸    时间: 2015-6-6 06:02
写的比较杂,因为我也是个新手,不当至于大家多多指正。
作者: 只想知道    时间: 2015-6-11 10:34
如果你已经到这种程度了,那么你已经可以做我的老师了。其实php也分很多的区域,




欢迎光临 仓酷云 (http://ckuyun.com/) Powered by Discuz! X3.2