ext-php-rs 0.15.10

Bindings for the Zend API to build PHP extensions natively in Rust.
Documentation
# Module Globals

PHP extensions can declare per-module global state that is automatically managed
by the engine. In ZTS (thread-safe) builds, PHP's TSRM allocates a separate copy
of the globals for each thread. In non-ZTS builds, the globals are a plain
static variable.

ext-php-rs exposes this via `ModuleGlobals<T>` and the `ModuleGlobal` trait.

## Defining Globals

Create a struct that implements `Default` and `ModuleGlobal`:

```rust,ignore
use ext_php_rs::zend::{ModuleGlobal, ModuleGlobals};

#[derive(Default)]
struct MyGlobals {
    request_count: i64,
    max_depth: i32,
}

impl ModuleGlobal for MyGlobals {
    fn ginit(&mut self) {
        self.max_depth = 512;
    }
}
```

`Default::default()` initializes the struct, then `ginit()` runs for any
additional setup. In ZTS mode these callbacks fire once per thread; in non-ZTS
mode they fire once at module load.

If you don't need custom initialization, leave the trait impl empty:

```rust,ignore
# use ext_php_rs::zend::{ModuleGlobal, ModuleGlobals};
#[derive(Default)]
struct SimpleGlobals {
    counter: i64,
}

impl ModuleGlobal for SimpleGlobals {}
```

## Registering Globals

Declare a `static` and pass it to `ModuleBuilder::globals()`:

```rust,ignore
use ext_php_rs::prelude::*;
use ext_php_rs::zend::{ModuleGlobal, ModuleGlobals};

# #[derive(Default)]
# struct MyGlobals { request_count: i64, max_depth: i32 }
# impl ModuleGlobal for MyGlobals {}
#
static MY_GLOBALS: ModuleGlobals<MyGlobals> = ModuleGlobals::new();

#[php_module]
pub fn module(module: ModuleBuilder) -> ModuleBuilder {
    module.globals(&MY_GLOBALS)
}
```

Only one globals struct per module is supported (a PHP limitation).

## Accessing Globals

Use `get()` for shared access and `get_mut()` for mutable access:

```rust,ignore
use ext_php_rs::prelude::*;
use ext_php_rs::zend::{ModuleGlobal, ModuleGlobals};

# #[derive(Default)]
# struct MyGlobals { request_count: i64, max_depth: i32 }
# impl ModuleGlobal for MyGlobals {}
# static MY_GLOBALS: ModuleGlobals<MyGlobals> = ModuleGlobals::new();
#
#[php_function]
pub fn get_request_count() -> i64 {
    MY_GLOBALS.get().request_count
}

#[php_function]
pub fn increment_request_count() {
    unsafe { MY_GLOBALS.get_mut() }.request_count += 1;
}
```

`get()` is safe because PHP runs one request per thread at a time. `get_mut()`
is `unsafe` because the caller must ensure exclusive access (which is guaranteed
within a single `#[php_function]` handler, but not from background Rust threads).

## Advanced: Raw Pointer Access

For power users who need direct pointer access (e.g., passing to C APIs or
building custom lock-free patterns), `as_ptr()` returns `*mut T`:

```rust,ignore
# use ext_php_rs::zend::{ModuleGlobal, ModuleGlobals};
# #[derive(Default)]
# struct MyGlobals { request_count: i64 }
# impl ModuleGlobal for MyGlobals {}
# static MY_GLOBALS: ModuleGlobals<MyGlobals> = ModuleGlobals::new();
let ptr: *mut MyGlobals = MY_GLOBALS.as_ptr();
```

## Cleanup

Implement `gshutdown()` if your globals hold external resources:

```rust,ignore
# use ext_php_rs::zend::ModuleGlobal;
# #[derive(Default)]
# struct MyGlobals { handle: Option<u64> }
impl ModuleGlobal for MyGlobals {
    fn gshutdown(&mut self) {
        self.handle.take();
    }
}
```

The struct is also dropped after `gshutdown()` returns, so standard `Drop`
implementations work as expected.