serialize() 함수
형식 : string serialize(mixed value)
PHP4 스크립트부터 객체를 serialize() 함수를 이용하여 다른 매체에 저장할 수 있는 문자열로 직렬화(serialize)시킬 수 있습니다. PHP3에서도 객체의 멤버변수까지는 직렬화할 수 있었지만 메소드까지는 지원되지 않았는데 PHP4부터는 메소드까지 지원하기 시작한 것이지요. 여러분이 잘 알고 계시는 세션함수가 내부적으로 바로 serialize()를 이용하여 등록된 세션변수값을 파일로 저장할 수 있도록 직렬화하는 것입니다. 그런데 이 serialize() 함수가 객체를 다룰 때 멤버변수만 다루지 메소드는 무시해 버립니다. 정확하게 이야기 하면 메소드 정의를 포함하고 있는 클래스명만 기록하며 클래스에 포함된 메소드 정의 부분은 다루지 않습니다. 앞장 "클래스와 인스턴스"를 주의깊게 읽어 보셨다면 serialize() 함수가 왜 메소드 정의를 다루지 않는 지를 이해할 수 있을 것입니다. serialize() 함수는 객체를 다루는 함수이지 클래스를 다루는 함수는 아닙니다. 객체에는 메소드가 포함되어 있지 않습니다. 따라서 객체를 직렬화한다고 해도 클래스에 포함되어 있는 메소드 정의 부분을 직렬화한다는 것은 올바르지 않지요. 메소드는 같은 클래스에서 생성된 모든 객체가 공유해야 할 정보이지 특정 객체에만 편입된 정보가 아니기 때문에 특정 객체를 직렬화 한다고 해서 직렬화된 정보에 메소드 정의 정보가 포함될 수 없는 것입니다. 이젠 제가 왜 serialize()/unserialize() 함수를 설명하기 전에 "클래스와 인스턴스"라는 주제를 앞 장에 삽입하여 장황하게 설명했는지 이해하실 것 입니다. 클래스와 인스턴스 개념을 이해하고 있지 못하면 왜 serialize() 함수가 메소드 정의 부분을 포함하여 직렬화 시키지 않았는지를 이해할 수가 없습니다.
예를 들어 아래와 같이 session_register() 함수를 이용하여 객체 변수 $obj를 등록시키겠습니다.
 <?php
 // 파일명 : test1.php

 class test {
   var $a = "1234ASDF";
  
   function test() {}
  
   function output() {
     echo($this->a);
   }
 }
  
 session_register("obj");
 $obj = new test();
 $obj->output();
 ?>

 <p><A href=test2.php>TEST2.PHP</A></p>
이와 같이 세션 등록을 하면 스크립트가 종료되는 순간에 객체를 serialize() 함수를 이용하여 직렬화한 후 서버의 /tmp 디렉토리에 sess_xxxxxxxxxxx 파일명으로 직렬화된 문자열을 저장하게 되는데 그 내용이 아래와 같습니다.
obj|O:4:"test":1:{s:1:"a";s:8:"1234ASDF";}
여기서 obj는 객체변수명, "test"는 클래스명, "a"는 멤버변수명, "1234ASDF"는 멤버변수값을 나타냅니다. 메소드에 관한 정보는 모두 빠져 있는 것을 볼 수 있습니다. 만약 PHP3에서 serialize() 함수를 이용하여 객체를 직렬화 하였다면 멤버변수는 멤버변수명과 멤버변수값이 모두 정상적으로 기록되지만 메소드는 메소드명만 기록되지 메소드 정의 부분이 기록하지 않습니다. 이것이 PHP4에 와서는 메소드명까지 기록하지 않게 되었습니다. 대신에 클래스명이 기록되지요.
unserialize() 함수
형식 : mixed serialize(string str)
unserialize() 함수는 serialize() 함수를 이용하여 객체로부터 직렬화된 문자열을 다시 객체로 복원시켜 줍니다. serialize() 함수를 설명할 때 언급한 것처럼 직렬화할 때 객체의 메소드의 정보가 기록되지 않기 때문에 unserialize() 함수로 다시 객체화하더라도 우선 멤버변수만 접근할 수 있지 메소드는 접근할 수 없습니다.
 <?php
 // 파일명 : test2.php
  
 session_register("obj");
 $obj->output();
 ?>
  
 <p><A href=test1.php>TEST1.PHP</A></p>
위의 예제에서 5번째줄 $obj->output()는 객체의 메소드를 실행하여야 하는데 객체의 메소드는 복원할 수 없으므로 아래와 같은 에러가 발생합니다.
Fatal error: Call to undefined function: output()
in /서버의 디렉토리/test2.php on line 5
따라서 세션함수에 의해 복원된 객체를 가지고 메소드를 실행하기 위해서는 복원된 페이지 내에서 원래의 클래스의 정의를 아래와 같이 명시적으로 포함시켜야 합니다. 즉, 메소드 정의는 별도로 복원시켜주어야 하는 것이지요.
 <?php
 // 파일명 : test2.php
  
 class test {
   function output() {
     echo($this->a);
   }
 }
 session_register("obj");
 $obj->output();
 ?>
  
 <p><A href=test1.php>TEST1.PHP</A></p>
PHP4 에서 객체의 serialize() 함수가 멤버변수와 메소드를 모두 지원한다 하더라도 메소드 정의 부분은 포함되지 않으므로 unserialize() 함수로 복원된 객체를 온전히 사용하기 위해서는 메소드 정의를 별도로 포함시켜야 한다는 것에 주의하여야 합니다.
PHP4에서 메소드를 직렬화/객체화하기
예를 들어 아래와 같이 예제를 작성하여 PHP3와 PHP4 스크립트에 각각 실행하여 보면, test2.php를 실행하였을 때 PHP4에서는 정상적으로 메소드가 실행되지만 PHP3에서는 에러가 발생합니다.
 <?php
 // 파일명 : test1.php

 class test {
   var $a;
   var $b;

   function output() {
     return "나 함수";
   }
 }

 $obj = new test;

 $obj->a = 0;
 $obj->b = "나 b";

 echo "<p>".$obj->a."</p>";
 echo "<p>".$obj->b."</p>";
 echo "<p>".$obj->output()."</p>";

 $ser = urlencode(serialize($obj));

 echo "<p><A href=test2.php?ser=$ser>TEST2.PHP</A></p>";

 ?>
 <?php
 // 파일명 : test2.php

 class test {
   var $a;
   var $b;

   function output() {
     return "나 함수";
   }
 }

 $obj = unserialize(stripslashes($ser));

 echo "<p>".$obj->a."</p>";
 echo "<p>".$obj->b."</p>";
 echo "<p>".$obj->output()."</p>";

 ?>

 <p><A href=test1.php>TEST1.PHP</A></p>
아래는 PHP3에서 실행한 결과입니다. PHP3에서는 serialize()/unserialize()가 객체의 메소드를 지원하지 않기 때문에 test2.php를 실행할 때에 17번 라인에서 에러가 발생합니다.
test1.php를 실행하였을 때:

0
나 b
나 함수

TEST2.PHP

test2.php를 실행하였을 때:

0
나 b

Fatal error: Function call to a non-function (output)
in /home/httpd/homepage/phpclass/exam2/simple/test2.php on line 17
아래는 PHP4에서 실행한 결과입니다. PHP4에서는 serialize() -> unserialize() 과정을 거친 객체가 정상적으로 복원되었다는 것을 알 수 있습니다. 앞장에서 설명하였지만 메소드 정의는 별도로 포함시켜야 하는 것을 잊어서는 안됩니다. 메소드 정의를 생략한다면 역시 에러를 만나게 될 것입니다.
test1.php를 실행하였을 때:

0
나 b
나 함수

TEST2.PHP

test2.php를 실행하였을 때:

0
나 b
나 함수

TEST1.PHP
PHP3에서 메소드를 직렬화/객체화하기
PHP3 의 serialize()/unserialize() 함수에서 객체의 메소드를 다루면 에러가 발생하게 됩니다. 즉, PHP3의 serialize()/unserialize() 함수가 객체의 메소드를 지원하지 않기 때문입니다. 그래서 PHP3에서도 객체의 메소드를 직렬화/객체화할 수 있는 라이브러리를 작성하여 보았습니다. 이 라이브러리는 향후 세셔너를 업그레이드할 때 사용할 작정입니다. 그러면 PHP3에서도 모든 변수와 함께 객체에 대해서도 온전히 세션 관리할 수 있을 겁니다.
 <?php

 /*
 filename : serialize.php (ver.0.0.1)
 email    : hwooky@phpclass.com
 homepage : www.phpclass.com
 author   : hwooky
 */

 /*
 사용자 함수:
 string serialize3(mixed value, string classname);
 mixed unserialize3(string str);
 */

 function prvExplodeGroup($str) {
   $count = 0;
   $prefix = $middle = $suffix = "";

   do {
     $pos_start = ($pos_start = strpos($str, "{")) ? $pos_start : "NOTHING";
     $pos_end   = ($pos_end   = strpos($str, "}")) ? $pos_end   : "NOTHING";

     if ((string)$pos_start < (string)$pos_end) {
       // "{"로 시작되는 부분
       if (0 == $count) {
         $prefix = substr($str, 0, $pos_start);
         $str    = substr($str, $pos_start+1);
       } else {
         $middle .= substr($str, 0, $pos_start)."{";
         $str     = substr($str, $pos_start+1);
       }
       $count++;
     } else if ((string)$pos_start > (string)$pos_end) {
       // "}"로 시작되는 부분
       $middle .= substr($str, 0, $pos_end)."}";
       $str     = substr($str, $pos_end+1);
       $count--;
     }
   } while ($count);

   if ($middle) {
     $middle = substr($middle, 0, -1);
     $suffix = $str;
   } else {
     $prefix = $str;
   }

   return array($prefix, $middle, $suffix);
 }

 function prvSimplifyObjectString($str) {
   $pos = strpos($str, "{");
   $prefix = substr($str, 0, $pos);
   $val = substr($str, $pos+1, -2);

   $suffix = $val;
   $str = "";
   $count = 0;

   do {
     list($prefix, $middle, $suffix) = prvExplodeGroup($suffix);
     if ($middle)
       $str .= $prefix.$count++.";";
   } while ($middle);

   return $str.$prefix;
 }

 function serialize3(&$obj, $classname="") {
   $str = serialize($obj);
   return $classname.";".$str;
 }

 function unserialize3($str) {
   $pos = strpos($str, ";");
   $classname = substr($str, 0, $pos);
   $val = substr($str, $pos+1);
   $obj = unserialize($val);

   if ($classname && function_exists($classname)) {
     $tobj = new $classname;

     $val = prvSimplifyObjectString($val);
     $arg = explode(";", $val);

     for ($i=0;$i<sizeof($arg);$i+=2) {
       $sep = explode(":", $arg[$i]);
       $name = substr($sep[2], 1, -1);

       if ("user function" != gettype($tobj->$name))
         $tobj->$name = $obj->$name;
     }
     return $tobj;
   }
   return $obj;
 }

 ?>
serialize3() 함수를 보면 serialize() 함수에는 없는 두번째 인수를 지정하여야 합니다. 두번째 인수는 객체를 직렬화할 때만 사용되는 인수입니다. 객체 이외의 변수를 직렬화하는 방법은 serialize() 함수와 동일합니다. 객체를 직렬화하려면 첫번째 인수로는 직렬화하려는 객체명을 지정하고, 두번째 인수로는 객체를 생성할 때 필요한 클래스명을 지정합니다. 예를 들어,
 $obj = new test;
위와 같이 생성된 객체를 직렬화하려면
 serialize3($obj, "test");
위와 같이 객체변수와 클래스명을 지정하여 줍니다. 앞 장에서 다루었던 예제를 여기서도 그대로 사용하여 보겠습니다. 앞 장과 다른 점은 serialize.php 라이브러리를 인클루드하는 부분이 추가되었고, seiralize()/unseiralize() 함수 대신에 라이브러리에 있는 seiralize3()/unseiralize3() 함수를 사용하였다는 것입니다. 실행 결과는 PHP4의 경우와 동일합니다.
 <?php

 // 파일명 : test1.php3

 require("./serialize.php");

 class test {
   var $a;
   var $b;

   function output() {
     return "나 함수";
   }
 }

 $obj = new test;

 $obj->a = 0;
 $obj->b = "나 b";

 echo "<p>".$obj->a."</p>";
 echo "<p>".$obj->b."</p>";
 echo "<p>".$obj->output()."</p>";

 $ser = urlencode(serialize3($obj, "test"));

 echo "<p><A href=test2.php3?ser=$ser>TEST2.PHP3</A></p>";

 ?>
 <?php
 // 파일명 : test2.php3

 require("./serialize.php");

 class test {
   var $a;
   var $b;

   function output() {
     return "나 함수";
   }
 }

 $obj = unserialize3(stripslashes($ser));

 echo "<p>".$obj->a."</p>";
 echo "<p>".$obj->b."</p>";
 echo "<p>".$obj->output()."</p>";
 ?>

 <p><A href=test1.php3>TEST1.PHP3</A></p>
serialize.php 라이브러리를 이용할 때도 PHP4 때와 마찬가지로 serialize3() -> unserialize3() 과정을 거친 객체가 정상적으로 복원되었다는 것을 알 수 있습니다.
test1.php3를 실행하였을 때:

0
나 b
나 함수

TEST2.PHP3

test2.php3를 실행하였을 때:

0
나 b
나 함수

TEST1.PHP3