Сериализация и десериализация в формате PHP для 1С:Предприятие 8.х

В PHP 4 и старше предусмотрена функция serialize(mixed $value): string,  которая генерирует пригодное для хранения строковое представление любой переменной. Строковое представление используется для хранения или передачи значений PHP между скриптами без потери их типа и структуры. Обратная операция получения переменной из строкового представления реализует функция unserialize() .

Строковое представление сериализации - это особый внутренний формат вида:

Для использования таких данных за пределами среды PHP необходимо выполнять десериализацию таких данных, а для сохранения сериализацию.

В настоящей публикации описан формат сериализации и приведены коды функций для 1С:Предприятие 8.

Формат сериализации

Сериализация - это преобразование данных произвольной структуры в строковую последовательность конечной длины, для которой в последствии может быть выполнено обратное преобразование для получения исходной структуры данных. В PHP подобное преобразование выполняет несколько пар функций, однако основной является пара serialize() и unserialize().
Сериализованные в строки данные имеют вид a:3:{i:1;s:5:"elem1";i:2;s:5:"elem2";i:3;s:5:"elem3";} и удобны для хранения в базе данных.

Скалярные типы:
  • Булево сериализуется как: b:<i>; где <i> это целое числовое значения 0 (Ложь) или 1 (Истина).
  • Целое сериализуется как: i:<i>; где <i> это числовое значение.
  • Число с плавающей точкой сериализуется как (для d подразумевается двойная точность double): d:<f>; где <f> это числовое значение.
  • Строка сериализуется как: s:<i>:"<s>"; где <i> это представленная длина строки, и <s> это сама строка.
Специальные типы:
  • Значение null просто сериализуется символом N;
Составные типы:
  • Массив сериализуется последовательностью a:<i>:{<elements>} где <i> это число элементов в массиве, а <elements> это пустой или непустой набор пар, разделенных ;
    • каждая пара образуется как <key>;<value> где <key> представляется скалярным типом , и <value> любым сериализуемым значением.

Следует учесть, что массив в PHP соответствует 1с-типу Соответствие.

  • Объект сериализуется как: O:<i>:"<s>":<i>:{<properties>} где первый <i> это целое число представляющее длину <s>, и <s> это имя класса (class name prepended with full namespace). Второй  <i> это целое, представляющее число свойств объекта. <properties> это пустой или нет набор пар:
    • <name>;<value> где <name> это сериализованная строка представляющая имя свойства и <value> любое сериализуемое значение.

При сериализации объекта имя свойства <name> содержит сведение о его видимости, поскольку <name> представляется как s:<i>:"<s>"; где <i> это целое представляющее длину <s>. Но значение <s> может быть различным в зависимости от видимости свойства:

      • для public свойства <s> это просто имя свойства.
      • для protected свойства <s> это также просто имя свойства, начинающееся символом *, заключенным в два NUL-символа (Chr(0)).
      • для private свойства <s> это имя свойства, начинающееся символом s, заключенным в два NUL-символа.
Другие типы:

Кроме перечисленных существуют и другие случаи как:  R:<i>; который представляет php-ссылку. Этот тип автору не встречался и его обработка алгоритмом не предусмотрена, поэтому в настоящей публикации он не рассматривается.

Реализация для 1С

Любые структуры данных 1С могут быть сериализованы в строку в полном соответствии с форматом PHP, а также почти любые данные сериализованные в среде PHP могут быть десерализованны в 1С. Некоторую неоднозначность вызывает десериализация составных типов, поскольку в PHP составные типы представлены типами Массив и Объект, в то время как 1С предусматривает типы Массив, Структура, Соответствие (а кроме того СписокЗначений, ТаблицаЗначений, ДеревоЗначений). Наиболее точно друг другу соответствует типы php-Массив и 1с-Соответствие, при этом php-индекс тождественен 1с-ключу.

Сериализация

Основная функция общего модуля СериализоватьРНР(Значение, Глубина)

  • Описание: Рекурсивная функция выполняет сериализацию произвольного значения в строк по формату PHP.
  • Параметры:
    • Значение - значение произвольного типа, которое будет сериализовано в формат PHP строки
    • Глубина - глубина рекурсивности для обхода сложных типов нахоящихся в Значении сложного типа
  • Возвращаемое значение: строка сериализации Значения

В коде функции применен не рекомендованный  1С способ директивы условной компиляции, который исключают компиляцию фрагмента сериализации объектов на Клиенте, который обычно там и не может находиться.

Десериализация

Функция общего модуля ДесериализоватьРНР(СтрокаСериализации, КурсорСтроки=1)
  • Описание: Рекурсивная функция выполняет десериализацию строки, являющейся сериализацией по формату PHP
  • Параметры:
    • СтрокаСериализации - строка, которая будет десериализована
    • КурсорСтроки - числовой, возвращаемый, устанавливает начало десериализации, по умолчанию =1, возвращаемое значение позволяет проконтролировать индекс завершение сериализации
  • Возвращаемое значение: возвращает десериализованное значение скалярного типа Булево, Число, Строка, NULL или Соотвествие

Приведенный код рассчитан на обработку корректной php-сериализации и не обрабатывает возможные ошибки, поэтому в некоторых случаях десериализация может возвратить абракадабру или даже безнадежно зациклиться.

Улучшение перечисленных недостатков я пока отложу до тех пор, пока они не начнут создавать для меня слишком существенные неудобства. Если кто-либо испытает подобное неудобство раньше, то устранить их не представит большого труда.

Дополнительные функции

Функция общего модуля СредРНР(Строка, НачальныйНомер, ЧислоСимволов) Экспорт
  • Описание: Функция работает аналогично стандартной Сред(), но корректирует значение ЧислоСимволов. Поскольку в PHP используется такая кодировка символов, при которой символы ASCII используют один символ, а символы национальных раскладок используют два, три или четыре символа (длина UTF-8 кода), то указываемая для s:<i>:"<s>"; длина строки php-символов оказывается больше, чем длина строки 1с-символов, если в строке присутствуют национальные символы.
    • Например: s:5:"А+Б"; при указанной php-длине 5, имеет 1с-длину 3, поэтому функция СредРНР(), получив параметр ЧислоСимволов=5, скорректирует его до ЧислоСимволов=3 и возвратит его по ссылке, и возвращаемую подстроку также уменьшит до 3 символов.
  • Параметры:
    • Строка - строка, из который извлекается подстрока
    • НачальныйНомер - числовой, номер первого символа подстроки в Строке
    • ЧислоСимволов - числовой, возвращаемый, первоначальная длина подстроки в php-символах, значение уменьшается на 1 для каждого найденного в подстроке национального символа
  • Возвращаемое значение: Строка

Функция общего модуля СтрДлинаРНР(СтрокаРНР) Экспорт
  • Описание: Функция работает аналогично стандартной СтрДлина(), но измеряет длину строки в байтах кодировки UTF-8, как требует PHP для указания в строке сериализации
  • Параметры: СтрокаРНР - измеряемая строка
  • Возвращаемое значение: количество байтов в строке PHP в кодировке UTF-8

Источники:

© «РеКС» и DrLightman, 2019

Авторское право принадлежит автору.
При использовании ссылка на источник обязательна.
Исходные тексты предоставлены в свободное использования "как есть" без ответственности за последствия.

Leave a Reply