|
| 1 | +# Output |
| 2 | + |
| 3 | +`ext-php-rs` provides several macros and functions for writing output to PHP's |
| 4 | +stdout and stderr streams. These are essential when your extension needs to |
| 5 | +produce output that integrates with PHP's output buffering system. |
| 6 | + |
| 7 | +## Text Output |
| 8 | + |
| 9 | +For regular text output (strings without NUL bytes), use the `php_print!` and |
| 10 | +`php_println!` macros. These work similarly to Rust's `print!` and `println!` |
| 11 | +macros. |
| 12 | + |
| 13 | +### `php_print!` |
| 14 | + |
| 15 | +Prints to PHP's standard output without a trailing newline. |
| 16 | + |
| 17 | +```rust,ignore |
| 18 | +use ext_php_rs::prelude::*; |
| 19 | +
|
| 20 | +#[php_function] |
| 21 | +pub fn greet(name: &str) { |
| 22 | + php_print!("Hello, {}!", name); |
| 23 | +} |
| 24 | +``` |
| 25 | + |
| 26 | +### `php_println!` |
| 27 | + |
| 28 | +Prints to PHP's standard output with a trailing newline. |
| 29 | + |
| 30 | +```rust,ignore |
| 31 | +use ext_php_rs::prelude::*; |
| 32 | +
|
| 33 | +#[php_function] |
| 34 | +pub fn greet(name: &str) { |
| 35 | + php_println!("Hello, {}!", name); |
| 36 | +} |
| 37 | +``` |
| 38 | + |
| 39 | +> **Note:** `php_print!` and `php_println!` will panic if the string contains |
| 40 | +> NUL bytes (`\0`). For binary-safe output, use `php_output!` or `php_write!`. |
| 41 | +
|
| 42 | +## Binary-Safe Output |
| 43 | + |
| 44 | +When working with binary data that may contain NUL bytes, use the binary-safe |
| 45 | +output functions. These are essential for outputting raw bytes, binary file |
| 46 | +contents, or any data that might contain `\0` characters. |
| 47 | + |
| 48 | +### `php_output!` |
| 49 | + |
| 50 | +Writes binary data to PHP's output stream. This macro is **both binary-safe AND |
| 51 | +respects PHP's output buffering** (`ob_start()`). This is usually what you want |
| 52 | +for binary output. |
| 53 | + |
| 54 | +```rust,ignore |
| 55 | +use ext_php_rs::prelude::*; |
| 56 | +
|
| 57 | +#[php_function] |
| 58 | +pub fn output_binary() -> i64 { |
| 59 | + // Write binary data with NUL bytes - will be captured by ob_start() |
| 60 | + let bytes_written = php_output!(b"Hello\x00World"); |
| 61 | + bytes_written as i64 |
| 62 | +} |
| 63 | +``` |
| 64 | + |
| 65 | +### `php_write!` |
| 66 | + |
| 67 | +Writes binary data directly to the SAPI output, **bypassing PHP's output |
| 68 | +buffering**. This macro is binary-safe but output will NOT be captured by |
| 69 | +`ob_start()`. The "ub" in `ub_write` stands for "unbuffered". |
| 70 | + |
| 71 | +```rust,ignore |
| 72 | +use ext_php_rs::prelude::*; |
| 73 | +
|
| 74 | +#[php_function] |
| 75 | +pub fn output_binary() -> i64 { |
| 76 | + // Write a byte literal |
| 77 | + php_write!(b"Hello World").expect("write failed"); |
| 78 | +
|
| 79 | + // Write binary data with NUL bytes (would panic with php_print!) |
| 80 | + let bytes_written = php_write!(b"Hello\x00World").expect("write failed"); |
| 81 | +
|
| 82 | + // Write a byte slice |
| 83 | + let data: &[u8] = &[0x48, 0x65, 0x6c, 0x6c, 0x6f]; // "Hello" |
| 84 | + php_write!(data).expect("write failed"); |
| 85 | +
|
| 86 | + bytes_written as i64 |
| 87 | +} |
| 88 | +``` |
| 89 | + |
| 90 | +The macro returns a `Result<usize>` with the number of bytes written, which can |
| 91 | +be useful for verifying that all data was output successfully. The error case |
| 92 | +occurs when the SAPI's `ub_write` function is not available. |
| 93 | + |
| 94 | +## Function API |
| 95 | + |
| 96 | +In addition to macros, you can use the underlying functions directly: |
| 97 | + |
| 98 | +| Function | Binary-Safe | Output Buffering | Description | |
| 99 | +|----------|-------------|------------------|-------------| |
| 100 | +| `zend::printf()` | No | Yes | Printf-style output (used by `php_print!`) | |
| 101 | +| `zend::output_write()` | Yes | Yes | Binary-safe buffered output | |
| 102 | +| `zend::write()` | Yes | No | Binary-safe unbuffered output | |
| 103 | + |
| 104 | +### Example using functions directly |
| 105 | + |
| 106 | +```rust,ignore |
| 107 | +use ext_php_rs::zend::output_write; |
| 108 | +
|
| 109 | +fn output_data(data: &[u8]) { |
| 110 | + let bytes_written = output_write(data); |
| 111 | + if bytes_written != data.len() { |
| 112 | + eprintln!("Warning: incomplete write"); |
| 113 | + } |
| 114 | +} |
| 115 | +``` |
| 116 | + |
| 117 | +## Comparison |
| 118 | + |
| 119 | +| Macro | Binary-Safe | Output Buffering | Supports Formatting | |
| 120 | +|-------|-------------|------------------|---------------------| |
| 121 | +| `php_print!` | No | Yes | Yes | |
| 122 | +| `php_println!` | No | Yes | Yes | |
| 123 | +| `php_output!` | Yes | Yes | No | |
| 124 | +| `php_write!` | Yes | No | No | |
| 125 | + |
| 126 | +## When to Use Each |
| 127 | + |
| 128 | +- **`php_print!` / `php_println!`**: Use for text output with format strings, |
| 129 | + similar to Rust's `print!` and `println!`. Best for human-readable messages. |
| 130 | + |
| 131 | +- **`php_output!`**: Use for binary data that needs to work with PHP's output |
| 132 | + buffering. This is the recommended choice for most binary output needs. |
| 133 | + |
| 134 | +- **`php_write!`**: Use when you need direct, unbuffered output that bypasses |
| 135 | + PHP's output layer. Useful for low-level SAPI interaction or when output |
| 136 | + buffering must be avoided. |
0 commit comments