Thank you for your interest in contributing to the PHP Identifier Extension! This document provides guidelines and information for contributors.
- PHP 8.3 or higher with development headers (
php-configmust be available) - Zig 0.15.2+ (Download from ziglang.org)
- Git
- Clone the repository:
git clone https://github.com/castor-labs/php-ext-identifier.git
cd php-ext-identifier- Build and test the extension:
zig build dev # Build + test in one command- Verify the extension loads:
php -d extension=./modules/identifier.so -m | grep identifierThis project uses Zig's build system instead of traditional PHP extension build tools (phpize/autoconf). The build system:
- Automatically discovers all
.cfiles in thesrc/directory - Uses
php-configto get PHP include paths and extension directories - Compiles everything into
modules/identifier.so
Key build commands:
zig build # Build the extension
zig build test # Run tests
zig build dev # Build + test
zig build clean # Clean build artifacts
zig build generate-stubs # Generate PHP stubs
zig build verify-stubs # Verify stubs match APIThe codebase follows a one-file-per-class pattern:
src/php_identifier.h- Main header with all declarationssrc/php_identifier.c- Extension initialization and utility functionssrc/bit128.c- BaseBit128class implementationsrc/state.c- State interface registrationsrc/state_system.c- System state (uses real time/randomness)src/state_fixed.c- Fixed state (deterministic for testing)src/uuid.c- Base UUID classsrc/uuid_version{1,3,4,5,6,7}.c- Individual UUID implementationssrc/ulid.c- ULID implementationsrc/codec.c- Base32 encoding/decoding
Identifier\State (interface)
├── Identifier\State\System
└── Identifier\State\Fixed
Identifier\Bit128 (implements Stringable)
├── Identifier\Uuid (abstract)
│ ├── Version1, Version3, Version4, Version5, Version6, Version7
└── Identifier\Ulid
Identifier\Codec (static utility class)
- Implement in C: Add your implementation to the appropriate
.cfile (or create a new one insrc/) - Add arginfo: Define
ZEND_BEGIN_ARG_INFOdeclarations for proper type hints - Register methods: Add methods to the class's
zend_function_entryarray - Write tests: Create
.phpttest files intests/ - Build and test: Run
zig build dev - Generate stubs: Run
zig build generate-stubs - Verify stubs: Run
zig build verify-stubs - Update stubs: Copy
stubs/identifier_gen.stub.phptostubs/identifier.stub.php
Tests use the PHPT format:
--TEST--
Description of what this test does
--SKIPIF--
<?php if (!extension_loaded("identifier")) print "skip"; ?>
--FILE--
<?php
// Your test code here
?>
--EXPECT--
Expected outputPlace test files in tests/ and run with:
zig build test # Run all tests
php tools/run-tests.php -d extension=./modules/identifier.so tests/002-bit128.phpt # Run single test- Follow standard PHP extension conventions
- Use 4 spaces for indentation (not tabs)
- Add descriptive comments for complex logic
- Use PHP's memory allocators (
emalloc,efree, etc.) - never usemalloc/free
Object structure (always embed zend_object as last member):
typedef struct _php_identifier_myclass_obj {
// Your data fields here
unsigned char data[16];
// zend_object MUST be last
zend_object std;
} php_identifier_myclass_obj;Method implementation:
static PHP_METHOD(Identifier_MyClass, myMethod)
{
zend_string *input;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(input)
ZEND_PARSE_PARAMETERS_END();
// Your implementation
}Error handling:
if (some_error_condition) {
zend_throw_exception(zend_ce_exception, "Error message", 0);
RETURN_THROWS();
}Memory Management:
- Always use
emalloc(),efree(),ecalloc(),erealloc() - Never mix PHP allocators with system allocators
- Handle reference counting properly for zval objects
Random Number Generation:
- Use
php_identifier_generate_random_bytes()for cryptographic randomness - Never use OS functions directly (like
/dev/urandomorgetrandom())
Timestamps:
- Use
php_identifier_get_timestamp_ms()for millisecond timestamps - Use
php_identifier_get_gregorian_epoch_time()for UUID v1/v6
State System:
- All generator methods should accept optional
Stateparameter - Use
State\Systemfor real randomness - Use
State\Fixedfor deterministic testing
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature-name - Make your changes following the workflow above
- Ensure all tests pass:
zig build dev - Commit with clear, descriptive messages
- Push to your fork:
git push origin feature/your-feature-name - Submit a pull request
- Provide a clear description of the changes
- Reference any related issues
- Ensure all tests pass
- Include new tests for new functionality
- Update stubs if API changes
- Keep commits focused and atomic
Pull request titles must follow the Conventional Commits specification for automated release management:
Format: <type>: <description> or <type>(#issue): <description>
Allowed types:
feat- New feature (triggers minor version bump)fix- Bug fix (triggers patch version bump)perf- Performance improvement (triggers patch version bump)refactor- Code refactoring (triggers patch version bump)docs- Documentation changes onlystyle- Code style changes (formatting, etc.)test- Adding or updating testsbuild- Build system changesci- CI/CD changeschore- Other changes that don't modify src or test filesrevert- Reverts a previous commit
Examples:
feat: add support for UUID v8feat(#12): implement automated releasesfix: resolve memory leak in ULID generationfix(#45): correct timestamp calculationperf: optimize Base32 encodingdocs: update installation instructions
Important: The PR title will be used to generate the release notes and determine version bumps, so make it descriptive and accurate.
This project uses automated releases based on semantic versioning:
- Automated Release Management: When changes are merged to
main, the semantic-release workflow analyzes PR titles to determine the version bump - Version Determination:
feat- Bumps minor version (e.g., 0.1.0 → 0.2.0)fix,perf,refactor,revert- Bumps patch version (e.g., 0.1.0 → 0.1.1)BREAKING CHANGEin PR body - Bumps major version (e.g., 0.1.0 → 1.0.0)
- Release Artifacts: When a release is published:
- Source archives are created in PIE-compliant formats
- Binary artifacts are built for multiple platforms:
- Linux: x86_64, aarch64
- macOS: x86_64 (Intel), arm64 (Apple Silicon)
- Windows: x64, arm64 (both TS and NTS)
- All artifacts follow PIE naming conventions
- CHANGELOG: Automatically generated and updated with each release
Releases are fully automated - no manual intervention required:
- Merging a PR to
maintriggers the release workflow - The workflow creates a GitHub release with proper version tag
- Build artifacts are automatically uploaded to the release
- The CHANGELOG.md is updated automatically
The first release will start at version 0.1.0 based on the initial feature commits.
When reporting issues, please include:
- PHP version (
php -v) - Extension version
- Zig version (
zig version) - Operating system
- Minimal code example that reproduces the issue
- Expected vs actual behavior
- Any error messages or stack traces
- Check the stub file for API documentation
- Review existing test files in
tests/for usage examples - Look at existing implementations in
src/for code patterns - Open an issue for questions or discussions
By contributing to this project, you agree that your contributions will be licensed under the MIT License.
Thank you for contributing!