Skip to main content

A PHP serializer/unserializer for Python with comprehensive type annotations

Project description

phpserialize-typed

A PHP serializer/unserializer for Python with comprehensive type annotations.

License Python Versions Type Checked

Overview

This project is based on phpserialize by Armin Ronacher, licensed under BSD 3-Clause. The primary enhancement in phpserialize-typed is the addition of comprehensive type annotations to support static type checking with tools like mypy.

Key Features

  • Full Type Annotations: Complete type hints for all functions, classes, and methods
  • Static Type Checking: Compatible with mypy, pyright, and other type checkers
  • PEP 561 Compliant: Includes py.typed marker for distribution of type information
  • Backward Compatible: Maintains full API compatibility with the original phpserialize
  • PHP Serialize/Unserialize: Port of PHP's serialize() and unserialize() functions to Python
  • Object Support: Serialization and unserialization of PHP objects
  • Array Hooks: Custom array converters (e.g., OrderedDict)
  • Python 3.7+: Modern Python support with proper typing

Installation

pip install phpserialize-typed

Or install from source:

git clone https://github.com/pc028771/phpserialize-typed.git
cd phpserialize-typed
pip install -e .

Quick Start

from phpserialize import dumps, loads

# Serialize Python objects to PHP format
serialized = dumps({"name": "Alice", "age": 30})
print(serialized)  # b'a:2:{s:4:"name";s:5:"Alice";s:3:"age";i:30;}'

# Unserialize PHP data back to Python
data = loads(b'a:2:{s:3:"foo";s:3:"bar";s:3:"baz";i:42;}')
print(data)  # {'foo': 'bar', 'baz': 42}

Usage Examples

Basic Serialization

from phpserialize import dumps, loads

# Simple values
dumps("Hello World")  # b's:11:"Hello World";'
loads(b's:11:"Hello World";')  # b'Hello World'

# Numbers
dumps(42)  # b'i:42;'
dumps(3.14)  # b'd:3.14;'

# Lists (converted to PHP arrays with numeric keys)
dumps([1, 2, 3])  # b'a:3:{i:0;i:1;i:1;i:2;i:2;i:3;}'

Working with Dictionaries

from phpserialize import loads, dict_to_list

# PHP doesn't distinguish between lists and arrays
# So lists are returned as dicts with integer keys
result = loads(dumps([1, 2, 3]))
print(result)  # {0: 1, 1: 2, 2: 3}

# Convert back to list
dict_to_list(result)  # [1, 2, 3]

Unicode Strings

from phpserialize import dumps, loads

# Encoding
dumps("Hello Wörld")  # Encodes to UTF-8 by default

# Decoding
loads(dumps("Hello Wörld"), decode_strings=True)  # Decodes back to str

Object Serialization

from phpserialize import dumps, loads, phpobject

# Unserializing PHP objects
data = b'O:7:"WP_User":1:{s:8:"username";s:5:"admin";}'
user = loads(data, object_hook=phpobject)
print(user.username)  # 'admin'
print(user.__name__)  # 'WP_User'

# Custom object hook
class User:
    def __init__(self, username: str):
        self.username = username

def my_object_hook(name: str, d: dict):
    if name == b'WP_User' or name == 'WP_User':
        return User(**d)
    raise ValueError(f"Unknown class: {name}")

user = loads(data, object_hook=my_object_hook)

Using Array Hooks

from collections import OrderedDict
from phpserialize import loads

# Preserve order with OrderedDict
data = b'a:2:{s:3:"foo";i:1;s:3:"bar";i:2;}'
result = loads(data, array_hook=OrderedDict)
print(result)  # OrderedDict([('foo', 1), ('bar', 2)])

File-like Objects

from io import BytesIO
from phpserialize import dump, load

# Writing to stream
stream = BytesIO()
dump([1, 2, 3], stream)
print(stream.getvalue())  # b'a:3:{i:0;i:1;i:1;i:2;i:2;i:3;}'

# Reading from stream
stream = BytesIO(b'a:2:{i:0;i:1;i:1;i:2;}')
data = load(stream)
print(data)  # {0: 1, 1: 2}

Type Checking

This library is fully typed and can be used with static type checkers:

from typing import Dict, Any
from phpserialize import loads, dumps

# Type checker understands return types
data: bytes = dumps({"key": "value"})
result: Any = loads(data)  # Returns Any since PHP types are dynamic

# For more specific typing, use type narrowing or casts
from typing import cast
typed_result: Dict[str, str] = cast(Dict[str, str], loads(data))

Running mypy

mypy your_script.py

The library itself passes strict mypy checks:

mypy phpserialize.py --strict

API Reference

Functions

  • dumps(data, charset='utf-8', errors='surrogateescape', object_hook=None) -> bytes
    • Serialize Python object to PHP format
  • loads(data, charset='utf-8', errors='surrogateescape', decode_strings=False, object_hook=None, array_hook=None) -> Any
    • Unserialize PHP data to Python object
  • dump(data, fp, charset='utf-8', errors='surrogateescape', object_hook=None) -> None
    • Serialize to file-like object
  • load(fp, charset='utf-8', errors='surrogateescape', decode_strings=False, object_hook=None, array_hook=None) -> Any
    • Unserialize from file-like object
  • dict_to_list(d) -> list
    • Convert dict with sequential integer keys to list
  • dict_to_tuple(d) -> tuple
    • Convert dict with sequential integer keys to tuple
  • convert_member_dict(d) -> dict
    • Convert PHP member names to Python identifiers

Classes

  • phpobject(name, d=None)
    • Represents a PHP object
    • __name__: PHP class name
    • __php_vars__: Dictionary of object properties
    • _asdict(): Convert to regular dict

Development

Setting up development environment

# Clone the repository
git clone https://github.com/pc028771/phpserialize-typed.git
cd phpserialize-typed

# Install development dependencies
pip install -e ".[dev]"

Running tests

pytest tests/

Type checking

mypy phpserialize.py --strict

Credits

This project is based on phpserialize by Armin Ronacher.

Original Author: Armin Ronacher
Original License: BSD 3-Clause
Original Project: https://github.com/mitsuhiko/phpserialize

The modifications in phpserialize-typed add comprehensive type annotations while maintaining full backward compatibility with the original library.

License

BSD 3-Clause License. See LICENSE file for details.

This project maintains the original BSD 3-Clause license from phpserialize and adds appropriate copyright notices for the modifications.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Changelog

1.0.0 (2026-01-31)

First release of phpserialize-typed as an independent fork.

Added:

  • Comprehensive type annotations for all functions and classes
  • Protocol types for file-like objects (SupportsRead, SupportsWrite)
  • PEP 561 compliance with py.typed marker
  • Full pytest test suite (37 tests)
  • Development dependencies (pytest, mypy, pytest-cov)

Changed:

  • Migrated tests from unittest to pytest
  • Refactored serialization/unserialization into class-based architecture
  • Improved type safety with Generic types and stricter annotations

Maintained:

  • Full backward compatibility with phpserialize 1.3 API
  • All original functionality and behavior

Based on phpserialize by Armin Ronacher.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

phpserialize_typed-1.0.0.tar.gz (16.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

phpserialize_typed-1.0.0-py3-none-any.whl (12.0 kB view details)

Uploaded Python 3

File details

Details for the file phpserialize_typed-1.0.0.tar.gz.

File metadata

  • Download URL: phpserialize_typed-1.0.0.tar.gz
  • Upload date:
  • Size: 16.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for phpserialize_typed-1.0.0.tar.gz
Algorithm Hash digest
SHA256 ba1af82dc221e7caf535d6c8a83e01ebd2599408e5e24650dfb45d5532d7d6c1
MD5 b991578f9977ab1859541677ae28281d
BLAKE2b-256 eeabca18556a1fc36e0de81f73e2622a8ba5b10ea2df12baecb8512f2bc6616d

See more details on using hashes here.

File details

Details for the file phpserialize_typed-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for phpserialize_typed-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7e8c8b22d7ad04d13ce7882fe55d1957e874267cd3eafd94cbc8c38247c5edaf
MD5 ccb81762c69f57ca0359dccdd3006ee0
BLAKE2b-256 b50fe139b086028ec1867f86476c0cf321b16212cd2212332c0595f418c8f5db

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page