>  기사  >  백엔드 개발  >  PHP 직렬화 및 역직렬화 원리 직접 살펴보기

PHP 직렬화 및 역직렬화 원리 직접 살펴보기

coldplay.xixi
coldplay.xixi앞으로
2020-07-20 17:23:002299검색

PHP 직렬화 및 역직렬화 원리 직접 살펴보기

0. 서문

PHP에서 직렬화의 결과는 json과 다소 유사한 PHP 사용자 정의 문자열 형식입니다.

us 직렬화 설계 어떤 언어로든 객체를 역직렬화하려면 여러 가지 문제를 해결해야 합니다. 객체를 직렬화한 후 직렬화 결과에는 자체 설명 기능이 있습니다(직렬화 결과에서 객체의 특정 세부 사항을 알 수 있음).


알고 있는 것만으로는 충분하지 않습니다. 물론 이 유형에 해당하는 특정 값도 알아야 합니다.)


직렬화 중 권한 제어, 직렬화 필드 등을 사용자 정의할 수 있습니다. 예를 들어 golang에서 수행하는 것이 매우 편리합니다.


시간 성능 문제: 고성능 서비스(직렬화를 위해 protobuf를 자주 사용함)와 같이 성능에 민감한 일부 시나리오에서는 객체 직렬화를 억제할 수 없습니다.


공간 성능 문제: 직렬화 후 결과가 너무 좋을 수 없습니다. 예를 들어, int 객체가 메모리에 있고 직렬화 후 데이터 길이가 int 길이의 10배가 되면 직렬화 알고리즘에 문제가 있는 것입니다.


이 문서에서는 관점에서 PHP의 시퀀스만 설명합니다. 직렬화 및 역직렬화 과정은 객체 데이터에서만 작동한다는 점을 기억하세요. 객체 지향 개발 경험이 있는 사람이라면 누구나 쉽게 이해할 수 있습니다.

관련 학습 권장 사항:
PHP 프로그래밍 초보부터 마스터까지

1. 직렬화 및 역직렬화 메서드 unserialize


php는 C++와 달리 객체 직렬화 기능을 기본적으로 제공합니다...^_^ 인터페이스도 두 개뿐이어서 사용하기도 매우 간단합니다.

class fobnn
{
 public $hack_id;
 private $hack_name;
 public function __construct($name,$id)
 {
  $this->hack_name = $name;
  $this->hack_id = $id;
 }
 public function print()
 {
  echo $this->hack_name.PHP_EOL;
 }
}
$obj = new fobnn('fobnn',1);
$obj->print();
$serializedstr = serialize($obj); //通过serialize接口序列化
echo $serializedstr.PHP_EOL;;
$toobj = unserialize($serializedstr);//通过unserialize反序列化
$toobj->print();
fobnn
O:5:"fobnn":2:{s:7:"hack_id";i:1;s:16:"fobnnhack_name";s:5:"fobnn";}
fobnn

두 번째 줄을 참조하세요. 이 문자열은 실제로 읽기 쉽습니다. 물론 개체 유형 이후의 레이블 이름은 개체 이름/멤버 이름을 통해 매핑됩니다. 형식 이름은 fobnn입니다. 이 형식에서 다음 2는 멤버 개체가 두 개 있음을 나타냅니다.

멤버 개체에 대해서는 실제로 동일한 하위 설명 집합입니다.

자기- 함수 설명 주로 문자열을 통해 객체와 멤버의 이름을 기록하는 방식으로 구현됩니다.

2. 성능 문제

이 기사에서는 PHP 직렬화의 시간 성능을 분석하지 않지만 실제로 직렬화 결과는 다음과 같습니다. json/bson에서 정의한 프로토콜과 유사하게 프로토콜 헤더가 있고, 프로토콜 헤더는 유형을 설명하고, 프로토콜 본문은 유형에 해당하는 값을 설명하며, 직렬화 결과는 압축되지 않습니다. deserialization의 매직 메소드

에 해당합니다. 두 번째 문제는 실제로 PHP에 해결책이 있습니다. 하나는 매직 메소드를 통한 것이고, 두 번째는 사용자 정의 직렬화 함수를 통한 것입니다. 먼저 매직 메소드인 __sleep 및 __wakeup

을 소개하겠습니다.
class fobnn
{
 public $hack_id;
 private $hack_name;
 public function __construct($name,$id)
 {
  $this->hack_name = $name;
  $this->hack_id = $id;
 }
 public function print()
 {
  echo $this->hack_name.PHP_EOL;
 }
 public function __sleep()
 {
  return array("hack_name");
 }
 public function __wakeup()
 {
  $this->hack_name = 'haha';
 }
}
$obj = new fobnn('fobnn',1);
$obj->print();
$serializedstr = serialize($obj);
echo $serializedstr.PHP_EOL;;
$toobj = unserialize($serializedstr);
$toobj->print();
fobnn
O:5:"fobnn":1:{s:16:"fobnnhack_name";s:5:"fobnn";}
haha

직렬화 전 __sleep이 먼저 호출되어 직렬화되어야 하는 멤버 이름 배열을 반환합니다. 이러한 방식으로 직렬화해야 하는 데이터를 제어할 수 있습니다. 이 경우에는 hack_name만 반환했습니다. code>. hack_name 멤버만 직렬화된 것을 볼 수 있습니다.

직렬화가 완료된 후 __wakeup가 사용됩니다. 여기서는 데이터베이스에 다시 연결하는 등의 후속 작업을 수행할 수 있습니다.

3. 직렬화 가능 인터페이스 사용자 정의

interface Serializable {
abstract public string serialize ( void )
abstract public void unserialize ( string $serialized )
}

이 인터페이스를 통해 직렬화 및 역직렬화 동작을 사용자 정의할 수 있습니다.

class fobnn implements Serializable
{
 public $hack_id;
 private $hack_name;
 public function __construct($name,$id)
 {
  $this->hack_name = $name;
  $this->hack_id = $id;
 }
 public function print()
 {
  echo $this->hack_name.PHP_EOL;
 }

 public function __sleep()
 {
  return array('hack_name');
 }

 public function __wakeup()
 {
  $this->hack_name = 'haha';
 }

 public function serialize()
 {
  return json_encode(array('id' => $this->hack_id ,'name'=>$this->hack_name ));
 }

 public function unserialize($var)
 {
  $array = json_decode($var,true);
  $this->hack_name = $array['name'];
  $this->hack_id = $array['id'];
 }
}
$obj = new fobnn('fobnn',1);
$obj->print();
$serializedstr = serialize($obj);
echo $serializedstr.PHP_EOL;;
$toobj = unserialize($serializedstr);
$toobj->print();
fobnn
C:5:"fobnn":23:{{"id":1,"name":"fobnn"}}
fobnn

사용자 정의 직렬화 인터페이스를 사용한 후에는 메소드는 쓸모가 없습니다.

hack_name,可以看到结果中只序列化了hack_name成员.

在序列化完成之后,会跳用__wakeup在这里我们可以做一些后续工作,例如重连数据库之类的.

3.自定义Serializable接口

class fobnn
{
 public $hack_id;
 public $hack_name;
 public function __construct($name,$id)
 {
  $this->hack_name = $name;
  $this->hack_id = $id;
 }
 public function print()
 {
  var_dump($this->hack_name);
 }
}
$obj = new fobnn('fobnn',1);
$obj->print();
$serializedstr = serialize($obj);
echo $serializedstr.PHP_EOL;;
$toobj = unserialize($serializedstr);
$toobj->print();
$toobj2 = unserialize("O:5:\"fobnn\":2:{s:7:\"hack_id\";i:1;s:9:\"hack_name\";i:12345;}");
$toobj2->print();

通过这个接口我们可以自定义序列化和反序列化的行为,这个功能主要可以用来自定义我们的序列化格式.

string(5) "fobnn"
O:5:"fobnn":2:{s:7:"hack_id";i:1;s:9:"hack_name";s:5:"fobnn";}
string(5) "fobnn"
int(12345)
rrreee

当使用了自定义序列化接口之后,我们的魔术方法就没用了.

4.PHP动态类型和PHP反序列化

既然上文中提到的自描述功能,那么序列化结果中保存了对象的类型,且php是动态类型语言,那么我们就可以来做个简单的实验.

rrreee

我们修改hack_name反序列化的结果为int类型, i:12345

4.PHP 동적 유형 및 PHP 역직렬화

🎜🎜위에서 언급한 자체 설명 함수이므로 직렬화 결과에 개체 유형이 저장되고 PHP는 동적 유형 언어이므로 우리는 간단한 실험을 할 수 있습니다.🎜rrreee🎜 hack_name의 역직렬화 결과를 int 유형으로 수정하면 i:12345🎜rrreee🎜를 찾을 수 있습니다. 물론 이 PHP 메커니즘은 유연한 구문을 제공하지만 보안 위험도 발생합니다. 우리는 PHP 직렬화 및 역직렬화 기능으로 인해 발생하는 보안 문제를 계속 분석할 것입니다.

위 내용은 PHP 직렬화 및 역직렬화 원리 직접 살펴보기의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 jb51.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제