diff --git a/.github/workflows/test-pecl-package/action.yml b/.github/workflows/test-pecl-package/action.yml index c0e005e7..f362452c 100644 --- a/.github/workflows/test-pecl-package/action.yml +++ b/.github/workflows/test-pecl-package/action.yml @@ -67,6 +67,7 @@ runs: - name: Determine package info shell: bash + id: package-info env: SKIP_CREATION: ${{ inputs.skip-package-creation }} PACKAGE_PATH: ${{ inputs.package-path }} @@ -95,7 +96,17 @@ runs: echo "Package directory: $PACKAGE_DIR" echo "Version: $VERSION" + # Check if version contains 'rc' (case-insensitive) + if echo "$VERSION" | grep -qi "rc"; then + echo "is-rc=true" >> $GITHUB_OUTPUT + echo "Release candidate detected - PECL installation test will be skipped" + else + echo "is-rc=false" >> $GITHUB_OUTPUT + echo "✓ Stable version detected - PECL installation test will run" + fi + - name: Setup PHP + if: steps.package-info.outputs.is-rc != 'true' uses: shivammathur/setup-php@v2 with: php-version: ${{ inputs.php-version }} @@ -103,6 +114,7 @@ runs: tools: none - name: Install system dependencies + if: steps.package-info.outputs.is-rc != 'true' shell: bash env: PHP_VER: ${{ inputs.php-version }} @@ -124,6 +136,7 @@ runs: libprotobuf-c1 - name: Install shared dependencies + if: steps.package-info.outputs.is-rc != 'true' uses: ./.github/workflows/install-shared-dependencies with: os: ubuntu @@ -132,6 +145,7 @@ runs: github-token: ${{ inputs.github-token || github.token }} - name: Install cbindgen + if: steps.package-info.outputs.is-rc != 'true' shell: bash run: | if [ -f "$HOME/.cargo/bin/cbindgen" ]; then @@ -142,6 +156,7 @@ runs: echo "$HOME/.cargo/bin" >> $GITHUB_PATH - name: Setup sccache for cross-user Rust caching + if: steps.package-info.outputs.is-rc != 'true' shell: bash run: | echo "=== Setting up sccache for cross-user Rust compilation caching ===" @@ -167,6 +182,7 @@ runs: echo "sccache setup complete" - name: Setup Cargo cache for root user + if: steps.package-info.outputs.is-rc != 'true' shell: bash run: | echo "=== Setting up Cargo cache for root user ===" @@ -205,6 +221,7 @@ runs: echo "Shared compilation cache setup complete" - name: Test PECL installation + if: steps.package-info.outputs.is-rc != 'true' shell: bash run: | echo "=== Testing PECL-style installation ===" @@ -344,6 +361,7 @@ runs: fi - name: Verify PECL installation + if: steps.package-info.outputs.is-rc != 'true' shell: bash run: | echo "=== Checking PHP extension directory ===" @@ -363,6 +381,7 @@ runs: php -d extension=valkey_glide -r "if (extension_loaded('valkey_glide')) { echo 'SUCCESS: Extension loaded and functional!'; } else { echo 'ERROR: Extension not functional'; }" - name: Install PHP dependencies + if: steps.package-info.outputs.is-rc != 'true' shell: bash run: | echo "=== Installing PHP dependencies ===" @@ -370,6 +389,7 @@ runs: echo "Composer install completed" - name: Run PHP Extension Tests + if: steps.package-info.outputs.is-rc != 'true' uses: ./.github/workflows/run-php-tests with: extension-path: valkey_glide diff --git a/.github/workflows/validate-version/action.yml b/.github/workflows/validate-version/action.yml index 93ef94bd..9490d9f9 100644 --- a/.github/workflows/validate-version/action.yml +++ b/.github/workflows/validate-version/action.yml @@ -85,6 +85,13 @@ runs: echo "" echo "=== Validating package.xml versions ===" + # Skip validation for release candidate versions + if [[ "$EXPECTED_VERSION" == *"rc"* ]]; then + echo "SKIPPED: Version contains 'rc' (release candidate) - package.xml validation skipped" + echo "Release candidate versions are not published to PECL" + exit 0 + fi + # Extract release version from package.xml (first occurrence only - main version, not changelog) RELEASE_VERSION=$(grep -o '[^<]*' package.xml | head -1 | sed 's/<[^>]*>//g') echo "Release version in package.xml: $RELEASE_VERSION" diff --git a/CHANGELOG.md b/CHANGELOG.md index 69de5e90..2ef21610 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,28 @@ # Changelog +## 1.0.0 + +### Changes (1.0.0) + +* PHP: Fix mac development instructions ([#96](https://github.com/valkey-io/valkey-glide-php/pull/96)) +* PHP: chore: bump valkey-glide submodule for root_certs support ([#99](https://github.com/valkey-io/valkey-glide-php/pull/99)) +* PHP: ci: Add release automation workflows and version management ([#94](https://github.com/valkey-io/valkey-glide-php/pull/94)) +* PHP: (dev): Update and improve linting infrastructure ([#104](https://github.com/valkey-io/valkey-glide-php/pull/104)) +* PHP: (ci): test-modules job queuing indefinitely ([#106](https://github.com/valkey-io/valkey-glide-php/pull/106)) +* PHP: (feat): Add TLS support for secure connections ([#100](https://github.com/valkey-io/valkey-glide-php/pull/100)) +* PHP: feat: add markdown linting support for developers ([#110](https://github.com/valkey-io/valkey-glide-php/pull/110)) +* PHP: perf(php): optimize struct member ordering to reduce padding ([#111](https://github.com/valkey-io/valkey-glide-php/pull/111)) +* PHP: Add script and function commands ([#97](https://github.com/valkey-io/valkey-glide-php/pull/97)) +* PHP: Pub/Sub Implementation ([#121](https://github.com/valkey-io/valkey-glide-php/pull/121)) +* PHP: Remove ValkeyGlideClusterException ([#127](https://github.com/valkey-io/valkey-glide-php/pull/127)) +* PHP: Add aliases to PHPRedis-compatible class names ([#126](https://github.com/valkey-io/valkey-glide-php/pull/126)) +* PHP: Add connect method for ValkeyGlide client ([#131](https://github.com/valkey-io/valkey-glide-php/pull/131)) +* PHP: Add benchmarks ([#124](https://github.com/valkey-io/valkey-glide-php/pull/124)) +* PHP: Fix validation check for rc builds on PECL Package ([#135](https://github.com/valkey-io/valkey-glide-php/pull/135)) + ## 0.10.0 -### Changes +### Changes (0.10.0) * PHP: Implement TLS support for PHP client ([#2983](https://github.com/valkey-io/valkey-glide/pull/2983)) * PHP: Add refresh topology configuration diff --git a/README.md b/README.md index ec5c1f41..bb596412 100644 --- a/README.md +++ b/README.md @@ -268,8 +268,8 @@ For easier migration from PHPRedis, you can use PHPRedis-compatible class names: **Standalone:** ```php -// Load the PHPRedis compatibility aliases -require_once 'vendor/valkey-io/valkey-glide-php/phpredis_aliases.php'; +// Register PHPRedis compatibility aliases +ValkeyGlide::registerPHPRedisAliases(); // Now you can use Redis instead of ValkeyGlide $client = new Redis(); @@ -291,8 +291,8 @@ $client->close(); **Cluster:** ```php -// Load the PHPRedis compatibility aliases -require_once 'vendor/valkey-io/valkey-glide-php/phpredis_aliases.php'; +// Register PHPRedis compatibility aliases +ValkeyGlide::registerPHPRedisAliases(); // Now you can use RedisCluster instead of ValkeyGlideCluster $cluster = new RedisCluster( diff --git a/benchmarks/README.md b/benchmarks/README.md index 77a7ade7..98ab9ab6 100644 --- a/benchmarks/README.md +++ b/benchmarks/README.md @@ -33,31 +33,37 @@ php run.php ### Examples **Standalone server:** + ```bash php run.php --host=localhost --port=6379 ``` **Cluster mode:** + ```bash php run.php --host=localhost --port=7001 --clusterModeEnabled ``` **With TLS:** + ```bash php run.php --host=localhost --port=6379 --tls ``` **Custom data size and iterations:** + ```bash php run.php --dataSize=1000 --iterations=100000,1000000 ``` **Only test Valkey GLIDE:** + ```bash php run.php --clients=glide ``` **Quick test (low iterations):** + ```bash php run.php --iterations=100000 ``` @@ -65,6 +71,7 @@ php run.php --iterations=100000 ## Benchmark Methodology The benchmark tests three operations with weighted probabilities: + - **GET (existing key)**: 64% - Retrieve keys that exist in the database - **GET (non-existing key)**: 16% - Query keys that don't exist (guaranteed cache misses) - **SET**: 20% - Write operations @@ -74,6 +81,7 @@ The database is pre-populated with 3 million keys before benchmarking to ensure ### Metrics Collected For each operation type: + - P50, P90, P99 latency (milliseconds) - Average latency (milliseconds) - Standard deviation (milliseconds) @@ -111,11 +119,8 @@ Results are saved as JSON with the following structure: ] ``` -**Note:** The JSON output format is standardized across all GLIDE language implementations (PHP, Python, Node.js, Rust, Go, Java) to enable cross-language performance comparisons. Fields like `num_of_tasks` and `client_count` are maintained for consistency even though PHP always uses single-process execution. - ## Current Limitations - **Single-process only**: Multi-process concurrency is not supported due to ValkeyGlide's Tokio runtime incompatibility with `pcntl_fork()`. The benchmark runs sequentially, measuring per-operation latency rather than true concurrent throughput. - **No connection pooling**: Each benchmark run uses a single client connection. - **phpredis comparison**: Requires phpredis extension to be installed separately. - diff --git a/benchmarks/run.php b/benchmarks/run.php index 9fe51a3d..3baca5e3 100644 --- a/benchmarks/run.php +++ b/benchmarks/run.php @@ -4,8 +4,18 @@ * Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 */ +declare(strict_types=1); + +namespace ValkeyGlide\Benchmarks; + +// phpcs:disable PSR1.Files.SideEffects require_once __DIR__ . '/utils.php'; +use ValkeyGlide; +use ValkeyGlideCluster; +use Redis; +use RedisCluster; + // Progress reporting constants const PROGRESS_REPORT_INTERVAL = 100_000; // Report progress every N operations diff --git a/benchmarks/utils.php b/benchmarks/utils.php index 9a9944f4..d25296ef 100644 --- a/benchmarks/utils.php +++ b/benchmarks/utils.php @@ -4,6 +4,10 @@ * Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 */ +declare(strict_types=1); + +namespace ValkeyGlide\Benchmarks; + const DEFAULT_PORT = 6379; const DEFAULT_HOST = 'localhost'; const PROB_GET_EXISTING = 0.64; diff --git a/common.h b/common.h index 9e1d4ea3..539473ad 100644 --- a/common.h +++ b/common.h @@ -10,7 +10,7 @@ #include "include/glide_bindings.h" /* ValkeyGlidePHP version */ -#define VALKEY_GLIDE_PHP_VERSION "0.10.0" +#define VALKEY_GLIDE_PHP_VERSION "1.0.0" #define VALKEY_GLIDE_PHP_GET_OBJECT(class_entry, o) \ (class_entry*) ((char*) o - XtOffsetOf(class_entry, std)) diff --git a/package.xml b/package.xml index e63a3107..21979135 100644 --- a/package.xml +++ b/package.xml @@ -12,19 +12,19 @@ Note: After installation, add "extension=valkey_glide" to your php.ini file.noreply@valkey.io yes - 2025-11-27 + 2025-01-26 - 0.10.0 - 0.10.0 + 1.0.0 + 1.0.0 - beta - beta + stable + stable Apache-2.0 -Release 0.10.0 of Valkey GLIDE PHP extension. +Release 1.0.0 of Valkey GLIDE PHP extension. New Features: - OpenTelemetry support for observability @@ -93,7 +93,6 @@ Requirements: - @@ -142,13 +141,20 @@ Requirements: Apache-2.0 -Release 0.10.0 with new features: -- OpenTelemetry support for observability -- Logging capabilities -- IAM authentication support for ElastiCache and MemoryDB -- Refresh topology configuration -- Multi-Database Support for Cluster Mode (Valkey 9.0+) -- Password API updates +Release 1.0.0 with new features: +- Fix mac development instructions +- bump valkey-glide submodule for root_certs support +- Add release automation workflows and version management +- Update and improve linting infrastructure +- test-modules job queuing indefinitely +- Add TLS support for secure connections +- add markdown linting support for developers +- perf: optimize struct member ordering to reduce padding +- Add script and function commands +- Pub/Sub Implementation +- Add aliases to PHPRedis-compatible class names +- Add connect method for ValkeyGlide client +- Add benchmarks diff --git a/phpredis_aliases.php b/phpredis_aliases.php deleted file mode 100644 index ac76df68..00000000 --- a/phpredis_aliases.php +++ /dev/null @@ -1,44 +0,0 @@ -assertTrue(class_exists('Redis'), 'Redis class alias should exist'); $this->assertTrue(class_exists('RedisException'), 'RedisException class alias should exist'); @@ -378,7 +378,7 @@ public function testRedisClusterAliasConnection() return; } - require_once __DIR__ . '/../phpredis_aliases.php'; + ValkeyGlide::registerPHPRedisAliases(); $this->assertTrue(class_exists('RedisCluster'), 'RedisCluster class alias should exist'); $this->assertTrue(class_exists('RedisException'), 'RedisException class alias should exist'); diff --git a/tests/ValkeyGlideClusterTest.php b/tests/ValkeyGlideClusterTest.php index be9d845b..ee6d6f47 100644 --- a/tests/ValkeyGlideClusterTest.php +++ b/tests/ValkeyGlideClusterTest.php @@ -1500,7 +1500,7 @@ public function testPHPRedisClusterAlias() return; } - require_once __DIR__ . "/../phpredis_aliases.php"; + ValkeyGlide::registerPHPRedisAliases(); $this->assertTrue(class_exists('RedisCluster'), 'RedisCluster class alias should exist'); diff --git a/tests/ValkeyGlideTest.php b/tests/ValkeyGlideTest.php index 5b09f748..624d732a 100644 --- a/tests/ValkeyGlideTest.php +++ b/tests/ValkeyGlideTest.php @@ -8083,7 +8083,7 @@ public function testPHPRedisAliases() return; } - require_once __DIR__ . "/../phpredis_aliases.php"; + ValkeyGlide::registerPHPRedisAliases(); $this->assertTrue(class_exists('Redis'), 'Redis class alias should exist'); $this->assertTrue(class_exists('RedisCluster'), 'RedisCluster class alias should exist'); diff --git a/valkey_glide.c b/valkey_glide.c index 097c2e83..5d75fc6a 100644 --- a/valkey_glide.c +++ b/valkey_glide.c @@ -574,6 +574,71 @@ PHP_METHOD(ValkeyGlide, __construct) { } /* }}} */ +/* {{{ Register PHPRedis compatibility aliases */ +PHP_METHOD(ValkeyGlide, registerPHPRedisAliases) { + ZEND_PARSE_PARAMETERS_START(0, 0) + ZEND_PARSE_PARAMETERS_END_EX(RETURN_THROWS()); + + // Check PHP version (requires 8.3+) + if (PHP_VERSION_ID < 80300) { + php_error_docref( + NULL, + E_WARNING, + "PHPRedis compatibility aliases require PHP 8.3 or higher. Current version: %s", + PHP_VERSION); + RETURN_FALSE; + } + + // Check if Redis class already exists + if (zend_hash_str_exists(CG(class_table), "redis", sizeof("redis") - 1)) { + php_error_docref( + NULL, + E_WARNING, + "Redis class already exists. Cannot create PHPRedis compatibility aliases. " + "PHPRedis may already be installed."); + RETURN_FALSE; + } + + // Get the ValkeyGlide class entry + zend_class_entry* valkey_glide_ce = Z_OBJCE_P(ZEND_THIS); + if (!valkey_glide_ce) { + valkey_glide_ce = + zend_hash_str_find_ptr(CG(class_table), "valkeyglide", sizeof("valkeyglide") - 1); + } + + // Get ValkeyGlideCluster class entry + zend_class_entry* valkey_glide_cluster_ce = zend_hash_str_find_ptr( + CG(class_table), "valkeyglidecluster", sizeof("valkeyglidecluster") - 1); + + // Get ValkeyGlideException class entry + zend_class_entry* valkey_glide_exception_ce = zend_hash_str_find_ptr( + CG(class_table), "valkeyglideexception", sizeof("valkeyglideexception") - 1); + + if (!valkey_glide_ce || !valkey_glide_cluster_ce || !valkey_glide_exception_ce) { + php_error_docref(NULL, E_WARNING, "Failed to find Valkey GLIDE classes"); + RETURN_FALSE; + } + + // Register class aliases + if (zend_register_class_alias_ex("Redis", sizeof("Redis") - 1, valkey_glide_ce, 0) != SUCCESS) { + RETURN_FALSE; + } + + if (zend_register_class_alias_ex( + "RedisCluster", sizeof("RedisCluster") - 1, valkey_glide_cluster_ce, 0) != SUCCESS) { + RETURN_FALSE; + } + + if (zend_register_class_alias_ex( + "RedisException", sizeof("RedisException") - 1, valkey_glide_exception_ce, 0) != + SUCCESS) { + RETURN_FALSE; + } + + RETURN_TRUE; +} +/* }}} */ + /* {{{ Creates and establishes connection to Valkey server. Validates parameters, builds configuration, and initializes the client connection. Returns SUCCESS on successful connection, FAILURE otherwise. */ diff --git a/valkey_glide.stub.php b/valkey_glide.stub.php index e3a6d682..f77447c6 100644 --- a/valkey_glide.stub.php +++ b/valkey_glide.stub.php @@ -291,6 +291,24 @@ class ValkeyGlide */ public const PIPELINE = UNKNOWN; + /** + * Register PHPRedis compatibility aliases. + * + * Creates class aliases to make Valkey GLIDE compatible with PHPRedis: + * - Redis -> ValkeyGlide + * - RedisCluster -> ValkeyGlideCluster + * - RedisException -> ValkeyGlideException + * + * @return bool True on success, false if aliases already exist + * + * @example + * ValkeyGlide::registerPHPRedisAliases(); + * $redis = new Redis(); // Now works! + */ + public static function registerPHPRedisAliases(): bool + { + } + /** * Create a new ValkeyGlide instance. *