打印

[php] PHP串行化与JSON[连载][已完成]

PHP串行化与JSON,原创教程,首发蓝色理想经典论坛,本文在2008年4月15日之前不允许转载,谢谢。
作者:hanguofeng(小韩)
博客:http://www.hanguofeng.com
本文在博客上的地址(同步更新):http://www.hanguofeng.cn/archives/web-server/php-serialize-json
连载预计于4月1日前完成

总目录
What 、Why、How       

What       
Why       
How       
PHP串行化语法       
PHP串行化实例       
在JavaScript中串行化为JSON—使用json2.js       
在JavaScript中串行化为JSON—使用prototype.js
       
PHP与JSON       
json_decode函数       
json_encode函数       
json_decode函数实例       
json_encode函数实例       

实践出真知
背景说明       
前台JavaScript部分       
后台PHP部分
       
我还有话要说

[ 本帖最后由 kuhanzhu 于 2008-4-1 18:41 编辑 ]
本帖最近评分记录
  • kuhanzhu 威望 +2 原创内容,谢谢分享,值得阅读。请再接 ... 2008-3-22 20:43
What 、Why、How

What
Ok,各位亲爱的朋友,让我们开始这个新概念的旅程,串行化这个话题可能大家以前都没有多加关注,事情其实起源于那天我随便翻翻PHP手册,发现这个串行化的函数,之后闲来无聊又做一个WordPress的插件,这个时候顺便用了一下串行化,发现在某些场合的确非常方便。
先来解释下串行化:简单来说,串行化即将变量转换成字节流的过程。串行化的提出,有效的解决了对象的保存和传输的问题,举例来说,我在JavaScript中建立了一个对象,我现在想将这个对象保存到服务器端的数据库中,那么我如何进行操作呢,这个时候往往就用到了对象的串行化。在JavaScript的串行化中不得不提JSON,JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。易于人阅读和编写,同时也易于机器解析和生成。它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。这些特性使JSON成为理想的数据交换语言。
人们通常将JSON和XML进行比较,二者都是将对象扁平化(稍后我们解释这个“扁平化”)的一种手段,XML的特点是结构严谨,而JSON的特点则是简单易读、容易使用程序进行分析,因为它能够很简单的将一个对象转换为一个字符流的形式,例如如下代码:
复制内容到剪贴板
代码:
{"type":"human","name":"hanguofeng","age":22}
则是一个JSON表达式,他保存了一个对象,我们如何将它恢复为对象呢?很简单,如下:
复制内容到剪贴板
代码:
var animal_str = '{"type":"human","name":"hanguofeng","age":22}';
var animal2=eval('(' + animal_str + ')');
我们通过JavaScript的求值函数,将JSON表达式进行运算,并返回值,用以获得一个对象,到这里,我想你一定会和我一样,对JSON格式的创造者的思维佩服不已吧。
本来说讲串行化的,“不小心”谈到JSON,并且讲了这么多,呵呵,跑题了吗?没有,PHP的串行化和JSON是非常像的,一个PHP的串行化表达式如下:
复制内容到剪贴板
代码:
a:3:{s:4:"type";s:5:"human";s:4:"name";s:10:"hanguofeng";s:3:"age";s:2:"20";}
他看起来结构和JSON有些类似,实际上,这个表达式是如下数组的串行化结果:
复制内容到剪贴板
代码:
$animal =
array
(
    "type" => "human",
    "name" => "hanguofeng",
    "age"  => "20"
);
OK,上面的一些介绍只是让你大致看到串行化和JSON是什么样的东西,你无须对这里的代码过分纠结,我们在后面会详细讲解的,下面我们来谈谈为什么要使用串行化。

Why
串行化首先是作为数据传输的方便而出现的,正如本文开始我提出的问题,我在JavaScript中建立了一个对象,我现在想将这个对象保存到服务器端的数据库中,应该如何做,这其实上是一个“我如何将一个对象从浏览器提交到服务器”的问题,在这个传输过程中,我们知道,实际上只能够传递字符流,字符流是一维(扁平)的,然而很多对象却是多维的,如果要传递的对象是一个字符串,那么很简单,我们直接将其作为传递的内容就可以了,如果要传递的对象是一个数组或者其他的结构呢,我们就需要用字符流来描述他,就比如在电话里面,我问你的名字是什么,你会告诉我,你的名字是张三、李四,而我问你,你的长相如何呢,你就需要用文字向我描述了,我们进行数据传递的媒介往往和这条电话线路一样,只能传递字符流,而我们描述对象的过程,实际上就是串行化的过程。
另外,串行化也可以用于对对象的持久化存储,也许你曾经也和我一样,想着在数据库的某一个字段中存储一个对象,现在我们可以非常简单的做到这一点,并且,你的这个数据库字段不需要设定为特殊格式,设定为varchar就可以了(当然,如果对象很大,你可能需要设定为text)。

How

PHP串行化语法
好了,我想What和Why的问题你都了解了,本节最后我们来讲点理论性强一些的内容,就是如何使用PHP串行化和反串行化数据,如何将JavaScript对象串行化(即变为JSON格式)和如何将其反串行化,最后则是如何将JSON和PHP的串行化建立关系。
PHP为我们提供了两个函数,用来进行串行化和反串行化的操作,这两个函数分别是:serialize()和unserialize(),他们适用于PHP4和PHP5,下面分别进行讲解:

serialize()
(PHP 4, PHP 5, PECL axis2:0.1.0-0.1.1)
serialize — 获得一个可存储的表述值
说明
string serialize ( mixed $value )
获得一个可存储的表述值
本函数用于无损的存储或者传递PHP变量值和结构。
如果需要将已经串行化的值转回PHP变量,可以使用unserialize()函数。
参数
value
即被串行化的表达式。serialize()处理除资源指针之外的所有类型,你甚至可以将含有指向自身元素的数组串行化。你串行化的含有循环指向的数组或者对象一样会被存储,其他的指向则会丢失。
当串行化对象时,PHP会尝试首先调用其成员函数__sleep()。这将允许对象在被串行化之前进行诸如最后的清理工作等。同样地,当使用unserialize()函数将对象恢复时,会调用成员函数__wakeup()。
返回值
       返回一个可以被存储在任何地点的包含对象的字节流表达式的字符串。
unserialize()
(PHP 4, PHP 5, PECL axis2:0.1.0-0.1.1)
unserialize — 从一个已存储的表达式中获得一个PHP变量值
说明
mixed unserialize ( string $str )
unserialize()获取一个简单类型的串行化变量并将其转换回PHP变量值。
参数
str
       串行化后的字符串
如果被反串行化的变量是一个对象,则成功恢复该对象的结构后,PHP将自动尝试执行该对象的__wakeup()成员函数(如果其存在)。
unserialize_callback_func指令:你可以设定在此过程中呗执行的回调函数,如果某个未被定义的类应当在反串行化时被实例化(以避免获得一个不完全的对象“__PHP_Incomplete_Class”)。你可以使用php.ini,ini_set()或者.htaccess来定义“unserialize_callback_func”。当一个未被定义的类被实例化时,它会被调用。屏蔽这个特性只需将其设为空即可。
返回值
返回转换后的数值,可能是布尔变量、实数、浮点数、字符串、数组或者对象。
假如传入的字符串不可以被反串行化,则返回FALSE,同时抛出NOTICE错误。
(以上译自PHP手册)

PHP串行化实例

数组的串行化和反串行化
OK,让我们来用实例学习一下,首先,请建立sample1.php文件,我们在这个文件中用如下语句来创建一个哈希数组:
复制内容到剪贴板
代码:
<?php
$animal =
array
(
    "type" => "human",
    "name" => "hanguofeng",
    "age"  => "20"
);
?>
为了测试这个数组的值,你可以使用print_r()函数来输出数组,输出的结果如下:
复制内容到剪贴板
代码:
Array
(
    [type] => human
    [name] => hanguofeng
    [age] => 20
)
那么我们将他来串行化一下,串行化的代码如下:
复制内容到剪贴板
代码:
<?php
$animal =
array
(
    "type" => "human",
    "name" => "hanguofeng",
    "age"  => "20"
);
$animal_ser=serialize($animal);
echo($animal_ser);
?>
这里我们将数组$animal串行化,将返回的串行化字符串保存在变量$animal_ser中,并输出,输出的结果是:
复制内容到剪贴板
代码:
a:3:{s:4:"type";s:5:"human";s:4:"name";s:10:"hanguofeng";s:3:"age";s:2:"20";}
我们来简单对这个字符串进行一个解析:
a:3表示这是一个数组型的对象(a),他共有三个内置的对象(3)
大括号里面的部分是以逗号分割的对象表达式列表,以s:4:"type"为例,他表示一个字符串(s),长度为4位(4),值为“type”,即哈希数组的第一个元素的键。
后面的部分以此类推,我们不再赘述,你可以试试自己将各种对象串行化,看看串行化后的字符串是如何构建的。
下面来看数组的反串行化,即将我们上面生成的串行化字符串恢复为数组,代码如下:
复制内容到剪贴板
代码:
<?php
$animal_ser='a:3:{s:4:"type";s:5:"human";s:4:"name";s:10:"hanguofeng";s:3:"age";s:2:"20";}';
$animal = unserialize($animal_ser);
print_r($animal);
?>
在第一行中,我们假设$animal_ser的值为上面获得的串行化字符串,在第二行将该字符串恢复为开始的数组,并赋值给$animal,最后输出$animal这个数组,此时的输出和本节开始时输出的原始数组是一样的,即:
复制内容到剪贴板
代码:
Array
(
    [type] => human
    [name] => hanguofeng
    [age] => 20
)
这样我们就完成了数组的反串行化。

拓展知识—自定义对象的串行化和反串行化

对数组进行串行化是一个基础操作,然而在实际的程序设计中,我们可能经常对其他类型的变量进行串行化,例如对某个自定义对象进行串行化,这里有一个我们自己编写的类A(保存在classa.inc中):
复制内容到剪贴板
代码:
<?php
class A {
    var $one = 1;
    function show_one() {
      echo $this->one;
    }
}
?>
我们在如下代码中创建类的实例并对该实例进行串行化:
复制内容到剪贴板
代码:
<?php
include("classa.inc");
$a=new A;
echo(serialize($a));
?>
此时输出的内容为:
复制内容到剪贴板
代码:
O:1:"A":1:{s:3:"one";i:1;}
总体来看,这个串行化字符串输出了改对象当前的状态,即i的值为1。下面我们来逐个分析其中的细节。
O:1:由于当前的变量是一个自定义对象,因此该表征字符为“O”,表示Object。
后面的"A"标识了该变量是哪个类的实例,这里即A类。
大括号内即该实例的各个属性的名称和值。
而后我们将其进行反串行化:
复制内容到剪贴板
代码:
<?php
include("classa.inc");
$s = 'O:1:"A":1:{s:3:"one";i:1;}';
$a = unserialize($s);
$a->show_one();
?>
此时输出“1”,即调用了A类的show_one()方法。
你可以注意到虽然在实例的串行化字符串中并没有包含类的方法,但是我们将其反串行化后,仍然可以调用类的方法,这个特性在PHP4及以上版本中被支持(当然,你需要包含类的定义文件classa.inc)。
注:你可以参考PHP手册中Language Reference->Classes and Objects->Serializing objects - objects in sessions一节的内容。

在JavaScript中串行化为JSON—使用json2.js

JavaScript中没有直接串行化对象的内置方法,当然你可以自己写一个,不过我还是强烈推荐你在这里偷个小懒,使用现成的组件,JSON的官方网站www.json.org提供了对JavaScript对象实现JSON串行化的代码库—json2.js,你可以从这里获得它。
获得完毕json2.js文件后,你可以打开这个文件,在文件的前部分包含了相当大量的注释信息,如果你的英文足够好,那么你可以省略我这一节,参考该文件的注释就可以了,如果作为程序员,你已经看够了大片的字母,想看看我的汉字+字母,那你可以向下继续了。
简单的翻译下这个注释:
可参考http://www.JSON.org/js.html
该文件创建了一个包含两个方法的全局对象JSON,它的方法分别是:
复制内容到剪贴板
代码:
JSON.stringify(value, whitelist)
value       任意的JavaScript值,一般是一个对象或者数组
whitelist       一个可选的数组参数,用于判定对象值如何被串行化
这个方法通过一个JavaScript值来生成JSON文本。在进行串行化时,根据可选的参数whitelist,有三种可能:
如果某个对象有toJSON方法,那么则调用该方法,toJSON方法的返回值将被串行化。
否则,如果可选参数whitelist是一个数组,那么数组中的元素将被用来选择对象进行串行化时的的成员。
否则,如果没有使用whitelist参数,则对象的所有成员将被串行化。
如果值没有JSON的表现形式,例如undefined或者函数,则其不会被串行化。在对象中,这样的值会被忽略,而在数组中将会被null替换。
JSON.stringify(undefined)会返回undefined。日期将会被串行化为被引用的ISO日期。
例:
复制内容到剪贴板
代码:
var text = JSON.stringify(['e', {pluribus: 'unum'}]);
//text is '["e",{"pluribus":"unum"}]'
JSON.parse(text, filter)
该方法解析一个JSON文本,并生成一个组件或者数组,其可能抛出一个SyntaxError异常。
可选的filter参数是一个可过滤和转换结果的函数、它接受每个键和值,它的返回值用来替换源值。如果它返回所接收的值,那么结果不会被改变。如果他返回undefined,则该成员会被删除。
例:
复制内容到剪贴板
代码:
//解析文本,如果某个键包含字符串“date”,则将其值转换为日期
myData = JSON.parse(text, function (key, value) {
return key.indexOf('date') >= 0 ? new Date(value) : value;
});
上面的入门教程已经使你基本了解了json2.js的使用方法,这里关于该文件我就不再赘述了,只是有一个小提示,如果你想简单的解析一个JSON文本,那么可以使用eval()函数,改函数是JavaScript的内置函数,例如解析在JSON.stringify的案例中生成的JSON文本,可以使用:
复制内容到剪贴板
代码:
var myE = eval('["e",{"pluribus":"unum"}]');
来获得对象myE。

在JavaScript中串行化为JSON—使用prototype.js

如果你和我一样,喜欢在自己的项目中使用开源的JavaScript框架,那么你可能可以省去使用json2.js文件了,这里以protype.js为例,该文件可以在http://www.prototypejs.org下载,由于本文不是在讲JavaScript框架,这里我假设你对prototype.js的使用已经有所了解了。
prototype.js中提供了对Object对象的toJSON方法,你可以使用Object.toJSON()方法来实现对对象的串行化,例如:
复制内容到剪贴板
代码:
var cat=
{
name:"hellokitty",
height:"6 apples"
}
alert(Object.toJSON(cat));    
//将弹出对话框,内容为 {"name": "hellokitty", "height": "6 apples"}
另外,在prototype.js中还有另外的JSON支持,主要是在Ajax对象中对Ajax返回请求中JSON内容的解析。这里暂时与我们的内容无关,也不再介绍了。

[ 本帖最后由 hanguofeng 于 2008-3-19 16:03 编辑 ]
本帖最近评分记录
  • 5do8 威望 +3 谢谢分享 2008-4-8 16:27
PHP与JSON

在上面我们一起了解了PHP进行对象串行化的方法以及在JavaScript中进行将对象串行化为JSON的方法,你大致会质疑我为什么将二者放在一起,因为他们的语法实际是不完全一样的,然而,在PHP中,可以对JSON文本进行反串行化,也可以将PHP的对象串行化为JSON而非PHP风格的文本。这主要是靠json_decode和json_encode两个函数来完成的,需要特别说明的是,这两个函数在PHP 5 >= 5.2.0中才被支持,如果你要编写运行在PHP4环境下的程序,那么这两个函数是不可以使用的。

json_decode函数

语法
mixed json_decode ( string $json [, bool $assoc] )
获取一个JSON编码文本,并且将其转换为PHP变量
参数
json
被JSON编码的文本
assoc
当为TRUE时,返回的值为联合数组
返回值
返回一个对象,或者如果可选的assoc参数为TRUE,则一个联合数组将会被返回

json_encode函数

语法
string json_encode ( mixed $value )
该函数返回一个值的JSON表达式
参数
value
要被编码的值,可以为除resource外的任何类型参数
这个函数仅在UTF-8编码格式时起作用
返回值
当成功时返回编码后的JSON文本

json_decode函数实例

下面两个例子都基于我们的一个情景假设,即,我们有一个用户注册的模块,这个模块以“面向对象”的方式工作,在json_decode函数实例中,我们在前台将用户的注册信息变为一个类的属性,而后传递到后台的php文件(这里为了简便,就不用Ajax了)。在json_encode实例中,我们在html文件中引用一个js文件,地址指向php文件,在php文件中输出json编码后的用户对象(同样为了简便,我们直接生成一个对象而不从数据库中取信息),并在html中输出。
好了,先来看前台的页面json_encode.htm,这个页面模仿了通常的注册页面,在其上面有一个表单,当提交时,触发JavaScript函数,生成一个用户对象user,将表单内容设为用户对象的属性,生成JSON文本,以POST方式传递到后台的json_encode.php文件。在js_encode.php文件中,将JSON文本用json_decode函数解析为PHP对象,并输出。
好了,先来看json_encode.html文件,文件代码如下:
复制内容到剪贴板
代码:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>json_decode</title>
<script src="json2.js" type="text/javascript"></script>
<script type="text/javascript">
function JSON_test(o)
{
    var user = {
        name:document.getElementById('txt_name').value,
        email:document.getElementById('txt_email').value,
        password:document.getElementById('txt_name').value
    }
    var json_string = JSON.stringify(user);
    
    document.getElementById('txt_json').value=json_string;
    alert("点击确定后将提交表单");
    o.submit();
}
</script>
</head>
<body>
<form id="form1" name="form1" method="post" action="json_encode.php" onsubmit="JSON_test(this)">
  <label for="txt_name">姓名</label>
  <p>
    <input type="text" name="txt_name" id="txt_name" />
  </p>
  <label for="txt_email">邮箱</label>
  <p>
    <input type="text" name="txt_email" id="txt_email" />
  </p>
  <p>
    <label for="txt_password">密码</label>
  </p>
  <p>
    <input type="text" name="txt_password" id="txt_password" />
  </p>
  <p>
  <input type="text" name="txt_json" id="txt_json" />
    <label for="button"></label>
    <input type="submit" name="button" id="button" value="JSON" />
  </p>
</form>
</body>
</html>
当提交表单时,将触发JavaScript函数JSON_text(),该函数首先建立一个JavaScript对象user,将其name、email和password属性分别设为对应表单的值,而后使用json2.js文件的JSON.stringify方法将其转换为JSON文本json_string,最后设定隐藏域(这里为了使你看的清楚,我把这个隐藏域以文本框形式显示了)txt_json的值为json_string,并提交表单。
下面到json_encode.php文件,如下:
复制内容到剪贴板
代码:
<?php
$json_string = $_POST["txt_json"];
if(ini_get("magic_quotes_gpc")=="1")
{
    $json_string=stripslashes($json_string);
}
$user = json_decode($json_string);
echo var_dump($user);
?>
在这个文件中,首先得到json_encode.html文件中POST表单域txt_json的值,放入变量$json_string中,而后判断,如果当前PHP的设定为magic_quotes_gpc=On,即传入的双引号等会被转义,这样json_decode函数无法解析,因此我们要将其反转义化。而后,使用json_decode函数将JSON文本转换为对象,保存在$user变量中,最终用echo var_dump($user);,将该对象dump输出出来,最终结果是:
复制内容到剪贴板
代码:
object(stdClass)#1 (3) {
  ["name"]=>
  string(10) "hanguofeng"
  ["email"]=>
  string(18) "example@domain.com"
  ["password"]=>
  string(10) "hanguofeng"
}
json_encode函数实例

在这个例子中,仍然是由两部分构成的,即json_enode.html和json_encode.php。在json_decode.html文件中,基本与json_decode.html文件的表单类似,但是不同的是,这次我们要从json_encode.php文件中获得相应用户的JSON文本,先来看这个PHP文件吧:
复制内容到剪贴板
代码:
<?php
Class user
{
    public $name="";
    public $email="";
    public $password="";
};
$myUser = new user;
$myUser->name="hanguofeng";
$myUser->email="example@domain.com";
$myUser->password="hanguofeng";
$json_string = json_encode($myUser);
?>
var user = <?php echo($json_string)?>;
这个文件首先建立类user,而后获得一个user类的实例myUser,并设定其用户名、邮箱和密码,接下来使用json_encode函数将其转换为JSON文本,保存在变量$json_string中,最后输出一段JavaScript代码,以在JavaScript中建立全局变量user。
接下,我们需要在json_encode.html文件中引入json_encode.php文件,并得到user对象的各个属性,如下:
复制内容到剪贴板
代码:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>json_encode</title>
<script src="json_encode.php" type="text/javascript"></script>
</head>
<body>
<form id="form1" name="form1" method="post">
  <label for="txt_name">姓名</label>
  <p>
    <input type="text" name="txt_name" id="txt_name" />
  </p>
  <label for="txt_email">邮箱</label>
  <p>
    <input type="text" name="txt_email" id="txt_email" />
  </p>
  <p>
    <label for="txt_password">密码</label>
  </p>
  <p>
    <input type="text" name="txt_password" id="txt_password" />
  </p>
</form>
<script type="text/javascript" >
    document.getElementById('txt_name').value=user.name;
    document.getElementById('txt_email').value=user.email;
    document.getElementById('txt_password').value=user.password;
</script>
</body>
</html>
在这个文件中,你需要注意两点,第一是,我们以这样的代码引入json_encode.php文件为JavaScript文件:
复制内容到剪贴板
代码:
<script src="json_encode.php" type="text/javascript"></script>
第二点则是:
我们在文本框代码后面加入JavaScript的代码,对文本框的value属性进行操作,分别设定其值为user对象的相应值。
实践出真知

背景说明

OK,各位亲爱的朋友,在经过上面这么多这么多的零散的关于PHP的串行化和JavaScript的串行化—JSON的说明后,我们来做一个完整的东西,在这里面,我们涉及了JavaScript中的对象操作、对象串行化,还涉及了当串行化的JSON文本传输到后台的PHP时,PHP进行的相应处理。
这里需要说明的是,为了将内容聚焦于本文所阐述的领域,我们将这个项目精简了很多,在这里讲的并不完全是实际生产环境下的做法,而是为了突出串行化的应用,在具体的地方我会详细说明,希望不影响你对整体的理解。
我们要完成的小案例是一个在线记事本的程序,用户可以在前台添加若干个Tab(即通常所说的选项卡),每个Tab保存一定的文本内容,你也可以将它当作一个动态的选项卡生成和管理的程序。
程序的运行界面如下图:



在这里,你可以看到有若干个Tab,当点击这些Tab时,下面将显示Tab的内容,同时你可以删除Tab和新增Tab,在完成对Tab的编辑后,可以点击“保存”按钮,将改动传输到后台的PHP进行处理,并保存在服务器上。
前台JavaScript部分
在前台的notepat.html文件中,我们要使用JavaScript完成大多数对Tab进行管理的任务,因此我构建了一个Tab管理的类,用来对其进行添加、删除等操作,这个类如下所示:



tabManager类的各个属性、方法含义如下:
_tabs:“私有属性”(加引号的原因是JavaScript中并没有私有公有的概念,这里只是从设计上来讲),该属性中存储了当前的tab数组,任何对Tab的操作将最终存储在这里。
_lastIndex:“私有属性”,表明最后添加的索引,用于对各个Tab进行唯一标识。

getTabs():返回当前的tab数组。
setTabs(tabs):设定当前的tab数组。
add(ptitle,pcontent):新增一个标题为ptitle,内容为pcontent的tab。
del(pid):删除id为pid的tab。
clean():“私有方法”,用于删除某个tab后,对tab数组进行精简压缩。
getTab(pid):用于获得指定的单个tab,参数pid为要获得的tab的id。
debug():预留的debug方法。

同时注意我们的tab对象有三个属性,分别为id、name和content。
这样,基础类的架构我们就讲解完毕了,这里由于其详细代码与本文话题关联不大,就不再详细列出和讲解了,稍后可能会单独发表文章来说这里。
那么,我们还需要构建一些函数,作为控制器,来沟通页面上各个按钮的点击事件和之前建立的tabManager类,这些函数包括:
selTab(o):当点击页面某个Tab时,切换内容区域以显示相应Tab的内容,传入参数为所点击的连接对象。
newTab():当点击“新建Tab”按钮时,负责询问用户新增Tab的信息,并调用tabManager.add()方法将用户输入的Tab信息建立一个新的Tab对象。
delTab():删除当前激活的Tab。
saveTab():将对Tab的所有更改提交到PHP中。
loadTab():加载Tab。
showTabContent(id):被selTab()函数调用以显示指定id的Tab的内容到内容区域。
draw(tabs):根据传入的tabs数组重绘Tab导航区域。

那么,这里我要重点强调的函数就有两个,分别是saveTab()和loadTab()。
先来看saveTab()函数:此函数源代码如下:
复制内容到剪贴板
代码:
function saveTab()
{
    document.getElementById("json_string").value = JSON.stringify(tabManager.getTabs());
    document.getElementById("frmMain").submit();
}
呵呵,好像比较简单啊,这个函数首先通过调用tabManager类的getTabs()方法,获得我们所操作的Tabs数组,而后调用json2.js文件中的JSON.stringfy()方法将其串行化,得到串行化的JSON文本后,将其赋给隐藏域json_string,并提交表单,这里我采取了简单的方法,其实你在这里也可以采用Ajax的方式,将JSON文本传递到PHP中。
另外则是函数loadTab(),其代码如下:
复制内容到剪贴板
代码:
function loadTab()
{
    tabManager.setTabs(notes);
    draw(tabManager.getTabs());
}
这里需要说明的是,我们在本文件的开头,通过如下代码:
复制内容到剪贴板
代码:
<script type="text/javascript" src="load.php"></script>
引入了一个经过后台处理的(你可以看到,扩展名为PHP)JavaScript文件load.php,。在这个文件中,建立了一个tab对象的数组notes。因此,在loadTab函数中,我们调用了tabManager类的setTabs方法,设定tabManager类的“私有属性”_tabs的值为notes数组,此时就完成了对Tab的加载。

后台PHP部分

当用户在网页上点击“保存”按钮后,会触发前面所讲解的saveTab()函数,最终提交表单到save.php页面,该页面读取用户提交的JSON文本,并将其转换为PHP对象,进行后续处理,其代码如下:
复制内容到剪贴板
代码:
<?php
$json_string = $_POST["json_string"];
if(ini_get("magic_quotes_gpc")=="1")
{
    $json_string=stripslashes($json_string);
}
$notes = json_decode($json_string);
foreach ($notes as $note)
{
    echo $note->title."<br>".$note->content."<br>-------------------------<br>";
}
$p = fopen("load.php","w+");
fwrite($p,"var notes=".json_encode($notes).";");
fclose($p);
?>
首先通过访问全局集合$_POST来获得提交的json_string隐藏域的值,而后进行处理,如果PHP的配置magic_quotes_gpc为On,则此时提交的文本中,引号会被转义,如果不进行处理,那么后面的json解码操作会失败,因此我们调用函数stripslashes()将其反转义。
接下来我们使用json_decode()函数对提交的JSON文本进行解码,返回的对象保存在$notes变量中,此时$notes变量为一个数组,数组中每一个元素即一个Tab对象,为了清楚的看到这一点,我们对$notes数组进行迭代,依次打印出数组中每一个Tab对象的标题和内容,最后,我们打开文件load.php,将使用json_encode进行JSON编码后的$notes对象写入此文件,以待notepad.html文件调用,这样就完成了对对象的持久化存储工作。
这里仍然需要说明的是我们精简的部分:在实际的生产环境中,你很可能需要在迭代$notes数组时将每一个Tab对象的信息写入数据库中,以方便其他的部分调用,而在load.php文件中,你可能并不是直接将JSON文本写入此文件,而是从数据库中读取一个结果集,而后迭代结果集,来生成一个PHP的数组,并将PHP数组进行JSON编码后,输出。
好了,絮絮叨叨一大堆,简单点用个图来表示吧:



TOP

我还有话要说
各位亲爱的~读者朋友,我们这篇“长”达一万五千字的连载完成了,在本文中,我想你了解了关于对象串行化的一些基本概念以及串行化在PHP和JavaScript中的使用方法。
串行化只是一种思路,他的妙用在于你熟悉了在各类语言中对对象的操作之后,JSON和XML各有特点,根据自己的情况进行优选才是王道。
欢迎大家在论坛或者博客中与我交流。


--------------------------------------------------------这是一条分割线--------------------------------------------------
本文资源:

Word版原文打包
PHP串行化与JSON.rar (63.86 KB)

实例部分源代码
sample.rar (5.89 KB)

图1:http://i.namipan.com/files/38220519b5b390b0467dd40e10792f55f3c9979f662100008b3a/0/PIC01.gif
图2:http://i.namipan.com/files/c133ba96caeb42302294e67e18c08118707b0dc35e180000dcad/0/PIC02.gif
图3:http://i.namipan.com/files/84e97995562c3988d17d434980def68a9fecf13788100000a104/0/PIC03.gif
图4:http://i.namipan.com/files/f7030628503797b9fd1d40f72d33b0536def4026bb120000edb9/0/PIC04.gif

[ 本帖最后由 hanguofeng 于 2008-4-1 18:35 编辑 ]

TOP

补充:关于“串行化”和“序列化”

拙文发表后有幸得到很多朋友的关注,斑竹5do8同学PM我,提出商榷的说法,即本文中的“串行化”,叫做“串行化”还是“序列化”比较合适。
我对“serialize”研究并不很深,Google了下,虽然网上很多地方都是二者同用,最后我同意序列化的说法更好,原因如下:
1。PHP官方的中文文档(http://www.php.net/manual/zh/function.serialize.php)翻译为序列化
2。http://blog.csdn.net/jungleford/archive/2005/03/20/324768.aspx一文提到的理由

特此说明,谢谢。

TOP

一般习惯上叫序列化,不过习惯就好
那个啥?

TOP

序列化是用serialize
串行化是用json
除非必须用到,要不然最好不用
速度很慢

TOP

讲的非常好 很透彻
感谢小韩
guees what

TOP

哈哈.嗯,很好,留个脚印先

TOP

此帖非常好.正好想看看这方面的内容..谢谢楼主..
<阿龍> donaldsu.cn

TOP

json2.js代码中没有!

TOP

讲的很透彻。
还加了过程图,很少见。
晚上一定仔细研究。

[ 本帖最后由 mqycn 于 2008-12-23 16:28 编辑 ]

TOP

引用:
原帖由 xudong1987 于 2008-12-22 17:17 发表
json2.js代码中没有!
JSON的官方网站www.json.org提供了对JavaScript对象实现JSON串行化的代码库—json2.js

TOP

想了解一下:JSON和serialize相对哪个效率高一些呢?

TOP

引用:
原帖由 KentaTse 于 2009-7-8 23:53 发表
想了解一下:JSON和serialize相对哪个效率高一些呢?
我想是serialize,但是没有经过测试,因为那是PHP原生的序列化方法

TOP

如果要保存到数据库里面,有中文的话只能使用serialize()。json_encode()会出错,json_encode只有输出到浏览器的时候才不会有太大的问题。
找靠谱的人才?快来蓝色理想招聘

TOP

引用:
原帖由 Missx 于 2009-7-10 10:44 发表
如果要保存到数据库里面,有中文的话只能使用serialize()。json_encode()会出错,json_encode只有输出到浏览器的时候才不会有太大的问题。
应该不会吧,我保存一个文本到数据库,出来的如果是那个文本的话,json_decode不会解析不出来才是

TOP

<?php
$text = '我是笨蛋';
$arr = array('id'=>1,'name'=>'愚者');
$json_encode_text = json_encode($text);
$json_decode_text = json_decode($json_encode_text);
$json_encode_arr = json_encode($arr);
$json_decode_arr = json_decode($json_encode_arr);
echo '$json_encode_text  : '.$json_encode_text .'<br />';
echo '$json_decode_text : '.$json_decode_text . '<br />';
echo '$json_encode_arr  : '.$json_encode_arr .'<br />';
echo '$json_decode_arr : <pre>';
print_r($json_decode_arr);
echo '</pre>';
?>
尝试下这个代码
找靠谱的人才?快来蓝色理想招聘

TOP

引用:
原帖由 Missx 于 2009-7-10 11:26 发表

尝试下这个代码
要另存为UTF-8格式才行的.
json_encode只支持UTF-8的中文.

[ 本帖最后由 feng4ever 于 2009-10-16 02:32 编辑 ]

TOP

引用:
原帖由 hanguofeng 于 2009-7-9 10:19 发表

我想是serialize,但是没有经过测试,因为那是PHP原生的序列化方法
json压缩率高.

TOP

其实序列化也不错.
www.oname.cn
--欢迎访问-我们的领地-最新版块-发泄地带-发泄我的不爽!--www.oname.cn

TOP

序列化还是有点作用的.特别是对数组变量存取数据库. 例如多选的问卷,可以把多选值当一个字段存入库,取出时反序列又是一数组. 简单方便
哈哈.
最近比较背!

TOP