我将告诉您一些关于PHP中序列化和反序列化的深入理解。相信朋友们也应该很关心这个话题。现在,让我们为我的朋友们谈谈对PHP中序列化和反序列化的深入理解。边肖还收集了关于深入理解PHP中序列化和反序列化的相关信息。我希望你看到后会喜欢。
本文将带您深入分析PHP中的序列化和反序列化。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。
[推荐研究:《PHP视频教程》]
序列化格式将PHP中用于存储或传输PHP的值序列化,而不丢失其类型和结构。
序列化函数原型如下:
序列化(混合$值)让我们先看下面的例子:
CC类{
公共$数据;
私人$通行证;
公共函数__construct($data,$pass)
{
$ this-data=$ data;
$ this-pass=$ pass;
}
}
$ number=34
$ str=' uusama
$ bool=true
$ null=NULL
$arr=array('a'=1,' b '=2);
$cc=新CC('uu ',true);
var _ dump(serialize($ number));
var _ dump(serialize($ str));
var _ dump(serialize($ bool));
var _ dump(serialize($ null));
var _ dump(serialize($ arr));
var _ dump(serialize($ cc));输出结果是:
字符串(5)“I :34;”
字符串(13)' s 33606: ' uu sama ';'
字符串(4)“b :1;”
字符串(2)“N;”
字符串(30)' a :2: { s 33601: ' a ';i:1s 33601:“b”;i:2}'
字符串(52)' o :2: ' CC ' :2: { s :4: ' data ';s 33602:“uu”;s 33608:‘CC通行证’;b:1“}”所以不同类型序列化得到的字符串格式是:
字符串: s:size:value整数: i:value布尔值: b:value(保存1或0)空:N;数组: a:size: {键定义;价值定义;(每个元素重复)}对象: O:strlen(对象名):对象名:对象大小: O:strlen(属性名):属性名:属性定义;(每个属性可重复)}序列化对象从上面的示例中,我们可以看到序列化对象时只保存属性值。
那么对象中的常量会被保存吗?从父类继承的变量是否会被保存?CB类{
public $ CB _ data=' cb
}
CC类扩展了CB{
const SECOND=60
公共$数据;
私人$通行证;
公共函数__construct($data,$pass)
{
$ this-data=$ data;
$ this-pass=$ pass;
}
公共函数setPass($pass)
{
$ this-pass=$ pass;
}
}
$cc=新CC('uu ',true);
var _ dump(serialize($ cc));输出结果是:
字符串(75)' o :2: ' CC ' :3: { s :4: ' data ';s 33602:“uu”;s 33608:‘CC通行证’;b:1s 33607:‘CB _ data’;s 33602:“CB”;“}”显然,序列化对象时不会保存常量的值。父类中的变量被保留。
对象序列化定制序列化对象时,我们不需要在对象中保存一些敏感属性。我们做什么呢
当调用serialize函数来序列化对象时,它会检查类中是否有magic method __sleep。如果存在,将先调用方法,然后调用
执行序列化操作。可以通过重载这个方法从而自定义序列化行为。该方法原型如下:public array __sleep ( void )该方法返回一个包含对象中所有应被序列化的变量名称的数组该方法未返回任何内容则 NULL 被序列化并产生一个E_NOTICE级别的错误__sleep不能返回父类的私有成员的名字。这样做会产生一个E_NOTICE级别的错误。这时只能用Serializable接口来替代。常用于保存那些大对象时的清理工作避免保存过多冗余数据看下面的例子:
class User{ const SITE = 'uusama'; public $username; public $nickname; private $password; public function __construct($username, $nickname, $password) { $this->username = $username; $this->nickname = $nickname; $this->password = $password; } // 重载序列化调用的方法 public function __sleep { // 返回需要序列化的变量名过滤掉password变量 return array('username', 'nickname'); } } $user = new User('uusama', 'uu', '123456'); var_dump(serialize($user));返回结果如下显然序列化的时候忽略了 password 字段的值。
string(67) "O:4:"User":2:{s:8:"username";s:6:"uusama";s:8:"nickname";s:2:"uu";}"序列化对象存储通过上面的介绍我们可以把一个复制的对象或者数据序列化成一个序列字符串保存值的同事还保存了他们的结构。
我们可以把序列化之后的值保存起来存在文件或者缓存里面。不推荐存在数据库里面可读性查而且不便于迁移维护不便于查询。
$user = new User('uusama', 'uu', '123456'); $ser = serialize($user); // 保存在本地 file_put_contents('user.ser', $ser);反序列化使用方法通过上面的讲解我们可以将对象序列化为字符串并保存起来那么如何把这些序列化后的字符串恢复成原样呢PHP提供了反序列函数:
mixed unserialize ( string $str )unserialize反序列化函数用于将单一的已序列化的变量转换回 PHP 的值。
如果传递的字符串不可解序列化则返回 FALSE并产生一个E_NOTICE返回的是转换之后的值可为integer``float、string、array或object若被反序列化的变量是一个对象在成功重新构造对象之后PHP会自动地试图去调用__wakeup成员函数(如果存在的话)看下面的例子:
class User{ const SITE = 'uusama'; public $username; public $nickname; private $password; private $order; public function __construct($username, $nickname, $password) { $this->username = $username; $this->nickname = $nickname; $this->password = $password; } // 定义反序列化后调用的方法 public function __wakeup { $this->password = $this->username; } } $user_ser = 'O:4:"User":2:{s:8:"username";s:6:"uusama";s:8:"nickname";s:2:"uu";}'; var_dump(unserialize($user_ser));输出结果为:
object(User)#1 (4) { ["username"]=> string(6) "uusama" ["nickname"]=> string(2) "uu" ["password":"User":private]=> string(6) "uusama" ["order":"User":private]=> NULL }可以得出以下结论:
__wakeup函数在对象被构建以后执行所以$this->username的值不为空反序列化时会尽量将变量值进行匹配并复制给序列化后的对象未定义类的处理在上面的例子中我们在调用反序列化函数unserialize之前提前定义了User类如果我们没有定义会怎么样呢
$user_ser = 'O:4:"User":2:{s:8:"username";s:6:"uusama";s:8:"nickname";s:2:"uu";}'; var_dump(unserialize($user_ser));这个例子中我们没有定义任何的User类反序列化正常执行并没有报错得到的结果如下:
object(__PHP_Incomplete_Class)#1 (3) { ["__PHP_Incomplete_Class_Name"]=> string(4) "User" ["username"]=> string(6) "uusama" ["nickname"]=> string(2) "uu" }注意对比之前定义了User类的结果这儿反序列化得到的对象是__PHP_Incomplete_Class并指定了未定义类的类名。
如果这个时候我们去使用这个反序列化后的不明对象则会抛出E_NOTICE。这么看着不能用也不是办法那么如何处理呢有两种方案。
定义__autoload等函数指定发现未定义类时加载类的定义文件可通过 php.ini、ini_set 或 .htaccess 定义unserialize_callback_func。每次实例化一个未定义类时它都会被调用以上两种方案的实现如下:
// unserialize_callback_func 从 PHP 4.2.0 起可用 ini_set('unserialize_callback_func', 'mycallback'); // 设置您的回调函数 function mycallback($classname) { // 只需包含含有类定义的文件 // $classname 指出需要的是哪一个类 } // 建议使用下面的函数代替__autoload spl_autoload_register(function ($class_name) { // 动态加载未定义类的定义文件 require_once $class_name . '.php'; });PHP预定义序列化接口Serializable还记得上面在将序列化过程中遇到的:无法在__sleep方法中返回父类对象的问题吗方法就是实现序列化接口Serializable。
该接口的原型如下:
Serializable { abstract public string serialize ( void ) abstract public mixed unserialize ( string $serialized ) }需要注意的是如果定义的类实现了Serializable接口那么序列化和反序列化的时候PHP就不会再去调用__sleep方法和__wakeup方法。
class CB implements Serializable{ public $CB_data = ''; private $CB_password = 'ttt'; public function setCBPassword($password) { $this->CB_password = $password; } public function serialize { echo __METHOD__ . "\n"; return serialize($this->CB_password); } public function unserialize($serialized) { echo __METHOD__ . "\n"; } } class CC extends CB { const SECOND = 60; public $data; private $pass; public function __construct($data, $pass) { $this->data = $data; $this->pass = $pass; } public function __sleep { // 输出调用了该方法名 echo __METHOD__ . "\n"; } public function __wakeup { // 输出调用了该方法名 echo __METHOD__ . "\n"; } } $cc = new CC('uu', true); $ser = serialize($cc); var_dump($ser); $un_cc = unserialize($ser); var_dump($un_cc);运行结果为:
CB::serialize string(24) "C:2:"CC":10:{s:3:"ttt";}" CB::unserialize object(CC)#2 (4) { ["data"]=> NULL ["pass":"CC":private]=> NULL ["CB_data"]=> string(0) "" ["CB_password":"CB":private]=> string(3) "ttt" }可以完全定义serialize方法该方法返回的值就是序列化后大括号内的值只要保证自定义序列化和反序列化的规则一致即可。
题外话在PHP应用中序列化和反序列化一般用做缓存比如session缓存cookie等。
序列化和反序列化在PHP中用得不算多在Java语言中用得比较多。其实你有没有发现这种把一个对象或者数组的变量转化成字符串的方式json也可以做到。
使用json来实现对象和字符串之间的转换在PHP中显得更加直观和轻便。而且经过测试使用json_encode比serialize方法更加快速大概快2~3倍。
在我看来序列化和反序列化是一种传输抽象数据的思想。通过定义序列化和反序列化的规则我们可以实现将PHP中的对象序列化成字节流然后传输给别的语言或者系统使用这在远程调用里面非常的方便。
更多编程相关知识请访问:编程视频!!
以上就是深入了解PHP中的序列化和反序列化的详细内容!
来源:php中文网
标签:
免责声明:本文由用户上传,与本网站立场无关。财经信息仅供读者参考,并不构成投资建议。投资者据此操作,风险自担。 如有侵权请联系删除!