Проблема PHP4 vs PHP5 функции serialize/unzerialize

chernomyrdin

Новичок
Проблема PHP4 vs PHP5 функции serialize/unzerialize

День добрый,

Достался проект написанный на PHP4 (4.4.8), все это крутится под FreeBSD 6.2 + Mysql 5.0.41 + Apache 2.0.59,
Хотелось-бы перейти на PHP5, но есть проблема - в SQL-е хранятся структуры данных (довольно сложные) и как следствие то, что сделано в PHP4 не всегда получается корректно unserialize в PHP5, Например:
PHP:
class item {
	function item( &$ptr, $id ) {
		$this->p = &$ptr;
		$this->id = $id;
	}
}
class container {
	var $l = array();
	function container() {
		$this->p = &$this;
	}
	function add( &$ptr ) {
		$this->l[ $ptr->id ] = &$ptr;
	}
}

$c = new container;
$i1 = new item( $c, 'item1' );
$c->add( $i1 );
$i2 = new item( $c, 'item2' );
$c->add( $i2 );

echo str_replace(array("}","{"),array("}\n","{\n"),serialize($c)),"\n";
Соответственно для PHP5 получается достаточно красивая структура:
Код:
O:9:"container":1:{
	s:1:"l";a:2:{
		s:5:"item1";O:4:"item":2:{
			s:1:"p";R:1;
			s:2:"id";s:5:"item1";
		}
		s:5:"item2";O:4:"item":2:{
			s:1:"p";R:1;
			s:2:"id";s:5:"item2";
		}
	}
}
А для PHP4 получаю непонятно что:
Код:
O:9:"container":1:{
	s:1:"l";a:2:{
		s:5:"item1";O:4:"item":2:{
			s:1:"p";O:9:"container":1:{
				s:1:"l";a:2:{
					s:5:"item1";R:3;
					s:5:"item2";O:4:"item":2:{
						s:1:"p";R:4;
						s:2:"id";s:5:"item2";
					}
				}
			}
			s:2:"id";s:5:"item1";
		}
		s:5:"item2";R:6;
	}
}
Собственно вопросов два:
- Это хоть как-то лечится ?
- Что делать ?
 

chernomyrdin

Новичок
Нет, это слегка переформарированный serialize, могу и var_dump:
Для PHP5 это:

Код:
object(container)#1 (2) {
  ["l"]=>
  array(2) {
    ["item1"]=>
    &object(item)#2 (2) {
      ["p"]=>
      &object(container)#1 (2) {
        ["l"]=>
        array(2) {
          ["item1"]=>
          &object(item)#2 (2) {
            ["p"]=>
            *RECURSION*
            ["id"]=>
            string(5) "item1"
          }
          ["item2"]=>
          &object(item)#3 (2) {
            ["p"]=>
            *RECURSION*
            ["id"]=>
            string(5) "item2"
          }
        }
        ["p"]=>
        *RECURSION*
      }
      ["id"]=>
      string(5) "item1"
    }
    ["item2"]=>
    &object(item)#3 (2) {
      ["p"]=>
      &object(container)#1 (2) {
        ["l"]=>
        array(2) {
          ["item1"]=>
          &object(item)#2 (2) {
            ["p"]=>
            *RECURSION*
            ["id"]=>
            string(5) "item1"
          }
          ["item2"]=>
          &object(item)#3 (2) {
            ["p"]=>
            *RECURSION*
            ["id"]=>
            string(5) "item2"
          }
        }
        ["p"]=>
        *RECURSION*
      }
      ["id"]=>
      string(5) "item2"
    }
  }
  ["p"]=>
  object(container)#1 (2) {
    ["l"]=>
    array(2) {
      ["item1"]=>
      &object(item)#2 (2) {
        ["p"]=>
        *RECURSION*
        ["id"]=>
        string(5) "item1"
      }
      ["item2"]=>
      &object(item)#3 (2) {
        ["p"]=>
        *RECURSION*
        ["id"]=>
        string(5) "item2"
      }
    }
    ["p"]=>
    *RECURSION*
  }
}
Для PHP4:
Код:
object(container)(2) {
  ["l"]=>
  array(2) {
    ["item1"]=>
    &object(item)(2) {
      ["p"]=>
      &object(container)(2) {
        ["l"]=>
        array(2) {
          ["item1"]=>
          &object(item)(2) {
            ["p"]=>
            &object(container)(2) {
              ["l"]=>
              *RECURSION*
              ["p"]=>
              &object(container)(2) {
                ["l"]=>
                array(0) {
                }
                ["p"]=>
                &object(container)(2) {
                  ["l"]=>
                  array(0) {
                  }
                  ["p"]=>
                  *RECURSION*
                }
              }
            }
            ["id"]=>
            string(5) "item1"
          }
          ["item2"]=>
          &object(item)(2) {
            ["p"]=>
            &object(container)(2) {
              ["l"]=>
              *RECURSION*
              ["p"]=>
              &object(container)(2) {
                ["l"]=>
                array(0) {
                }
                ["p"]=>
                &object(container)(2) {
                  ["l"]=>
                  array(0) {
                  }
                  ["p"]=>
                  *RECURSION*
                }
              }
            }
            ["id"]=>
            string(5) "item2"
          }
        }
        ["p"]=>
        &object(container)(2) {
          ["l"]=>
          array(0) {
          }
          ["p"]=>
          &object(container)(2) {
            ["l"]=>
            array(0) {
            }
            ["p"]=>
            *RECURSION*
          }
        }
      }
      ["id"]=>
      string(5) "item1"
    }
    ["item2"]=>
    &object(item)(2) {
      ["p"]=>
      &object(container)(2) {
        ["l"]=>
        array(2) {
          ["item1"]=>
          &object(item)(2) {
            ["p"]=>
            &object(container)(2) {
              ["l"]=>
              *RECURSION*
              ["p"]=>
              &object(container)(2) {
                ["l"]=>
                array(0) {
                }
                ["p"]=>
                &object(container)(2) {
                  ["l"]=>
                  array(0) {
                  }
                  ["p"]=>
                  *RECURSION*
                }
              }
            }
            ["id"]=>
            string(5) "item1"
          }
          ["item2"]=>
          &object(item)(2) {
            ["p"]=>
            &object(container)(2) {
              ["l"]=>
              *RECURSION*
              ["p"]=>
              &object(container)(2) {
                ["l"]=>
                array(0) {
                }
                ["p"]=>
                &object(container)(2) {
                  ["l"]=>
                  array(0) {
                  }
                  ["p"]=>
                  *RECURSION*
                }
              }
            }
            ["id"]=>
            string(5) "item2"
          }
        }
        ["p"]=>
        &object(container)(2) {
          ["l"]=>
          array(0) {
          }
          ["p"]=>
          &object(container)(2) {
            ["l"]=>
            array(0) {
            }
            ["p"]=>
            *RECURSION*
          }
        }
      }
      ["id"]=>
      string(5) "item2"
    }
  }
  ["p"]=>
  &object(container)(2) {
    ["l"]=>
    array(0) {
    }
    ["p"]=>
    &object(container)(2) {
      ["l"]=>
      array(0) {
      }
      ["p"]=>
      *RECURSION*
    }
  }
}
 

Glazyrin Sergey

Новичок
А может написать скриптик который перегонит все в json - на пхп 4 запусти его
А потом перегнать из json в serialize в пхп5 ?
Проблем быть не должно

-~{}~ 23.01.09 13:18:

Как один из вариантов
 

chernomyrdin

Новичок
Понятно что в каких-то случаях PHP4 вставляет копию объекта вместо ссылки. Вопрос как с этим боротся...

Уже и ссылок (&) где надо и где не надо навставлял...
 

StUV

Rotaredom
chernomyrdin
действительно, логично с самого начала конвертнуть данные в единый общий формат и не париться с различием в структуре serialize 4 vs. 5
 

chernomyrdin

Новичок
Автор оригинала: Glazyrin Sergey
А может написать скриптик который перегонит все в json - на пхп 4 запусти его
А потом перегнать из json в serialize в пхп5 ?
Единственный вопрос, через что работает json...
serialize работает где-то на уровне ядра интерпретатора php, и все беда у него что бардак у него на уровне ядра, куча копированных объяектов разной степени готовности (на какой момент производились действия с объектом)
 

Glazyrin Sergey

Новичок
JSON - это представление данных строковое - поверь проблем не будет
для PHP4 - юзай PEAR/Services_JSON
для PHP5 - юзай родной json_encode json_decode
если возникнут проблемы и для php5 юзай PEAR/Services_JSON
чтобы все было в единообразном стиле
 

chernomyrdin

Новичок
Автор оригинала: StUV
chernomyrdin
действительно, логично с самого начала конвертнуть данные в единый общий формат и не париться с различием в структуре serialize 4 vs. 5
Это хорошо когда все начинать сначала - тут нет проблем
Допустим я все данные перегоню в XML и буду этот XML загружать... В случае с PHP4 я боюсь получить достаточно кривые данные внутри...
Так как даже на таком банальном примере видно что, 4 и 5 работают по-разному.
Вопрос про то, как их хранить внутри PHP, если ссылки использовать нельзя, а очень хочется :)

То есть как модифицировать данный пример кода что-бы и в 4 и в 5 при serialize или каком другом методе зкспорте внутренних данных во вне я получал одинаковые данные.

-~{}~ 23.01.09 13:59:

Автор оригинала: Glazyrin Sergey
JSON - это представление данных строковое - поверь проблем не будет
для PHP4 - юзай PEAR/Services_JSON
для PHP5 - юзай родной json_encode json_decode
если возникнут проблемы и для php5 юзай PEAR/Services_JSON
чтобы все было в единообразном стиле
Попробывал, взял JSON с http://pear.php.net/pepr/pepr-proposal-show.php?id=198
код:

PHP:
include 'JSON.php';

class item {
	function item( &$ptr, $id ) {
		$this->p = &$ptr;
		$this->id = $id;
	}
}
class container {
	var $l = array();
	function add( &$ptr ) {
		$this->l[ $ptr->id ] = &$ptr;
	}
}

$c = new container;
$i1 = new item( $c, 'item1' );
$c->add( $i1 );
$i2 = new item( $c, 'item2' );
$c->add( $i2 );

if( function_exists('json_encode') ) {
	$str = json_encode( $c );
}
else {
	$json = new Services_JSON();
	$str = $json->encode( $c );
}
echo $str,"\n";
Падает по segmentation fault на PHP4
На PHP5 получаю:
Код:
Warning: json_encode(): recursion detected in sample.php on line 24

Warning: json_encode(): recursion detected in sample.php on line 24
{"l":{"item1":{"p":{"l":null},"id":"item1"},"item2":{"p":{"l":null},"id":"item2"}}}
То есть с рекурсивными данными json работать не может...
 

chernomyrdin

Новичок
Самое смешное, что если все сделать без использования объектов, то поведение 4 и 5-ки становится более менее одинаковым.
Пример:
PHP:
$c = array();
$c['l'] = array(
	'item1'	=> array( 'p' => &$c, 'id' => "item1" ),
	'item2'	=> array( 'p' => &$c, 'id' => "item2" ),
);
По serialize я получаю:
Код:
a:1:{
	s:1:"l";a:2:{
		s:5:"item1";a:2:{
			s:1:"p";a:1:{
				s:1:"l";a:2:{
					s:5:"item1";a:2:{
						s:1:"p";R:4;
						s:2:"id";s:5:"item1";
					}
					s:5:"item2";a:2:{
						s:1:"p";R:4;
						s:2:"id";s:5:"item2";
					}
				}
			}
			s:2:"id";s:5:"item1";
		}
		s:5:"item2";a:2:{
			s:1:"p";R:4;
			s:2:"id";s:5:"item2";
		}
	}
}
Умом логику работы не понять :)
 

Glazyrin Sergey

Новичок
кстати у json_encode есть параметр второй указывающий что нужно все делать в массивах

-~{}~ 23.01.09 15:06:

ой верней json_decode :) упс извините перепутал
 

StUV

Rotaredom
да не нужны здесь ни serialize, ни json
надо просто разобраться в структуре данных и пересохранить их "в понятно-структурированном виде"
 

Glazyrin Sergey

Новичок
Согласен, но если на таком хранении данных завязан весь проект, то лучше как то их сконвертировать в нормальный вариант, или ты предпочтешь переписывать проект ?
 

dimagolov

Новичок
Glazyrin Sergey, то, что ты сейчас делаешь называется speculation. Автор топика сказал только что у него в БД для чего-то хранятся сериализованные объекты из PHP4. Исходя из существенных различий в реализации ООП в 4 и 5, то даже успешно десеарилизованные они потребуют переработки для жизни в 5-ке. А раз так, то вполне можно переделать и механизм их хранения.

2 chernomyrdin: Это у тебя там что, объектная БД хранилась в SQL-е?
 

Glazyrin Sergey

Новичок
Автор оригинала: dimagolov
Glazyrin Sergey, то, что ты сейчас делаешь называется speculation. Автор топика сказал только что у него в БД для чего-то хранятся сериализованные объекты из PHP4. Исходя из существенных различий в реализации ООП в 4 и 5, то даже успешно десеарилизованные они потребуют переработки для жизни в 5-ке. А раз так, то вполне можно переделать и механизм их хранения.

2 chernomyrdin: Это у тебя там что, объектная БД хранилась в SQL-е?
:)
 

StUV

Rotaredom
Согласен, но если на таком хранении данных завязан весь проект, то лучше как то их сконвертировать в нормальный вариант, или ты предпочтешь переписывать проект ?
думаю, структуры данных, которые работают с этими сериализованными данными вполне можно замапить отдельной прослойкой функций/классов на некоторое "обобщенное" представление, реализовав прямое/обратное преобразование из этого представления в сериализованные для 4-ки и 5-ки

если подобная "прослойка" больше по объему собственно кода проекта - то да, я бы посоветовал переписать проект (и больше никогда так над данными не издеваться ;))
 

chernomyrdin

Новичок
Автор оригинала: dimagolov
2 chernomyrdin: Это у тебя там что, объектная БД хранилась в SQL-е?
Да, есть пара мест где хранятся объекты :-(
С ними-то как раз и проблемы.
Пытался просто написать код (на PHP4) что-бы можно было-бы эти данные сохранить так что-бы их можно было-бы де-сериализовать в PHP5.
Пока написал только некий оптимизатор объектов, который в некоторых местах корректирует объекты дабы они занимали меньше места и были "более правильными" с точки зрения того, что я хочу получить...
Но цели - десериализация объектов в PHP5 пока не достиг.

Сейчас подумываю о том что-бы корректно "задампить" все это в XML и потом на PHP5 его парсать... Там тоже есть несколько грабель и написать переносимый код PHP4->PHP5 без использования phpversion не получается...
PHP:
if( intval(phpversion()) > 5 ) {
    # ... PHP5 код
}
else {
   # ... PHP4 код
}
В идеале хотелось-бы получить код который корректно работает и 4-ке и в 5-ке.

-~{}~ 26.01.09 10:23:

Автор оригинала: StUV
думаю, структуры данных, которые работают с этими сериализованными данными вполне можно замапить отдельной прослойкой функций/классов на некоторое "обобщенное" представление, реализовав прямое/обратное преобразование из этого представления в сериализованные для 4-ки и 5-ки

если подобная "прослойка" больше по объему собственно кода проекта - то да, я бы посоветовал переписать проект (и больше никогда так над данными не издеваться ;))
Проект достаточно большой и целиком его переписывать нет ни какого желания,
А вот с прослйкой - есть тонкости... Так как 4 и 5 по-разному размещают данные внутри объектов. Но кое-какие идеи есть.

Цель поста - собрать как можно больше данных про то, как работает объектная модель и как писать переносимый код для объектов в PHP (переносимы объектный код :)
 

chernomyrdin

Новичок
Автор оригинала: Glazyrin Sergey
http://www.ibm.com/developerworks/ru/library/x-xml2jsonphp/index.html
Вы это так и не читали ?
Читал.

Но как-то сам формат сериализации не решает, так например можно дампить не в JSON а в YAML, благо модули для этого существует...
Беда модулей в том, что они не очень хорошо работают с рекурсивными данными....

Ну а при написании своего сериализатора, все равно во что сериализировать.
 
Сверху