whynot 0.2.0

Rust ↔ PHP bridge: call PHP functions from Rust, capture return values, output, and exceptions.
Documentation
whynot-0.2.0 has been yanked.

whyNot πŸ˜βž‘οΈπŸ¦€

Crates.io Docs.rs

Rust ↔ PHP bridge that lets you call PHP functions directly from Rust, capture return values, printed output, and exceptions β€” with async support via threads or Tokio.


✨ Features

  • Call any PHP function from Rust
  • Capture both return values and printed output
  • Structured exception handling (PhpException)
  • Objects returned with class + fields
  • Persistent runtime (globals/includes survive across calls)
  • include and eval support
  • Async via threads (call_async_with_cfg)
  • Async/await via Tokio (--features async_tokio)

πŸš€ Getting Started

Install

To install you can run:

cargo add whynot

Or add to your Cargo.toml:

[dependencies]
whynot = "0.1.0"

Requirements

  • PHP CLI (php) available in PATH
  • php/runner.php and php/bootstrap.php included in your project

πŸ“– Usage

Basic call

use whynot::{new_runtime, PhpRuntime, RuntimeConfig, RuntimeKind};

fn main() {
    let cfg = RuntimeConfig::default();
    let mut rt = new_runtime(RuntimeKind::Process(cfg)).unwrap();

    let result = rt.call("add", &[7.into(), 5.into()]).unwrap();
    println!("add.result = {:?}", result.result);
    println!("add.output = {:?}", result.output);
}

Exceptions

let boom = rt.call("risky", &[]).unwrap();
if let Some(ex) = boom.exception {
    println!("Exception: {} ({})", ex.message, ex.class);
    println!("Trace: {}", ex.trace);
}

Async (threads)

use whynot::process::ProcRuntime;

let h1 = ProcRuntime::call_async_with_cfg(cfg.clone(), "greet".to_string(), vec!["Milton".into()]);
let h2 = ProcRuntime::call_async_with_cfg(cfg.clone(), "add".to_string(), vec![7.into(), 9.into()]);

println!("greet = {:?}", h1.join().unwrap().unwrap().result);
println!("add = {:?}", h2.join().unwrap().unwrap().result);

Async/await (Tokio)

Enable the feature:

cargo run --example tokio_async --features async_tokio

Example:

#[tokio::main]
async fn main() {
    let cfg = RuntimeConfig::default();

    let greet = whynot::async_tokio::call_async(cfg.clone(), "greet".to_string(), vec!["Milton".into()])
        .await.unwrap();
    println!("greet.result = {:?}", greet.result);
}

πŸ“‚ Project Layout

whynot/
  Cargo.toml
  src/
    lib.rs
    value.rs
    macros.rs
    process.rs
    embedded.rs
    async_tokio.rs
  php/
    runner.php
    bootstrap.php
  examples/
    call_any.rs
    async_calls.rs
    tokio_async.rs

πŸ›  Roadmap

  • Function calls, output capture, exceptions
  • Objects serialization
  • Includes, eval
  • Threaded async
  • Tokio async/await
  • Embedded Zend runtime (in‑process)
  • Resource/extension support
  • Automatic Rust ↔ PHP struct mapping
  • Publish crate to crates.io

🀝 Contributing

Pull requests welcome. Please open issues for bugs, feature requests, or questions.