7个不稳定版本 (3个重大更改)
0.5.0 | 2020年10月7日 |
---|---|
0.4.1 | 2020年2月17日 |
0.3.0 | 2019年11月4日 |
0.2.2 | 2019年10月29日 |
#1728 in 编码
每月115次下载
56KB
1.5K SLoC
PHP序列化对serde的支持
允许将数据序列化和反序列化到PHP的 serialize()
/unserialize()
格式。请参阅文档以获取详细信息: docs.rs/serde_php.
lib.rs
:
PHP序列化格式对serde的支持
PHP通过其 serialize()
和 unserialize()
方法使用自定义序列化格式。此crate通过使用 serde
添加了对该格式的部分支持。
可以在 https://stackoverflow.com/questions/14297926/structure-of-a-serialized-php-string 中查看格式的概述,详细信息可在 http://www.phpinternalsbook.com/php5/classes_objects/serialization.html 中找到。
支持哪些内容?
-
基本和复合类型
PHP类型 Rust类型 布尔值 bool
整数 i64
(自动转换为其他类型支持)浮点数 f64
(自动转换为f32
支持)字符串 Vec<u8>
(PHP字符串不是UTF8)null 解码为 None
数组(非关联数组) 元组 结构体
或Vec<_>
数组(关联数组) 常规 结构体
或HashMap<_, _>
-
Rust
String
可以透明地转换为 PHP 字节字符串。
无序数组
PHP 数组可以“无序”创建,因为它们将每个数组索引作为显式整数存储在数组中。因此,以下代码
$arr = array();
$arr[0] = "zero";
$arr[3] = "three";
$arr[2] = "two";
$arr[1] = "one";
会得到一个相当于 ["zero", "one", "two", "three"] 的数组,至少在迭代时是这样。
因为反序列化不会缓冲值,所以这些数组不能直接序列化为 Vec
。相反,它们应该被反序列化为一个映射,然后再根据需要将其转换为 Vec
。
第二个问题是数组中的“空洞”,例如,如果缺少键为 1
的条目。如何填充这些通常取决于用户。
可以使用辅助函数 deserialize_unordered_array
与 serde 的 deserialize_with
装饰器一起使用,以自动缓冲和排序内容,以及通过关闭任何间隙来填充空洞。
缺少什么?
- PHP 对象
- 非字符串/数字数组键,除非在反序列化为
HashMap
时 - 混合数组。假设数组键始终具有相同的键类型(注意:如果需要,考虑扩展此库以使用变体类型)。
示例用法
给定一个示例数据结构,使用以下 PHP 代码存储会话令牌
<?php
$serialized = serialize(array("user", "", array()));
echo($serialized);
因此以下输出
a:3:{i:0;s:4:"user";i:1;s:0:"";i:2;a:0:{}}
,可以使用以下 rust 代码重构数据
use serde::Deserialize;
use serde_php::from_bytes;
#[derive(Debug, Deserialize, Eq, PartialEq)]
struct Data(Vec<u8>, Vec<u8>, SubData);
#[derive(Debug, Deserialize, Eq, PartialEq)]
struct SubData();
let input = br#"a:3:{i:0;s:4:"user";i:1;s:0:"";i:2;a:0:{}}"#;
assert_eq!(
from_bytes::<Data>(input).unwrap(),
Data(b"user".to_vec(), b"".to_vec(), SubData())
);
同样,如果 PHP 数组使用键
<?php
$serialized = serialize(
array("foo" => true,
"bar" => "xyz",
"sub" => array("x" => 42))
);
echo($serialized);
在 Rust 中
#[derive(Debug, Deserialize, Eq, PartialEq)]
struct Outer {
foo: bool,
bar: String,
sub: Inner,
}
#[derive(Debug, Deserialize, Eq, PartialEq)]
struct Inner {
x: i64,
}
let input = br#"a:3:{s:3:"foo";b:1;s:3:"bar";s:3:"xyz";s:3:"sub";a:1:{s:1:"x";i:42;}}"#;
let expected = Outer {
foo: true,
bar: "xyz".to_owned(),
sub: Inner { x: 42 },
};
let deserialized: Outer = from_bytes(input).expect("deserialization failed");
assert_eq!(deserialized, expected);
可选值
缺失的值可以留作可选,如下例所示
<?php
$location_a = array();
$location_b = array("province" => "Newfoundland and Labrador, CA");
$location_c = array("postalcode" => "90002",
"country" => "United States of America");
echo(serialize($location_a) . "\n");
echo(serialize($location_b) . "\n");
# -> a:1:{s:8:"province";s:29:"Newfoundland and Labrador, CA";}
echo(serialize($location_c) . "\n");
# -> a:2:{s:10:"postalcode";s:5:"90002";s:7:"country";
# s:24:"United States of America";}
以下对 Location
的声明将能够解析所有三个示例输入。
#[derive(Debug, Deserialize, Eq, PartialEq)]
struct Location {
province: Option<String>,
postalcode: Option<String>,
country: Option<String>,
}
完整往返示例
use serde::{Deserialize, Serialize};
use serde_php::{to_vec, from_bytes};
#[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
struct UserProfile {
id: u32,
name: String,
tags: Vec<String>,
}
let orig = UserProfile {
id: 42,
name: "Bob".to_owned(),
tags: vec!["foo".to_owned(), "bar".to_owned()],
};
let serialized = to_vec(&orig).expect("serialization failed");
let expected = br#"a:3:{s:2:"id";i:42;s:4:"name";s:3:"Bob";s:4:"tags";a:2:{i:0;s:3:"foo";i:1;s:3:"bar";}}"#;
assert_eq!(serialized, &expected[..]);
let profile: UserProfile = from_bytes(&serialized).expect("deserialization failed");
assert_eq!(profile, orig);
依赖项
~2MB
~42K SLoC