Skip to content

Commit e3f32b3

Browse files
committed
docs(superglobals): a guide chapter on Superglobals #499
1 parent b4d16f7 commit e3f32b3

File tree

2 files changed

+343
-0
lines changed

2 files changed

+343
-0
lines changed

guide/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
- [`Attributes`](./macros/php.md)
3737
- [Exceptions](./exceptions.md)
3838
- [INI Settings](./ini-settings.md)
39+
- [Superglobals](./superglobals.md)
3940

4041
# Advanced Topics
4142

guide/src/superglobals.md

Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
# Superglobals
2+
3+
PHP provides several superglobal arrays that are accessible from any scope. In
4+
ext-php-rs, you can access these superglobals using the `ProcessGlobals`,
5+
`SapiGlobals`, and `ExecutorGlobals` types.
6+
7+
> **Note for FrankenPHP users:** In FrankenPHP worker mode, you would need to
8+
> override `sapi_activate`/`sapi_deactivate` hooks to mimic
9+
> `php_rinit`/`php_rshutdown` behavior. However, superglobals are inaccessible
10+
> during `sapi_activate` and will cause crashes if accessed at that point.
11+
12+
## Accessing HTTP Superglobals
13+
14+
The `ProcessGlobals` type provides access to the common HTTP superglobals:
15+
16+
| Method | PHP Equivalent |
17+
|-----------------------|----------------|
18+
| `http_get_vars()` | `$_GET` |
19+
| `http_post_vars()` | `$_POST` |
20+
| `http_cookie_vars()` | `$_COOKIE` |
21+
| `http_server_vars()` | `$_SERVER` |
22+
| `http_env_vars()` | `$_ENV` |
23+
| `http_files_vars()` | `$_FILES` |
24+
| `http_request_vars()` | `$_REQUEST` |
25+
26+
### Basic Example
27+
28+
```rust,no_run
29+
# #![cfg_attr(windows, feature(abi_vectorcall))]
30+
# extern crate ext_php_rs;
31+
use ext_php_rs::prelude::*;
32+
use ext_php_rs::zend::ProcessGlobals;
33+
34+
#[php_function]
35+
pub fn get_cookie(name: String) -> Option<String> {
36+
ProcessGlobals::get()
37+
.http_cookie_vars()
38+
.get(name.as_str())
39+
.and_then(|zval| zval.string())
40+
}
41+
42+
#[php_function]
43+
pub fn get_query_param(name: String) -> Option<String> {
44+
ProcessGlobals::get()
45+
.http_get_vars()
46+
.get(name.as_str())
47+
.and_then(|zval| zval.string())
48+
}
49+
50+
#[php_function]
51+
pub fn get_post_param(name: String) -> Option<String> {
52+
ProcessGlobals::get()
53+
.http_post_vars()
54+
.get(name.as_str())
55+
.and_then(|zval| zval.string())
56+
}
57+
# fn main() {}
58+
```
59+
60+
### Accessing `$_SERVER`
61+
62+
The `$_SERVER` superglobal is lazy-initialized in PHP, so `http_server_vars()`
63+
returns an `Option`:
64+
65+
```rust,no_run
66+
# #![cfg_attr(windows, feature(abi_vectorcall))]
67+
# extern crate ext_php_rs;
68+
use ext_php_rs::prelude::*;
69+
use ext_php_rs::zend::ProcessGlobals;
70+
71+
#[php_function]
72+
pub fn get_request_method() -> Option<String> {
73+
ProcessGlobals::get()
74+
.http_server_vars()?
75+
.get("REQUEST_METHOD")
76+
.and_then(|zval| zval.string())
77+
}
78+
79+
#[php_function]
80+
pub fn get_remote_addr() -> Option<String> {
81+
ProcessGlobals::get()
82+
.http_server_vars()?
83+
.get("REMOTE_ADDR")
84+
.and_then(|zval| zval.string())
85+
}
86+
87+
#[php_function]
88+
pub fn get_user_agent() -> Option<String> {
89+
ProcessGlobals::get()
90+
.http_server_vars()?
91+
.get("HTTP_USER_AGENT")
92+
.and_then(|zval| zval.string())
93+
}
94+
# fn main() {}
95+
```
96+
97+
### Working with `$_FILES`
98+
99+
```rust,no_run
100+
# #![cfg_attr(windows, feature(abi_vectorcall))]
101+
# extern crate ext_php_rs;
102+
use ext_php_rs::prelude::*;
103+
use ext_php_rs::zend::ProcessGlobals;
104+
105+
#[php_function]
106+
pub fn get_uploaded_file_name(field: String) -> Option<String> {
107+
let globals = ProcessGlobals::get();
108+
let files = globals.http_files_vars();
109+
110+
// $_FILES structure: $_FILES['field']['name'], ['tmp_name'], ['size'], etc.
111+
files
112+
.get(field.as_str())?
113+
.array()?
114+
.get("name")
115+
.and_then(|zval| zval.string())
116+
}
117+
118+
#[php_function]
119+
pub fn get_uploaded_file_tmp_path(field: String) -> Option<String> {
120+
let globals = ProcessGlobals::get();
121+
let files = globals.http_files_vars();
122+
123+
files
124+
.get(field.as_str())?
125+
.array()?
126+
.get("tmp_name")
127+
.and_then(|zval| zval.string())
128+
}
129+
# fn main() {}
130+
```
131+
132+
### Returning Superglobals to PHP
133+
134+
You can return copies of superglobals back to PHP:
135+
136+
```rust,no_run
137+
# #![cfg_attr(windows, feature(abi_vectorcall))]
138+
# extern crate ext_php_rs;
139+
use ext_php_rs::prelude::*;
140+
use ext_php_rs::boxed::ZBox;
141+
use ext_php_rs::types::ZendHashTable;
142+
use ext_php_rs::zend::ProcessGlobals;
143+
144+
#[php_function]
145+
pub fn get_all_cookies() -> ZBox<ZendHashTable> {
146+
ProcessGlobals::get().http_cookie_vars().to_owned()
147+
}
148+
149+
#[php_function]
150+
pub fn get_all_get_params() -> ZBox<ZendHashTable> {
151+
ProcessGlobals::get().http_get_vars().to_owned()
152+
}
153+
154+
#[php_function]
155+
pub fn get_server_vars() -> Option<ZBox<ZendHashTable>> {
156+
Some(ProcessGlobals::get().http_server_vars()?.to_owned())
157+
}
158+
# fn main() {}
159+
```
160+
161+
## SAPI Request Information
162+
163+
For lower-level request information, use `SapiGlobals`:
164+
165+
```rust,no_run
166+
# #![cfg_attr(windows, feature(abi_vectorcall))]
167+
# extern crate ext_php_rs;
168+
use ext_php_rs::prelude::*;
169+
use ext_php_rs::zend::SapiGlobals;
170+
171+
#[php_function]
172+
pub fn get_request_info() -> Vec<String> {
173+
let globals = SapiGlobals::get();
174+
let request_info = globals.request_info();
175+
176+
let mut info = Vec::new();
177+
178+
if let Some(method) = request_info.request_method() {
179+
info.push(format!("Method: {}", method));
180+
}
181+
if let Some(uri) = request_info.request_uri() {
182+
info.push(format!("URI: {}", uri));
183+
}
184+
if let Some(query) = request_info.query_string() {
185+
info.push(format!("Query: {}", query));
186+
}
187+
if let Some(content_type) = request_info.content_type() {
188+
info.push(format!("Content-Type: {}", content_type));
189+
}
190+
info.push(format!("Content-Length: {}", request_info.content_length()));
191+
192+
info
193+
}
194+
# fn main() {}
195+
```
196+
197+
### Available Request Info Methods
198+
199+
| Method | Description |
200+
|---------------------|-------------------------------|
201+
| `request_method()` | HTTP method (GET, POST, etc.) |
202+
| `request_uri()` | Request URI |
203+
| `query_string()` | Query string |
204+
| `cookie_data()` | Raw cookie data |
205+
| `content_type()` | Content-Type header |
206+
| `content_length()` | Content-Length value |
207+
| `path_translated()` | Translated filesystem path |
208+
| `auth_user()` | HTTP Basic auth username |
209+
| `auth_password()` | HTTP Basic auth password |
210+
211+
## Accessing Constants
212+
213+
Use `ExecutorGlobals` to access PHP constants:
214+
215+
```rust,no_run
216+
# #![cfg_attr(windows, feature(abi_vectorcall))]
217+
# extern crate ext_php_rs;
218+
use ext_php_rs::prelude::*;
219+
use ext_php_rs::zend::ExecutorGlobals;
220+
221+
#[php_function]
222+
pub fn get_php_version_constant() -> Option<String> {
223+
let globals = ExecutorGlobals::get();
224+
globals
225+
.constants()?
226+
.get("PHP_VERSION")
227+
.and_then(|zval| zval.string())
228+
}
229+
230+
#[php_function]
231+
pub fn constant_exists(name: String) -> bool {
232+
let globals = ExecutorGlobals::get();
233+
globals
234+
.constants()
235+
.is_some_and(|c| c.get(name.as_str()).is_some())
236+
}
237+
# fn main() {}
238+
```
239+
240+
## Accessing INI Values
241+
242+
```rust,no_run
243+
# #![cfg_attr(windows, feature(abi_vectorcall))]
244+
# extern crate ext_php_rs;
245+
use ext_php_rs::prelude::*;
246+
use ext_php_rs::zend::ExecutorGlobals;
247+
248+
#[php_function]
249+
pub fn get_memory_limit() -> Option<String> {
250+
ExecutorGlobals::get()
251+
.ini_values()
252+
.get("memory_limit")
253+
.cloned()
254+
.flatten()
255+
}
256+
257+
#[php_function]
258+
pub fn get_all_ini_values() -> Vec<(String, String)> {
259+
ExecutorGlobals::get()
260+
.ini_values()
261+
.iter()
262+
.filter_map(|(k, v)| {
263+
v.as_ref().map(|val| (k.clone(), val.clone()))
264+
})
265+
.collect()
266+
}
267+
# fn main() {}
268+
```
269+
270+
## Thread Safety
271+
272+
All global access methods use guard types that provide thread-safe access:
273+
274+
- `ProcessGlobals::get()` returns a `GlobalReadGuard<ProcessGlobals>`
275+
- `ExecutorGlobals::get()` returns a `GlobalReadGuard<ExecutorGlobals>`
276+
- `SapiGlobals::get()` returns a `GlobalReadGuard<SapiGlobals>`
277+
278+
The guard is automatically released when it goes out of scope. For mutable
279+
access (rarely needed), use `get_mut()`:
280+
281+
```rust,no_run
282+
# #![cfg_attr(windows, feature(abi_vectorcall))]
283+
# extern crate ext_php_rs;
284+
use ext_php_rs::zend::ExecutorGlobals;
285+
286+
fn example() {
287+
// Read-only access (most common)
288+
let globals = ExecutorGlobals::get();
289+
// ... use globals ...
290+
// Guard released when `globals` goes out of scope
291+
292+
// Mutable access (rarely needed)
293+
let mut globals = ExecutorGlobals::get_mut();
294+
// ... modify globals ...
295+
}
296+
# fn main() {}
297+
```
298+
299+
## PHP Example
300+
301+
```php
302+
<?php
303+
304+
// Assuming you've registered the functions above
305+
306+
// Access cookies
307+
$session_id = get_cookie('session_id');
308+
309+
// Access query parameters
310+
$page = get_query_param('page') ?? '1';
311+
312+
// Get request method
313+
$method = get_request_method(); // "GET", "POST", etc.
314+
315+
// Get all cookies as array
316+
$all_cookies = get_all_cookies();
317+
print_r($all_cookies);
318+
319+
// Get request info
320+
$info = get_request_info();
321+
print_r($info);
322+
323+
// Access constants
324+
$php_version = get_php_version_constant();
325+
echo "PHP Version: $php_version\n";
326+
327+
// Check if constant exists
328+
if (constant_exists('MY_CUSTOM_CONSTANT')) {
329+
echo "Constant exists!\n";
330+
}
331+
```
332+
333+
## Summary
334+
335+
| Type | Use Case |
336+
|-------------------|---------------------------------------------------------|
337+
| `ProcessGlobals` | HTTP superglobals (`$_GET`, `$_POST`, `$_COOKIE`, etc.) |
338+
| `SapiGlobals` | Low-level request info, headers |
339+
| `ExecutorGlobals` | Constants, INI values, function/class tables |
340+
341+
All types are accessed via `::get()` for read access or `::get_mut()` for write
342+
access, and provide thread-safe access through guard types.

0 commit comments

Comments
 (0)