|
| 1 | +# Hello World |
| 2 | + |
| 3 | +Let's create a basic PHP extension. We will start by creating a new Rust library |
| 4 | +crate: |
| 5 | + |
| 6 | +```sh |
| 7 | +$ cargo new hello_world --lib |
| 8 | +$ cd hello_world |
| 9 | +``` |
| 10 | + |
| 11 | +Let's set up our crate by adding `ext-php-rs` as a dependency and setting the |
| 12 | +crate type to `cdylib`. Update the `Cargo.toml` to look something like so: |
| 13 | + |
| 14 | +### `Cargo.toml` |
| 15 | + |
| 16 | +```toml |
| 17 | +[package] |
| 18 | +name = "hello_world" |
| 19 | +version = "0.1.0" |
| 20 | +edition = "2018" |
| 21 | + |
| 22 | +[dependencies] |
| 23 | +ext-php-rs = "0.2" |
| 24 | + |
| 25 | +[lib] |
| 26 | +crate-type = ["cdylib"] |
| 27 | +``` |
| 28 | + |
| 29 | +As the linker will not be able to find the PHP installation that we are |
| 30 | +dynamically linking to, we need to enable dynamic linking with undefined |
| 31 | +symbols. We do this by creating a Cargo config file in `.cargo/config.toml` with |
| 32 | +the following contents: |
| 33 | + |
| 34 | +### `.cargo/config.toml` |
| 35 | + |
| 36 | +```toml |
| 37 | +[build] |
| 38 | +rustflags = ["-C", "link-arg=-Wl,-undefined,dynamic_lookup"] |
| 39 | +``` |
| 40 | + |
| 41 | +Let's actually write the extension code now. We start by importing the |
| 42 | +`ext-php-rs` prelude, which contains most of the imports required to make a |
| 43 | +basic extension. We will then write our basic `hello_world` function, which will |
| 44 | +take a string argument for the callers name, and we will return another string. |
| 45 | +Finally, we write a `get_module` function which is used by PHP to find out about |
| 46 | +your module. The `#[php_module]` attribute automatically registers your new |
| 47 | +function so we don't need to do anything except return the `ModuleBuilder` that |
| 48 | +we were given. |
| 49 | + |
| 50 | +### `src/lib.rs` |
| 51 | + |
| 52 | +```rust |
| 53 | +# extern crate ext_php_rs; |
| 54 | +use ext_php_rs::prelude::*; |
| 55 | + |
| 56 | +#[php_function] |
| 57 | +pub fn hello_world(name: String) -> String { |
| 58 | + format!("Hello, {}!", name) |
| 59 | +} |
| 60 | + |
| 61 | +#[php_module] |
| 62 | +pub fn get_module(module: ModuleBuilder) -> ModuleBuilder { |
| 63 | + module |
| 64 | +} |
| 65 | +``` |
| 66 | + |
| 67 | +Let's make a test script. |
| 68 | + |
| 69 | +### `test.php` |
| 70 | + |
| 71 | +```php |
| 72 | +<?php |
| 73 | + |
| 74 | +var_dump(hello_world("David")); |
| 75 | +``` |
| 76 | + |
| 77 | +Now let's build our extension and run our test script. This is done through |
| 78 | +`cargo` like any other Rust crate. It is required that the `php-config` |
| 79 | +executable is able to be found by the `ext-php-rs` build script. |
| 80 | + |
| 81 | +The extension is stored inside `target/debug` (if you did a debug build, |
| 82 | +`target/release` for release builds). The file name will be based on your crate |
| 83 | +name, so for us it will be `libhello_world`. The extension is based on your OS - |
| 84 | +on Linux it will be `libhello_world.so` and on macOS it will be |
| 85 | +`libhello_world.dylib`. |
| 86 | + |
| 87 | +``` |
| 88 | +$ cargo build |
| 89 | + Finished dev [unoptimized + debuginfo] target(s) in 0.01s |
| 90 | +$ php -dextension=./target/debug/libhello_world.dylib test.php |
| 91 | +string(13) "Hello, David!" |
| 92 | +``` |
0 commit comments