### Cargo-PHP Install Command Help Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/getting-started/cargo-php.md Displays help information for the `cargo-php install` command. Use this to understand the available options for installing a PHP extension. ```text $ cargo php install --help cargo-php-install Installs the extension in the current PHP installation. This copies the extension to the PHP installation and adds the extension to a PHP configuration file. Note that this uses the `php-config` executable installed alongside PHP to locate your `php.ini` file and extension directory. If you want to use a different `php-config`, the application will read the `PHP_CONFIG` variable (if it is set), and will use this as the path to the executable instead. USAGE: cargo-php install [OPTIONS] OPTIONS: --disable Installs the extension but doesn't enable the extension in the `php.ini` file -h, --help Print help information --ini-path Path to the `php.ini` file to update with the new extension --install-dir Changes the path that the extension is copied to. This will not activate the extension unless `ini_path` is also passed --manifest Path to the Cargo manifest of the extension. Defaults to the manifest in the directory the command is called --release Whether to install the release version of the extension --yes Bypasses the confirmation prompt ``` -------------------------------- ### Install cargo-php Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/getting-started/cargo-php.md Install the `cargo-php` subcommand using Cargo. Ensure you use the `--locked` flag for reproducible builds. ```bash $ cargo install cargo-php --locked ``` -------------------------------- ### BailoutGuard API Examples Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/advanced/bailout_guard.md Provides examples of creating and using `BailoutGuard`, including accessing the inner value and extracting it. ```rust // Create a guard let guard = BailoutGuard::new(value); // Access the value (implements Deref and DerefMut) guard.do_something(); let inner: &T = &*guard; let inner_mut: &mut T = &mut *guard; // Explicitly get references let inner: &T = guard.get(); let inner_mut: &mut T = guard.get_mut(); // Extract the value, cancelling cleanup let value: T = guard.into_inner(); ``` -------------------------------- ### Install PHP Extension with cargo-php Source: https://github.com/extphprs/ext-php-rs/blob/master/README.md This command compiles and installs a PHP extension in release mode using `cargo-php`. It prompts for confirmation before installation. ```bash cargo php install --release ``` -------------------------------- ### PHP Example Usage of Rust String Function Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/types/string.md Demonstrates how to call the Rust `str_example` function from PHP. It shows examples with both a string input and an integer input, illustrating PHP's automatic type conversion to string. ```php $value) { echo "$key => $value\n"; } // Output: // 0 => 1 // 1 => 2 // 2 => 3 // 3 => 4 // 4 => 5 // Works with iterator functions $arr = iterator_to_array(new RangeIterator(10, 12)); // [0 => 10, 1 => 11, 2 => 12] $count = iterator_count(new RangeIterator(1, 100)); // 100 ``` -------------------------------- ### Registering $_SERVER Variables Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/advanced/custom_sapi.md Override the `register_server_variables` method in your `Sapi` implementation to populate the `$_SERVER` superglobal array. This example registers `SERVER_SOFTWARE` and `SERVER_PROTOCOL`. ```rust use ext_php_rs::embed::{Sapi, ServerVarRegistrar}; # struct MySapi; # struct Ctx; # impl ext_php_rs::embed::ServerContext for Ctx { # fn init_request_info(&self, _: &mut ext_php_rs::embed::RequestInfo) {} # fn read_post(&mut self, _: &mut [u8]) -> usize { 0 } # fn read_cookies(&self) -> Option<&str> { None } # fn finish_request(&mut self) -> bool { true } # fn is_request_finished(&self) -> bool { true } # } # impl Sapi for MySapi { # type Context = Ctx; # fn name() -> &'static str { "x" } # fn pretty_name() -> &'static str { "x" } # fn ub_write(_: &mut Ctx, b: &[u8]) -> usize { b.len() } # fn log_message(_: &str, _: i32) {} fn register_server_variables( _ctx: &mut Ctx, registrar: &mut ServerVarRegistrar, ) { registrar.register("SERVER_SOFTWARE", "my-server/1.0"); registrar.register("SERVER_PROTOCOL", "HTTP/1.1"); } # } ``` -------------------------------- ### PHP Usage of Rust String Functions Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/types/str.md This PHP code demonstrates how to call the Rust functions `str_example` and `str_return_example`. It shows a successful call with a string input and an example of an invalid input type for `str_example`. ```php fontSize = 16.0; echo $style->fontSize; // 12.0 — original is unchanged ``` -------------------------------- ### PHP HashSet Example Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/types/vec.md Demonstrates calling the Rust `test_hashset` function from PHP. The output shows that duplicates are removed and the order is not preserved in the resulting PHP array. ```php String { format!("Hello {}", input) } fn main() {} ``` -------------------------------- ### Generate PHP IDE Stubs with cargo-php Source: https://github.com/extphprs/ext-php-rs/blob/master/README.md This command installs `cargo-php` and generates IDE stubs for a PHP extension. This is useful for IDE autocompletion and type checking. ```bash cargo install cargo-php --locked cargo php stubs --stdout ``` -------------------------------- ### Implement ZendExtensionHandler for Statement Profiling Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/advanced/observer.md Register a `ZendExtensionHandler` to enable per-statement profiling. This example counts executed statements and resets the count on activation. ```rust use ext_php_rs::prelude::*; use ext_php_rs::ffi::zend_op_array; use ext_php_rs::zend::ExecuteData; use std::sync::atomic::{AtomicU64, Ordering}; struct StatementProfiler { count: AtomicU64 } impl ZendExtensionHandler for StatementProfiler { fn on_statement(&self, _execute_data: &ExecuteData) { self.count.fetch_add(1, Ordering::Relaxed); } fn on_activate(&self) { self.count.store(0, Ordering::Relaxed); } } #[php_module] pub fn get_module(module: ModuleBuilder) -> ModuleBuilder { module .zend_extension(|| StatementProfiler { count: AtomicU64::new(0) }) .hook_statements() .finish() } ``` -------------------------------- ### Display cargo-php stubs subcommand help Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/getting-started/cargo-php.md Get detailed help for the `stubs` subcommand, which is used to generate PHP stub files for your extension. ```bash $ cargo php stubs --help ``` -------------------------------- ### PHP Module Macro Usage Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/macros/module.md This example demonstrates how to use the `#[php_module]` attribute to define a PHP extension. It includes registering a constant, a class, a function, and a custom info function for `phpinfo()`. ```rust #![cfg_attr(windows, feature(abi_vectorcall))] extern crate ext_php_rs; use ext_php_rs::{ prelude::*, zend::ModuleEntry, info_table_start, info_table_row, info_table_end }; #[php_const] pub const MY_CUSTOM_CONST: &'static str = "Hello, world!"; #[php_class] pub struct Test { a: i32, b: i32 } #[php_function] pub fn hello_world() -> &'static str { "Hello, world!" } /// Used by the `phpinfo()` function and when you run `php -i`. /// This will probably be simplified with another macro eventually! pub extern "C" fn php_module_info(_module: *mut ModuleEntry) { info_table_start!(); info_table_row!("my extension", "enabled"); info_table_end!(); } #[php_module] pub fn get_module(module: ModuleBuilder) -> ModuleBuilder { module .constant(wrap_constant!(MY_CUSTOM_CONST)) .class::() .function(wrap_function!(hello_world)) .info_function(php_module_info) } # fn main() {} ``` -------------------------------- ### Direct Function Call for Buffered Binary Output Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/output.md The `zend::output_write()` function provides buffered, binary-safe output. This example demonstrates writing data and checking for incomplete writes. ```rust use ext_php_rs::zend::output_write; fn output_data(data: &[u8]) { let bytes_written = output_write(data); if bytes_written != data.len() { eprintln!("Warning: incomplete write"); } } ``` -------------------------------- ### Build Rust Extension Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/getting-started/hello_world.md Build the Rust extension using Cargo. Environment variables like PHP and PHP_CONFIG can be used to specify PHP installation paths. ```sh cargo build ``` -------------------------------- ### Exposing Async Rust Functions with #[php_async_impl] Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/advanced/async_impl.md This snippet demonstrates how to expose an async Rust HTTP client (reqwest) to PHP. It includes initializing the event loop, defining an async `get` function, and setting up a request shutdown handler. Ensure php-tokio is a dependency. ```rust # extern crate ext_php_rs; # extern crate php_tokio; # extern crate reqwest; use ext_php_rs::prelude::*; use php_tokio::{php_async_impl, EventLoop}; #[php_class] struct Client {} #[php_async_impl] impl Client { pub fn init() -> PhpResult { EventLoop::init() } pub fn wakeup() -> PhpResult<()> { EventLoop::wakeup() } pub async fn get(url: &str) -> anyhow::Result { Ok(reqwest::get(url).await?.text().await?) } } pub extern "C" fn request_shutdown(_type: i32, _module_number: i32) -> i32 { EventLoop::shutdown(); 0 } #[php_module] pub fn get_module(module: ModuleBuilder) -> ModuleBuilder { module.request_shutdown_function(request_shutdown) } ``` -------------------------------- ### PHP Function Call Example Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/types/numbers.md This PHP code shows how to call the Rust-defined `test_numbers` function with sample integer and float arguments. The output demonstrates the values received by the Rust function. ```php ``` -------------------------------- ### Obtain and Call a PHP Function from Rust Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/types/functions.md Demonstrates how to get a `Function` struct for a PHP function like `var_dump` and then call it with arguments. It's recommended to reuse the `Function` object. ```rust # #![cfg_attr(windows, feature(abi_vectorcall))] # extern crate ext_php_rs; use ext_php_rs::prelude::*; use ext_php_rs::zend::Function; #[php_function] pub fn test_function() -> () { let var_dump = Function::try_from_function("var_dump").unwrap(); let _ = var_dump.try_call(vec![&"abc"]); } # fn main() {} ``` -------------------------------- ### Calling Rust ZendIterator function from PHP Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/types/iterator.md This PHP example shows how to create a generator and pass it to the `test_iterator` Rust function. The generator yields key-value pairs that are then processed by the Rust code. ```php 'world'; yield 'rust' => 'php'; }; test_iterator($generator()); ``` -------------------------------- ### Solution 2: Using BailoutGuard for Guaranteed Cleanup Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/advanced/bailout_guard.md Illustrates how `BailoutGuard` ensures cleanup of resources like file handles even if a bailout occurs directly. ```rust use ext_php_rs::prelude::*; use std::fs::File; #[php_function] pub fn process_file(callback: ZendCallable) { // Wrap the file handle in BailoutGuard let file = BailoutGuard::new(File::open("data.txt").unwrap()); // Even if bailout occurs, the file will be closed callback.try_call(vec![]); // Use the file via Deref // file.read_to_string(...); } ``` -------------------------------- ### Building the SAPI Module Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/advanced/custom_sapi.md Use `Sapi::build_module()` to generate a `SapiModule` from your SAPI implementation. This module can then be used with `sapi_startup()` and `php_module_startup()`. ```rust use ext_php_rs::embed::Sapi; # struct MySapi; # impl Sapi for MySapi { # type Context = (); # fn name() -> &'static str { "x" } # fn pretty_name() -> &'static str { "x" } # fn ub_write(_ctx: &mut (), _buf: &[u8]) -> usize { 0 } # fn log_message(_: &str, _: i32) {} # } # impl ext_php_rs::embed::ServerContext for () { # fn init_request_info(&self, _: &mut ext_php_rs::embed::RequestInfo) {} # fn read_post(&mut self, _: &mut [u8]) -> usize { 0 } # fn read_cookies(&self) -> Option<&str> { None } # fn finish_request(&mut self) -> bool { true } # fn is_request_finished(&self) -> bool { true } # } let module = MySapi::build_module().expect("failed to build SAPI module"); ``` -------------------------------- ### Creating and Reading ZendHashTable in Rust Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/types/zend_hashtable.md Demonstrates how to create a new `ZendHashTable`, push values, insert with string/numeric keys, and read values by key or index. Also shows iteration and length checks. ```rust # #![cfg_attr(windows, feature(abi_vectorcall))] # extern crate ext_php_rs; use ext_php_rs::prelude::*; use ext_php_rs::types::{ZendHashTable, ZendStr}; use ext_php_rs::boxed::ZBox; #[php_function] pub fn create_array() -> ZBox { let mut ht = ZendHashTable::new(); // Push values (auto-incrementing numeric keys) ht.push("first").unwrap(); ht.push("second").unwrap(); // Insert with string keys ht.insert("name", "John").unwrap(); ht.insert("age", 30i64).unwrap(); // Insert at specific numeric index ht.insert_at_index(100, "at index 100").unwrap(); // Insert with ZendStr keys // This allows bypassing repeated zend_string_init allocations and re-hashing // when working with pre-existing or interned PHP strings let key = ZendStr::new("hello", false); ht.insert(&key, "world"); ht } #[php_function] pub fn read_array(arr: &ZendHashTable) { // Get by string key if let Some(name) = arr.get("name") { println!("Name: {:?}", name.str()); } // Get by numeric index if let Some(first) = arr.get_index(0) { println!("First: {:?}", first.str()); } // Check length println!("Length: {}", arr.len()); println!("Is empty: {}", arr.is_empty()); // Iterate over key-value pairs for (key, value) in arr.iter() { println!("{}: {:?}", key, value); } } # fn main() {} ``` -------------------------------- ### Get Raw Pointer to Module Globals Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/advanced/module_globals.md Use `as_ptr()` to get a raw mutable pointer to the global state, useful for interfacing with C APIs or custom concurrency patterns. ```rust # use ext_php_rs::zend::{ModuleGlobal, ModuleGlobals}; # #[derive(Default)] # struct MyGlobals { request_count: i64 } # impl ModuleGlobal for MyGlobals {} # static MY_GLOBALS: ModuleGlobals = ModuleGlobals::new(); let ptr: *mut MyGlobals = MY_GLOBALS.as_ptr(); ``` -------------------------------- ### Create Rust Library Crate Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/getting-started/hello_world.md Initialize a new Rust library crate for the PHP extension. ```sh $ cargo new hello_world --lib $ cd hello_world ``` -------------------------------- ### Using the Rust-defined Interface in PHP Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/macros/interface.md Demonstrates how to instantiate a Rust class that implements a custom PHP interface and use its methods in PHP. It also shows how to use the interface for type hinting. ```php greet(); // Output: Hello, World! // Can be used as type hint function greet(Rust\Greetable $obj): void { echo $obj->greet(); } greet($greeter); ``` -------------------------------- ### Using Rust-implemented PHP Class in PHP Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/macros/impl.md Demonstrates how to instantiate and use the 'Human' class, implemented in Rust, within a PHP script. Shows calling methods and accessing static properties. ```php introduce(); // My name is David and I am 20 years old. var_dump(Human::get_max_age()); // int(100) var_dump(Human::MAX_AGE); // int(100) ``` -------------------------------- ### Using a Rust-defined Interface in PHP Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/macros/interface.md Demonstrates how to check for the existence of the 'Rust\TestInterface' and implement it in a PHP class. ```php Self { Self { exception_count: AtomicU64::new(0), } } } impl ExceptionObserver for ExceptionTracker { fn on_exception(&self, exception: &ExceptionInfo) { self.exception_count.fetch_add(1, Ordering::Relaxed); eprintln!("[EXCEPTION] {}: {} at {}:{}", exception.class_name, exception.message.as_deref().unwrap_or(""), exception.file.as_deref().unwrap_or(""), exception.line ); } } #[php_module] pub fn get_module(module: ModuleBuilder) -> ModuleBuilder { module.exception_observer(ExceptionTracker::new) } ``` -------------------------------- ### Using IniBuilder to Configure SAPI Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/ini-builder.md Demonstrates how to use IniBuilder to append and prepend INI settings, and then apply them to a SAPI. Use IniBuilder for immutable SAPI configurations. ```rust use ext_php_rs::builder::{IniBuilder, SapiBuilder}; # fn main() { // Create a new IniBuilder instance. let mut builder = IniBuilder::new(); // Append a single key/value pair to the INIT buffer with an unquoted value. builder.unquoted("log_errors", "1"); // Append a single key/value pair to the INI buffer with a quoted value. builder.quoted("default_mimetype", "text/html"); // Append INI line text as-is. A line break will be automatically appended. builder.define("memory_limit=128MB"); // Prepend INI line text as-is. No line break insertion will occur. builder.prepend("error_reporting=0\ndisplay_errors=1\n"); // Construct a SAPI. let mut sapi = SapiBuilder::new("name", "pretty_name").build() .expect("should build SAPI"); // Dump INI entries from the builder into the SAPI. sapi.ini_entries = builder.finish(); # } ``` -------------------------------- ### Run and Test Extension Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/getting-started/hello_world.md Execute the PHP script with the loaded extension using the '-d extension=' option. ```sh $ php -d extension=./target/debug/libhello_world.so test.php ``` -------------------------------- ### Register Module Globals with ModuleBuilder Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/advanced/module_globals.md Register the global state by declaring a static `ModuleGlobals` instance and passing it to `ModuleBuilder::globals()` during module setup. ```rust 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 = ModuleGlobals::new(); #[php_module] pub fn module(module: ModuleBuilder) -> ModuleBuilder { module.globals(&MY_GLOBALS) } ``` -------------------------------- ### Cargo.toml Configuration Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/getting-started/hello_world.md Configure the Cargo.toml file to include ext-php-rs as a dependency and set the crate type to 'cdylib'. ```toml [package] name = "hello_world" version = "0.1.0" edition = "2018" [lib] crate-type = ["cdylib"] [dependencies] ext-php-rs = "*" [profile.release] strip = "debuginfo" ``` -------------------------------- ### Worker Mode API Functions Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/advanced/worker_mode.md Demonstrates the core functions for managing worker mode: shutting down a request, starting a new one, and resetting superglobals. ```rust use ext_php_rs::embed::{ worker_request_shutdown, worker_request_startup, worker_reset_superglobals, }; // After processing a request: worker_request_shutdown(); // Before the next request: worker_request_startup().expect("startup failed"); worker_reset_superglobals(); ``` -------------------------------- ### Update Bindings Script Source: https://github.com/extphprs/ext-php-rs/blob/master/README.md This bash script updates the `docsrs_bindings.rs` file by building Rust bindings using Docker. Ensure Docker and buildx are installed before running. ```bash tools/update_bindings.sh ``` -------------------------------- ### Solution 1: Using try_call to Catch Bailouts Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/advanced/bailout_guard.md Shows how `try_call` can catch PHP bailouts internally, allowing Rust destructors to run and prevent resource leaks. ```rust #[php_function] pub fn process_file(callback: ZendCallable) { let file = File::open("data.txt").unwrap(); // try_call catches bailout, function returns, file is dropped let result = callback.try_call(vec![]); if result.is_err() { // Bailout occurred, but file will still be closed // when this function returns } } ``` -------------------------------- ### PHP: Create Lazy Proxy using Reflection Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/types/object.md Demonstrates creating a lazy proxy object in PHP using the Reflection API. This enables delayed instantiation of an object. ```php newLazyProxy(function ($obj) { return new MyClass('initialized'); }); ``` -------------------------------- ### Display cargo-php help Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/getting-started/cargo-php.md View the main help information for the `cargo-php` command to understand its available subcommands and options. ```bash $ cargo php --help ``` -------------------------------- ### Using Cross-Crate Implemented Interface in PHP Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/macros/interface.md Demonstrates using a Rust class from one crate that implements an interface defined in another crate. It shows that `instanceof` and type hints work correctly across crates. ```php toJson(); } echo serialize_object($user); // Output: {"name":"John","email":"john@example.com"} ``` -------------------------------- ### PHP: Create Lazy Ghost using Reflection Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/types/object.md Demonstrates creating a lazy ghost object in PHP using the Reflection API. This allows for deferred initialization of an object. ```php newLazyGhost(function ($obj) { $obj->__construct('initialized'); }); ``` -------------------------------- ### Rust Function with Option Parameter and Return Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/types/option.md Demonstrates how to define a Rust function that accepts an Option and returns an Option. If a string is provided, it's wrapped in 'Hello '. If no input is given (None), the function returns None (which translates to null in PHP). ```rust #![cfg_attr(windows, feature(abi_vectorcall))] extern crate ext_php_rs; use ext_php_rs::prelude::*; #[php_function] pub fn test_option_null(input: Option) -> Option { input.map(|input| format!("Hello {}", input).into()) } fn main() {} ``` -------------------------------- ### PHP Autoloader and Helper Function Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/advanced/embedded_php.md This PHP code defines an autoloader for a specific namespace and a helper function to get a version string. It's intended to be embedded and executed from Rust. ```php anyhow::Result<()> { let php = find_php()?; let info = PHPInfo::get(&php)?; let version: ApiVersion = info.zend_version()?.try_into()?; emit_check_cfg(); emit_php_cfg_flags(version); Ok(()) } ``` -------------------------------- ### Create Custom PHP Exception with Namespace Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/macros/classes.md This example shows how to create a custom PHP exception named `RedisException` that extends the built-in `Exception` class and is placed within the `Redis\Exception` namespace. ```rust #![cfg_attr(windows, feature(abi_vectorcall))] ``` -------------------------------- ### Async PHP Client for Rust Service Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/advanced/async_impl.md This PHP code interacts with the exposed Rust client. It initializes the Revolt event loop, sets up handlers for event loop events, and provides a static method to call Rust functions. It also demonstrates how to run multiple async tasks concurrently using Amp\async and Amp\Future\await. ```php \Client::wakeup()); } public static function reference(): void { EventLoop::reference(self::$id); } public static function unreference(): void { EventLoop::unreference(self::$id); } public static function __callStatic(string $name, array $args): mixed { return \Client::$name(...$args); } } Client::init(); function test(int $delay): void { $url = "https://httpbin.org/delay/".$delay; $t = time(); echo "Making async reqwest to $url that will return after $delay seconds...".PHP_EOL; Client::get($url); $t = time() - $t; echo "Got response from $url after ~".$t." seconds!".PHP_EOL; }; $futures = []; $futures []= async(test(...), 5); $futures []= async(test(...), 5); $futures []= async(test(...), 5); await($futures); ``` -------------------------------- ### PHP Associative Array to Rust IndexMap Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/types/hashmap.md Demonstrates passing a PHP associative array to a Rust function expecting an IndexMap. The PHP example shows how keys maintain their order when passed. ```php 'last', 'a' => 'first', 'm' => 'middle', ]); // Output preserves insertion order foreach ($result as $key => $value) { echo "$key => $value\n"; } // first => 1 // second => 2 // third => 3 ``` -------------------------------- ### Configure Rust LLD Linker for Windows Source: https://github.com/extphprs/ext-php-rs/blob/master/README.md Use this configuration to set `rust-lld` as the linker for your Rust extension on Windows. Replace the target triple if you are not using the x86_64 architecture. ```toml # Replace target triple if you have a different architecture than x86_64 [target.x86_64-pc-windows-msvc] linker = "rust-lld" ``` -------------------------------- ### Define a Custom PHP Exception Class in Rust Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/macros/classes.md Define a custom exception class in Rust that can be thrown from PHP. This example creates a RedisException class extending PHP's built-in Exception. ```rust # extern crate ext_php_rs; use ext_php_rs::{ prelude::*, exception::PhpException, zend::ce }; #[php_class] #[php(name = "Redis\\Exception\\RedisException")] #[php(extends(ce = ce::exception, stub = "\\Exception"))] #[derive(Default)] pub struct RedisException; // Throw our newly created exception #[php_function] pub fn throw_exception() -> PhpResult { Err(PhpException::from_class::("Not good!".into())) } #[php_module] pub fn get_module(module: ModuleBuilder) -> ModuleBuilder { module .class::() .function(wrap_function!(throw_exception)) } # fn main() {} ``` -------------------------------- ### Counting Occurrences with ZendHashTable Entry API in Rust Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/types/zend_hashtable.md Provides an example of using the `ZendHashTable` Entry API to count the occurrences of words in a list, incrementing a counter for existing words or inserting a new one. ```rust # #![cfg_attr(windows, feature(abi_vectorcall))] # extern crate ext_php_rs; use ext_php_rs::prelude::*; use ext_php_rs::types::ZendHashTable; use ext_php_rs::boxed::ZBox; #[php_function] pub fn count_words(words: Vec) -> ZBox { let mut counts = ZendHashTable::new(); for word in words { counts.entry(word.as_str()) .and_modify(|v| { if let Some(n) = v.long() { v.set_long(n + 1); } }) .or_insert(1i64) .unwrap(); } counts } # fn main() {} ``` -------------------------------- ### Cargo Configuration for Linker Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/getting-started/hello_world.md Set up .cargo/config.toml to handle linker configurations for different operating systems, especially for dynamic loading on Linux/macOS and using rust-lld on Windows. ```toml {{#include ../../../.cargo/config.toml}} ``` -------------------------------- ### Create New Class Instance in Rust Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/types/class_object.md Shows how to define a Rust struct and implement a method to create a new instance of that struct, which can then be used as a PHP class object. ```rust #![cfg_attr(windows, feature(abi_vectorcall))] extern crate ext_php_rs; use ext_php_rs::prelude::*; #[php_class] pub struct Example { foo: i32, bar: i32 } #[php_impl] impl Example { pub fn make_new(foo: i32, bar: i32) -> Example { Example { foo, bar } } } #[php_module] pub fn get_module(module: ModuleBuilder) -> ModuleBuilder { module.class::() } # fn main() {} ``` -------------------------------- ### Exporting a Rust Function to PHP Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/macros/function.md Use the `#[php_function]` attribute to export a Rust function. The function signature determines how arguments are passed from PHP. This example shows a simple function with an optional `age` parameter. ```rust #![cfg_attr(windows, feature(abi_vectorcall))] extern crate ext_php_rs; use ext_php_rs::prelude::*; #[php_function] pub fn greet(name: String, age: Option) -> String { let mut greeting = format!("Hello, {}!", name); if let Some(age) = age { greeting += &format!(" You are {} years old.", age); } greeting } #[php_module] pub fn get_module(module: ModuleBuilder) -> ModuleBuilder { module.function(wrap_function!(greet)) } fn main() {} ``` -------------------------------- ### Implementing ServerContext for Per-Request State Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/advanced/custom_sapi.md Implement the `ServerContext` trait for your custom request type to manage per-request state like method, URI, and body. This example shows a basic `MyContext` struct and its implementation. ```rust use ext_php_rs::embed::{ServerContext, RequestInfo}; struct MyContext { method: String, uri: String, body: Vec, body_offset: usize, finished: bool, } impl ServerContext for MyContext { fn init_request_info(&self, info: &mut RequestInfo) { info.request_method = Some(self.method.clone()); info.request_uri = Some(self.uri.clone()); info.content_length = self.body.len() as i64; } fn read_post(&mut self, buf: &mut [u8]) -> usize { let remaining = &self.body[self.body_offset..]; let n = buf.len().min(remaining.len()); buf[..n].copy_from_slice(&remaining[..n]); self.body_offset += n; n } fn read_cookies(&self) -> Option<&str> { None } fn finish_request(&mut self) -> bool { if self.finished { return false; } self.finished = true; true } fn is_request_finished(&self) -> bool { self.finished } } ``` -------------------------------- ### Implementing the Sapi Trait for Custom SAPI Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/advanced/custom_sapi.md Implement the `Sapi` trait to define your custom SAPI's behavior, including output handling (`ub_write`) and logging (`log_message`). This example defines a basic `MySapi` struct. ```rust use ext_php_rs::embed::{Sapi, ServerContext, RequestInfo, ServerVarRegistrar}; # struct MyContext { method: String, uri: String, body: Vec, body_offset: usize, finished: bool } # impl ServerContext for MyContext { # fn init_request_info(&self, _: &mut RequestInfo) {} # fn read_post(&mut self, _: &mut [u8]) -> usize { 0 } # fn read_cookies(&self) -> Option<&str> { None } # fn finish_request(&mut self) -> bool { true } # fn is_request_finished(&self) -> bool { true } # } struct MySapi; impl Sapi for MySapi { type Context = MyContext; fn name() -> &'static str { "my-sapi" } fn pretty_name() -> &'static str { "My Custom SAPI" } fn ub_write(_ctx: &mut MyContext, buf: &[u8]) -> usize { // Forward output to your HTTP response print!("{}", String::from_utf8_lossy(buf)); buf.len() } fn log_message(msg: &str, _syslog_type: i32) { eprintln!("[php] {msg}"); } } ``` -------------------------------- ### Get Request Information in Rust Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/superglobals.md Retrieves various details about the current HTTP request, such as method, URI, query string, and content type. This function is useful for inspecting incoming requests within a PHP environment. ```rust #![cfg_attr(windows, feature(abi_vectorcall))] extern crate ext_php_rs; use ext_php_rs::prelude::*; use ext_php_rs::zend::SapiGlobals; #[php_function] pub fn get_request_info() -> Vec { let globals = SapiGlobals::get(); let request_info = globals.request_info(); let mut info = Vec::new(); if let Some(method) = request_info.request_method() { info.push(format!("Method: {}", method)); } if let Some(uri) = request_info.request_uri() { info.push(format!("URI: {}", uri)); } if let Some(query) = request_info.query_string() { info.push(format!("Query: {}", query)); } if let Some(content_type) = request_info.content_type() { info.push(format!("Content-Type: {}", content_type)); } info.push(format!("Content-Length: {}", request_info.content_length())); info } # fn main() {} ``` -------------------------------- ### Defining an Abstract Class with Abstract Method Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/macros/impl.md Demonstrates how to define an abstract class and an abstract method using `#[php(flags = ClassFlags::Abstract)]` and `#[php(abstract)]`. Subclasses must implement the abstract method. ```rust use ext_php_rs::prelude::*; use ext_php_rs::flags::ClassFlags; #[php_class] #[php(flags = ClassFlags::Abstract)] pub struct AbstractShape; #[php_impl] impl AbstractShape { // Protected constructor for subclasses #[php(vis = "protected")] pub fn __construct() -> Self { Self } // Abstract method - subclasses must implement this. // The body is never called; use unimplemented!() as a placeholder. #[php(abstract)] pub fn area(&self) -> f64 { unimplemented!() } // Concrete method in abstract class pub fn describe(&self) -> String { format!("A shape with area {}", self.area()) } } ``` -------------------------------- ### Exporting a Backed Rust Enum to PHP (String Values) Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/macros/enum.md This example shows how to create a PHP enum where each case has a specific string value. Use the `#[php(value = "...")]` attribute on each enum variant. ```rust #![cfg_attr(windows, feature(abi_vectorcall))] extern crate ext_php_rs; use ext_php_rs::prelude::*; #[php_enum] pub enum Suit { #[php(value = "hearts")] Hearts, #[php(value = "diamonds")] Diamonds, #[php(value = "clubs")] Clubs, #[php(value = "spades")] Spades, } #[php_module] pub fn get_module(module: ModuleBuilder) -> ModuleBuilder { module.enumeration::() } ``` -------------------------------- ### Registering Multiple Observers in a PHP Module Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/advanced/observer.md Demonstrates how to register various observers (fcall, error, exception, zend extension) and enable statement hooks within a PHP module using the ModuleBuilder. ```rust #[php_module] pub fn get_module(module: ModuleBuilder) -> ModuleBuilder { module .fcall_observer(MyProfiler::new) .error_observer(MyErrorTracker::new) .exception_observer(MyExceptionTracker::new) .zend_extension(MyStatementProfiler::new) .hook_statements() .finish() } ``` -------------------------------- ### Export Rust Struct as PHP Class with Property Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/macros/classes.md This example demonstrates exporting a Rust struct `Human` as a PHP class. It includes a `name` and `age` field, and exposes the `address` field as a public PHP property using `#[php(prop)]`. ```rust #![cfg_attr(windows, feature(abi_vectorcall))] extern crate ext_php_rs; use ext_php_rs::prelude::*; #[php_class] pub struct Human { name: String, age: i32, #[php(prop)] address: String, } #[php_module] pub fn get_module(module: ModuleBuilder) -> ModuleBuilder { module.class::() } fn main() {} ``` -------------------------------- ### PHP Associative Array to Rust HashMap Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/types/hashmap.md Shows how a PHP associative array is passed to a Rust function expecting a HashMap. The example PHP code demonstrates passing an array with string keys and a numerically indexed element. ```php 'world', 'rust' => 'php', 'okk', ])); ``` -------------------------------- ### Problem: File Handle Leak on PHP Exit Source: https://github.com/extphprs/ext-php-rs/blob/master/guide/src/advanced/bailout_guard.md Demonstrates how a file handle can leak if a PHP callback triggers an exit, bypassing Rust's drop semantics. ```rust #[php_function] pub fn process_file(callback: ZendCallable) { let file = File::open("data.txt").unwrap(); // If callback calls exit(), the file handle leaks! callback.try_call(vec![]); // file.drop() never runs } ```