객체 직렬화 — 세션 속의 객체
객체 직렬화 — 세션 속의 객체
serialize()는 PHP에 저장할 수 있는 모든 값을 바이트 스트림(문자열) 형태로 바꾼 문자열을 돌려줘요. 그리고 unserialize()는 이 문자열을 다시 원래의 변수 값으로 복원해 줍니다. serialize로 객체를 저장하면 그 객체 안의 모든 변수는 그대로 저장되고, 객체의 메서드는 저장되지 않아요. 대신 그 객체가 어떤 클래스인지, 클래스 이름만 함께 저장됩니다.
unserialize()로 객체를 되살리려면 그 객체의 클래스가 정의되어 있어야 해요. 예를 들어 A 클래스의 객체를 serialize하면, 결과 문자열에는 A 클래스를 가리키는 이름과 함께 그 안에 들어 있는 모든 변수 값이 담깁니다. 이 객체를 다른 파일에서 unserialize하려면, 그 파일에 A 클래스의 정의가 먼저 있어야 하죠. 이렇게 하려면 예를 들어 A.php의 클래스 정의를 include 파일로 만들어 두고 그 파일을 포함시키거나, spl_autoload_register() 함수를 이용하면 됩니다.
<?php
// A.php:
class A {
public $one = 1;
public function show_one() {
echo $this->one;
}
}
// page1.php:
include "A.php";
$a = new A;
$s = serialize($a);
// store $s somewhere where page2.php can find it.
file_put_contents('store', $s);
// page2.php:
// this is needed for the unserialize to work properly.
include "A.php";
$s = file_get_contents('store');
$a = unserialize($s);
// now use the function show_one() of the $a object.
$a->show_one();
?>
page1.php에서 $a를 직렬화해 파일에 저장하고, page2.php에서 다시 읽어 되살린 뒤 show_one()을 호출하고 있어요. 두 파일 모두 A.php를 먼저 include해서 클래스 정의를 준비해 두는 게 핵심이에요.
애플리케이션이 나중에 쓸 목적으로 객체를 직렬화한다면, 앱 전체에서 그 객체의 클래스 정의를 포함하도록 하는 걸 강력히 권장합니다. 그러지 않으면 클래스 정의 없이 객체가 역직렬화될 수 있는데, 그렇게 되면 PHP는 그 객체에 __PHP_Incomplete_Class_Name이라는 클래스를 부여해요. 이 클래스에는 메서드가 전혀 없어서, 결국 그 객체는 쓸모없게 돼버립니다.
위 예시에서 $a가 $_SESSION 슈퍼글로벌 배열에 새 키를 추가해 세션의 일부가 된다면, page1.php와 page2.php뿐 아니라 모든 페이지에서 A.php를 include해야 합니다.
이 방법 말고도, 객체의 직렬화·역직렬화 시점에 끼어들 수 있는 훅이 있어요. 바로 __sleep()과 __wakeup() 메서드를 이용하는 거예요. __sleep()을 쓰면 객체의 일부 프로퍼티만 골라서 직렬화할 수도 있습니다.