README.md

September 6, 2026 · View on GitHub

Swoole Logo

Twitter Discord Unit Tests License Latest Release Codecov

C++ wrapper for Zend API

简体中文

Requirements

  • PHP 8.4 or later
  • Linux/macOS/Windows
  • GCC 9 or later (with C++17 support)
  • Composer

Installation

Build libphpx.so

# Standard build (Release mode)
cmake .
make -j 4
sudo make install
sudo ldconfig

Debug Mode (for troubleshooting)

# Clean previous builds
cmake --build . --target clean

# Configure Debug mode (includes debug symbols and runtime checks)
cmake -DCMAKE_BUILD_TYPE=Debug .

# Compile
make -j 4
sudo make install
sudo ldconfig

Debug Mode Features:

  • ✅ Generates complete debug symbols
  • ✅ Disables compiler optimizations for easier debugging
  • ✅ Enables runtime error checking
  • ✅ More detailed compilation output

Quick Start

Create a New Extension Project

mkdir test
cd test
composer require swoole/phpx
vendor/bin/phpx init

Basic Usage Example

Here's a complete example demonstrating modern PHPX extension development:

#include "phpx_ext.h"

// Include auto-generated arginfo header (generated by gen_stub.php)
BEGIN_EXTERN_C()
#include "your_extension_arginfo.h"
END_EXTERN_C()

using namespace php;
using namespace std;

// Method implementation using PHPX_METHOD macro
PHPX_METHOD(MyClass, __construct) {
    // Initialize object properties
    _this.set("name", args[0].toString());
    _this.set("value", args[1].toInt());
    return nullptr;
}

PHPX_METHOD(MyClass, greet) {
    // Access object properties
    auto name = _this.get("name");
    auto value = _this.get("value");

    // Return formatted string
    return "Hello, " + name.toStdString() + "! Value: " + to_string(value.toInt());
}

PHPX_METHOD(MyClass, processData) {
    // Work with Array type
    Array input = args[0];
    Array result;

    // Iterate and transform
    for (auto &item : input) {
        result.append(item.value.toInt() * 2);
    }

    return result;
}

// Function implementation using PHPX_FUNCTION macro
PHPX_FUNCTION(my_extension_func) {
    // Variant - universal type container
    Variant str_var = "Hello PHPX";
    Variant int_var = 42;
    Variant float_var = 3.14159;

    // Array operations
    Array arr;
    arr.set("name", "PHPX");
    arr.set("version", 8.2);
    arr.set("features", Array{"C++17", "Type-safe", "Modern API"});

    // Object creation and method calls
    Object datetime = newObject("DateTime");
    auto formatted = datetime.call("format", {"Y-m-d H:i:s"});

    // Call PHP functions through the generic call API
    php::call("var_dump", {arr});
    php::call("print_r", {datetime});

    // File operations
    auto content = php::call("file_get_contents", {"/etc/hosts"});
    if (content.isString()) {
        echo("File length: ", content.length(), "\n");
    }

    // Array manipulation with references
    Array numbers{1, 2, 3, 4, 5};
    numbers.sort();
    numbers.appendValue(6);
    numbers.appendValue(7);
    numbers.appendValue(8);

    RETURN_STRING("PHPX Demo Completed!");
}

// Extension entry point
PHPX_EXTENSION() {
    Extension *ext = new Extension("my_extension", "1.0.0");

    // Register lifecycle callbacks
    ext->onStart = [ext]() noexcept {
        // Register constants
        ext->registerConstant("MY_EXT_VERSION", 10000);

        // Register class with methods
        Class *c = new Class("MyClass");
        c->addProperty("name", "", ZEND_ACC_PUBLIC);
        c->addProperty("value", 0, ZEND_ACC_PUBLIC);
        c->registerFunctions(class_MyClass_methods);  // From arginfo header
        ext->registerClass(c);

    };

    // Register the function table generated from the stub.
    ext->registerFunctions(ext_functions);

    // PHP info page configuration
    ext->info({"my_extension support", "enabled"},
              {
                  {"author", "Your Name"},
                  {"version", ext->version},
                  {"github", "https://github.com/your/repo"},
              });

    return ext;
}

Key Features:

  • PHPX_METHOD/PHPX_FUNCTION: Modern macros for cleaner code
  • Extension/Class API: Object-oriented extension registration
  • Lambda callbacks: Flexible lifecycle management with onStart, onShutdown, etc.
  • Type-safe wrappers: Variant, Array, Object, String classes
  • Generic calls: Invoke PHP functions and methods with php::call() and Object::call()
  • Auto-generated arginfo: Use gen_stub.php to generate type information

Generate ArgInfo & Function Entries

phpx init creates the CMake project, src/, include/, a PHPT smoke test, and README in the current Composer project. It also copies the matching gen_stub.php to build/ and run-tests.php to the project root from the PHP development package, without requiring phpize:

composer require swoole/phpx
vendor/bin/phpx init
vendor/bin/phpx build
sudo vendor/bin/phpx install
sudo vendor/bin/phpx enable

After building, phpx install, phpx enable, and phpx disable copy the module and update php.ini. init uses php-config from PATH; use phpx init --php-config=/path/to/php-config initially or phpx switch /path/to/php-config later to select another PHP installation.

Stub files belong in src/*.stub.php; generated *_arginfo.h files are written next to their stubs and remain private implementation files. phpx install publishes only C/C++ headers placed explicitly under include/, installing them to $(php-config --include-dir)/ext/<extension-name>/. Headers under src/ are never installed.

Build Your Extension

cd test
cmake .
make -j 4
make install

Load Your Extension

Edit php.ini and add:

extension=test.so

Test Your Extension

Create a test file test.php:

<?php
echo hello_world() . "\n";
?>

Run it:

php test.php

Expected output:

Hello, World!

Advanced Usage

1. Variant Type Usage

Variant is a universal type container that can hold any PHP value:

#include "phpx.h"

using namespace php;

// Create variants of different types
Variant str_var = "Hello PHPX";
Variant int_var = 42;
Variant float_var = 3.14159;
Variant bool_var = true;
Variant null_var;

// Type checking
if (str_var.isString()) {
    echo("String: ", str_var.toCString());
}

if (int_var.isInt()) {
    echo("Integer: ", int_var.toInt());
}

// Type conversion
auto str = int_var.toString();      // Convert to string
auto num = str_var.toInt();         // Convert to integer (0 if not numeric)

// Comparison
if (str_var.equals("Hello PHPX")) {
    echo("Match!");
}

// Serialization
Variant serialized = str_var.serialize();
Variant unserialized = serialized.unserialize();

2. Array Type Usage

Array provides a C++ wrapper for PHP arrays with rich functionality:

#include "phpx.h"

using namespace php;

// Create arrays
Array arr;
arr.set("name", "PHPX");
arr.set("version", 8.2);
arr.set("features", Array{"C++17", "Type-safe", "Modern API"});

// Initialize with list
Array numbers{1, 2, 3, 4, 5};
Array map{{"key1", "value1"}, {"key2", "value2"}};

// Access elements
auto name = arr.get("name");
auto first = numbers[0];

// Check existence
if (arr.exists("name")) {
    echo("Name exists");
}

// Iterate array
for (auto &item : arr) {
    echo(item.key, ": ", item.value, "\n");
}

// Array operations
arr.append("new_element");          // Add element
arr.del("name");                    // Remove element
auto count = arr.count();           // Get count
auto keys = arr.keys();             // Get all keys

// Nested arrays
Array nested;
nested.set("level1", Array{
    {"level2", Array{"deep_value"}}
});
auto deep = nested.item("level1").item("level2");

// Reference for modification
Array nums{5, 2, 8, 1, 9};
Reference ref = nums.toReference();
php::sort(ref);                     // Sort in place
php::array_push(ref, 10, 11);       // Push elements

3. Object Type Usage

Object wraps PHP objects and provides method calling capabilities:

#include "phpx.h"

using namespace php;

// Create object
Object datetime = newObject("DateTime");

// Call methods
auto formatted = datetime.call("format", {"Y-m-d H:i:s"});
echo("Current time: ", formatted.toCString());

// Set properties
Object stdclass = newObject("stdClass");
stdclass.set("name", "test");
stdclass.set("value", 42);

// Get properties
auto name = stdclass.get("name");
auto value = stdclass.get("value");

// Check property existence
if (stdclass.exists("name")) {
    echo("Property exists");
}

// Create object with constructor arguments
Object arrayObj = newObject("ArrayObject", {
    Array{1, 2, 3, 4, 5}
});

// Call method and get result
auto count = arrayObj.call("count");
echo("Count: ", count.toInt());

// Static method calls
    auto result = callStaticMethod("DateTime", "createFromFormat", {
    "Y-m-d", "2024-01-01"
});

4. Calling PHP Functions

PHP functions are invoked through the generic php::call() API. Frequently used, type-safe fast paths are available separately in php::fn through phpx_std.h.

#include "phpx.h"
#include "phpx_std.h"

using namespace php;

Array data{{"name", "PHPX"}, {"version", 8.2}};
auto json = php::call("json_encode", {data});
auto decoded = php::call("json_decode", {json, true});
php::call("var_dump", {decoded});

// Optimized standard-library wrappers
auto digest = php::fn::md5("hello");

5. Calling Built-in Classes

Use newObject(), Object::call(), and callStaticMethod() for PHP classes:

#include "phpx.h"

using namespace php;

Object redis = newObject("Redis");
redis.call("connect", {"127.0.0.1", 6379});
redis.call("set", {"name", "PHPX"});
auto name = redis.call("get", {"name"});

auto date = callStaticMethod("DateTime", "createFromFormat", {
    "Y-m-d", "2024-01-01"
});

Documentation

For more detailed documentation, please check:

Examples

Check out the examples directory for more comprehensive examples including:

  • Bloom filter implementation
  • Queue data structure
  • RocksDB integration
  • GTK application
  • And more!

Language

License

PHPX is open-sourced software licensed under the Apache License 2.0.