Skip to content

Commit cae6332

Browse files
committed
docs(macro): update documentation for builder pattern
1 parent 0f7bbf3 commit cae6332

27 files changed

+460
-203
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@ Contributions welcome include:
192192
When contributing, please keep in mind the following:
193193
- Create tests if possible.
194194
- Update the documentation if necessary.
195+
- If your change is a [braking change](https://semver.org) a migration guide MUST be included. This
196+
should be placed in the `guide/src/migration-guides` directory.
195197
- Use [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/). We use these to automatically generate changelogs.
196198

197199
Unless you explicitly state otherwise, any contribution intentionally submitted

build.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
//! The build script for ext-php-rs.
2+
//! This script is responsible for generating the bindings to the PHP Zend API.
3+
//! It also checks the PHP version for compatibility with ext-php-rs and sets
4+
//! configuration flags accordingly.
15
#[cfg_attr(windows, path = "windows_build.rs")]
26
#[cfg_attr(not(windows), path = "unix_build.rs")]
37
mod impl_;
@@ -18,6 +22,7 @@ use impl_::Provider;
1822
const MIN_PHP_API_VER: u32 = 20200930;
1923
const MAX_PHP_API_VER: u32 = 20240924;
2024

25+
/// Provides information about the PHP installation.
2126
pub trait PHPProvider<'a>: Sized {
2227
/// Create a new PHP provider.
2328
fn new(info: &'a PHPInfo) -> Result<Self>;
@@ -75,9 +80,11 @@ fn find_php() -> Result<PathBuf> {
7580
})
7681
}
7782

83+
/// Output of `php -i`.
7884
pub struct PHPInfo(String);
7985

8086
impl PHPInfo {
87+
/// Get the PHP info.
8188
pub fn get(php: &Path) -> Result<Self> {
8289
let cmd = Command::new(php)
8390
.arg("-i")
@@ -100,25 +107,29 @@ impl PHPInfo {
100107
.try_into()
101108
}
102109

110+
/// Checks if thread safety is enabled.
103111
pub fn thread_safety(&self) -> Result<bool> {
104112
Ok(self
105113
.get_key("Thread Safety")
106114
.context("Could not find thread safety of PHP")?
107115
== "enabled")
108116
}
109117

118+
/// Checks if PHP was built with debug.
110119
pub fn debug(&self) -> Result<bool> {
111120
Ok(self
112121
.get_key("Debug Build")
113122
.context("Could not find debug build of PHP")?
114123
== "yes")
115124
}
116125

126+
/// Get the php version.
117127
pub fn version(&self) -> Result<&str> {
118128
self.get_key("PHP Version")
119129
.context("Failed to get PHP version")
120130
}
121131

132+
/// Get the zend version.
122133
pub fn zend_version(&self) -> Result<u32> {
123134
self.get_key("PHP API")
124135
.context("Failed to get Zend version")

crates/macros/src/function.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,11 @@ impl<'a> Function<'a> {
134134
// `handler` impl
135135
let required_arg_names: Vec<_> = required.iter().map(|arg| arg.name).collect();
136136
let not_required_arg_names: Vec<_> = not_required.iter().map(|arg| arg.name).collect();
137-
let arg_declerations = self
137+
let arg_declarations = self
138138
.args
139139
.typed
140140
.iter()
141-
.map(TypedArg::arg_decleration)
141+
.map(TypedArg::arg_declaration)
142142
.collect::<Result<Vec<_>>>()?;
143143
let arg_accessors = self.args.typed.iter().map(|arg| {
144144
arg.accessor(|e| {
@@ -248,7 +248,7 @@ impl<'a> Function<'a> {
248248
) {
249249
use ::ext_php_rs::convert::IntoZval;
250250

251-
#(#arg_declerations)*
251+
#(#arg_declarations)*
252252
let result = {
253253
#result
254254
};
@@ -308,11 +308,11 @@ impl<'a> Function<'a> {
308308

309309
let required_arg_names: Vec<_> = required.iter().map(|arg| arg.name).collect();
310310
let not_required_arg_names: Vec<_> = not_required.iter().map(|arg| arg.name).collect();
311-
let arg_declerations = self
311+
let arg_declarations = self
312312
.args
313313
.typed
314314
.iter()
315-
.map(TypedArg::arg_decleration)
315+
.map(TypedArg::arg_declaration)
316316
.collect::<Result<Vec<_>>>()?;
317317
let arg_accessors = self.args.typed.iter().map(|arg| {
318318
arg.accessor(
@@ -329,7 +329,7 @@ impl<'a> Function<'a> {
329329
::ext_php_rs::class::ConstructorMeta {
330330
constructor: {
331331
fn inner(ex: &mut ::ext_php_rs::zend::ExecuteData) -> ::ext_php_rs::class::ConstructorResult<#class> {
332-
#(#arg_declerations)*
332+
#(#arg_declarations)*
333333
let parse = ex.parser()
334334
#(.arg(&mut #required_arg_names))*
335335
.not_required()
@@ -515,9 +515,9 @@ impl TypedArg<'_> {
515515
ty
516516
}
517517

518-
/// Returns a token stream containing an argument decleration, where the
518+
/// Returns a token stream containing an argument declaration, where the
519519
/// name of the variable holding the arg is the name of the argument.
520-
fn arg_decleration(&self) -> Result<TokenStream> {
520+
fn arg_declaration(&self) -> Result<TokenStream> {
521521
let name = self.name;
522522
let val = self.arg_builder()?;
523523
Ok(quote! {

crates/macros/src/impl_.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub enum RenameRule {
1313
/// Methods won't be renamed.
1414
#[darling(rename = "none")]
1515
None,
16-
/// Methods will be conveted to camelCase.
16+
/// Methods will be converted to camelCase.
1717
#[darling(rename = "camelCase")]
1818
#[default]
1919
Camel,

crates/macros/src/lib.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ use syn::{
1919

2020
extern crate proc_macro;
2121

22+
// Not included in the doc tests, as they depend on `ext-php-rs` being available.
23+
// The guide tests will cover these macros.
24+
#[cfg(not(doctest))]
2225
#[lsp_doc("guide/src/macros/classes.md")]
2326
#[proc_macro_attribute]
2427
pub fn php_class(args: TokenStream, input: TokenStream) -> TokenStream {
@@ -30,6 +33,9 @@ pub fn php_class(args: TokenStream, input: TokenStream) -> TokenStream {
3033
.into()
3134
}
3235

36+
// Not included in the doc tests, as they depend on `ext-php-rs` being available.
37+
// The guide tests will cover these macros.
38+
#[cfg(not(doctest))]
3339
#[lsp_doc("guide/src/macros/function.md")]
3440
#[proc_macro_attribute]
3541
pub fn php_function(args: TokenStream, input: TokenStream) -> TokenStream {
@@ -41,6 +47,9 @@ pub fn php_function(args: TokenStream, input: TokenStream) -> TokenStream {
4147
.into()
4248
}
4349

50+
// Not included in the doc tests, as they depend on `ext-php-rs` being available.
51+
// The guide tests will cover these macros.
52+
#[cfg(not(doctest))]
4453
#[lsp_doc("guide/src/macros/constant.md")]
4554
#[proc_macro_attribute]
4655
pub fn php_const(_args: TokenStream, input: TokenStream) -> TokenStream {
@@ -49,6 +58,9 @@ pub fn php_const(_args: TokenStream, input: TokenStream) -> TokenStream {
4958
constant::parser(input).into()
5059
}
5160

61+
// Not included in the doc tests, as they depend on `ext-php-rs` being available.
62+
// The guide tests will cover these macros.
63+
#[cfg(not(doctest))]
5264
#[lsp_doc("guide/src/macros/module.md")]
5365
#[proc_macro_attribute]
5466
pub fn php_module(args: TokenStream, input: TokenStream) -> TokenStream {
@@ -60,6 +72,9 @@ pub fn php_module(args: TokenStream, input: TokenStream) -> TokenStream {
6072
.into()
6173
}
6274

75+
// Not included in the doc tests, as they depend on `ext-php-rs` being available.
76+
// The guide tests will cover these macros.
77+
#[cfg(not(doctest))]
6378
#[lsp_doc("guide/src/macros/impl.md")]
6479
#[proc_macro_attribute]
6580
pub fn php_impl(args: TokenStream, input: TokenStream) -> TokenStream {
@@ -71,6 +86,9 @@ pub fn php_impl(args: TokenStream, input: TokenStream) -> TokenStream {
7186
.into()
7287
}
7388

89+
// Not included in the doc tests, as they depend on `ext-php-rs` being available.
90+
// The guide tests will cover these macros.
91+
#[cfg(not(doctest))]
7492
#[lsp_doc("guide/src/macros/extern.md")]
7593
#[proc_macro_attribute]
7694
pub fn php_extern(_: TokenStream, input: TokenStream) -> TokenStream {
@@ -81,6 +99,9 @@ pub fn php_extern(_: TokenStream, input: TokenStream) -> TokenStream {
8199
.into()
82100
}
83101

102+
// Not included in the doc tests, as they depend on `ext-php-rs` being available.
103+
// The guide tests will cover these macros.
104+
#[cfg(not(doctest))]
84105
#[lsp_doc("guide/src/macros/zval_convert.md")]
85106
#[proc_macro_derive(ZvalConvert)]
86107
pub fn zval_convert_derive(input: TokenStream) -> TokenStream {
@@ -91,6 +112,7 @@ pub fn zval_convert_derive(input: TokenStream) -> TokenStream {
91112
.into()
92113
}
93114

115+
#[cfg(not(doctest))]
94116
/// Defines an `extern` function with the Zend fastcall convention based on
95117
/// operating system.
96118
///

guide/src/SUMMARY.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
- [Async futures](./macros/async_impl.md)
2828
- [Macros](./macros/index.md)
2929
- [Module](./macros/module.md)
30-
- [Module Startup Function](./macros/module_startup.md)
3130
- [Function](./macros/function.md)
3231
- [Classes](./macros/classes.md)
3332
- [`impl`s](./macros/impl.md)
@@ -37,3 +36,7 @@
3736
- [`ZvalConvert`](./macros/zval_convert.md)
3837
- [Exceptions](./exceptions.md)
3938
- [INI Settings](./ini-settings.md)
39+
40+
# Migration Guides
41+
---
42+
[v0.14](./migration-guides/v0.14.md)

guide/src/getting-started/hello_world.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,16 @@ Let's actually write the extension code now. We start by importing the
5757
basic extension. We will then write our basic `hello_world` function, which will
5858
take a string argument for the callers name, and we will return another string.
5959
Finally, we write a `get_module` function which is used by PHP to find out about
60-
your module. The `#[php_module]` attribute automatically registers your new
61-
function so we don't need to do anything except return the `ModuleBuilder` that
62-
we were given.
60+
your module. We must provide the defined function to the given `ModuleBuilder`
61+
and then return the same object.
6362

64-
We also need to enable the `abi_vectorcall` feature when compiling for Windows.
65-
This is a nightly-only feature so it is recommended to use the `#[cfg_attr]`
66-
macro to not enable the feature on other operating systems.
63+
We also need to enable the `abi_vectorcall` feature when compiling for Windows
64+
(the first line). This is a nightly-only feature so it is recommended to use
65+
the `#[cfg_attr]` macro to not enable the feature on other operating systems.
6766

68-
```rust,ignore
67+
```rust,no_run
6968
#![cfg_attr(windows, feature(abi_vectorcall))]
69+
# extern crate ext_php_rs;
7070
use ext_php_rs::prelude::*;
7171
7272
#[php_function]
@@ -76,8 +76,9 @@ pub fn hello_world(name: &str) -> String {
7676
7777
#[php_module]
7878
pub fn get_module(module: ModuleBuilder) -> ModuleBuilder {
79-
module
79+
module.function(wrap_function!(hello_world))
8080
}
81+
# fn main() {}
8182
```
8283

8384
## Building the extension

guide/src/ini-settings.md

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,22 @@ All PHP INI definitions must be registered with PHP to get / set their values vi
1414
# use ext_php_rs::zend::IniEntryDef;
1515
# use ext_php_rs::flags::IniEntryPermission;
1616
17-
#[php_startup]
18-
pub fn startup_function(ty: i32, module_number: i32) {
17+
pub fn startup(ty: i32, mod_num: i32) -> i32 {
1918
let ini_entries: Vec<IniEntryDef> = vec![
2019
IniEntryDef::new(
2120
"my_extension.display_emoji".to_owned(),
2221
"yes".to_owned(),
2322
IniEntryPermission::All,
2423
),
2524
];
26-
IniEntryDef::register(ini_entries, module_number);
25+
IniEntryDef::register(ini_entries, mod_num);
26+
27+
0
28+
}
29+
30+
#[php_module(startup = "startup")]
31+
pub fn get_module(module: ModuleBuilder) -> ModuleBuilder {
32+
module
2733
}
2834
# fn main() {}
2935
```
@@ -35,14 +41,22 @@ The INI values are stored as part of the `GlobalExecutor`, and can be accessed v
3541
```rust,no_run
3642
# #![cfg_attr(windows, feature(abi_vectorcall))]
3743
# extern crate ext_php_rs;
38-
# use ext_php_rs::prelude::*;
39-
# use ext_php_rs::zend::ExecutorGlobals;
44+
use ext_php_rs::{
45+
prelude::*,
46+
zend::ExecutorGlobals,
47+
};
4048
41-
#[php_startup]
42-
pub fn startup_function(ty: i32, module_number: i32) {
49+
pub fn startup(ty: i32, mod_num: i32) -> i32 {
4350
// Get all INI values
4451
let ini_values = ExecutorGlobals::get().ini_values(); // HashMap<String, Option<String>>
4552
let my_ini_value = ini_values.get("my_extension.display_emoji"); // Option<Option<String>>
53+
54+
0
55+
}
56+
57+
#[php_module(startup = "startup")]
58+
pub fn get_module(module: ModuleBuilder) -> ModuleBuilder {
59+
module
4660
}
4761
# fn main() {}
4862
```

guide/src/introduction.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ Our main goal is to **make extension development easier.**
3232
guaranteed while we are at major version `0`, which is for the foreseeable
3333
future. It's recommended to lock the version at the patch level.
3434

35+
When introducing breaking changes a migration guide will be provided in this
36+
guide.
37+
3538
## Documentation
3639

3740
- This guide!

guide/src/macros/async_impl.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
# `#[php_async_impl]`
1+
# `#[php_async_impl]` Attribute
22

3-
Using `#[php_async_impl]` instead of `#[php_impl]` allows us to expose any async Rust library to PHP, using [PHP fibers](https://www.php.net/manual/en/language.fibers.php), [php-tokio](https://github.com/danog/php-tokio) and the [PHP Revolt event loop](https://revolt.run) under the hood to handle async interoperability.
3+
Using `#[php_async_impl]` instead of `#[php_impl]` allows us to expose any async Rust library to PHP, using [PHP fibers](https://www.php.net/manual/en/language.fibers.php), [php-tokio](https://github.com/danog/php-tokio) and the [PHP Revolt event loop](https://revolt.run) under the hood to handle async interoperability.
44

55
This allows full compatibility with [amphp](https://amphp.org), [PSL](https://github.com/azjezz/psl), [reactphp](https://reactphp.org) and any other async PHP library based on [Revolt](https://revolt.run).
66

7-
Traits annotated with `#[php_async_impl]` can freely expose any async function, using `await` and any async Rust library.
7+
Traits annotated with `#[php_async_impl]` can freely expose any async function, using `await` and any async Rust library.
88

99
Make sure to also expose the `php_tokio::EventLoop::init` and `php_tokio::EventLoop::wakeup` functions to PHP in order to initialize the event loop, as specified in the full example [here &raquo;](#async-example).
1010

1111
Also, make sure to invoke `EventLoop::shutdown` in the request shutdown handler to clean up the tokio event loop before finishing the request.
1212

1313
## Async example
1414

15-
In this example, we're exposing an async Rust HTTP client library called [reqwest](https://docs.rs/reqwest/latest/reqwest/) to PHP, using [PHP fibers](https://www.php.net/manual/en/language.fibers.php), [php-tokio](https://github.com/danog/php-tokio) and the [PHP Revolt event loop](https://revolt.run) under the hood to handle async interoperability.
15+
In this example, we're exposing an async Rust HTTP client library called [reqwest](https://docs.rs/reqwest/latest/reqwest/) to PHP, using [PHP fibers](https://www.php.net/manual/en/language.fibers.php), [php-tokio](https://github.com/danog/php-tokio) and the [PHP Revolt event loop](https://revolt.run) under the hood to handle async interoperability.
1616

17-
This allows full compatibility with [amphp](https://amphp.org), [PSL](https://github.com/azjezz/psl), [reactphp](https://reactphp.org) and any other async PHP library based on [Revolt](https://revolt.run).
17+
This allows full compatibility with [amphp](https://amphp.org), [PSL](https://github.com/azjezz/psl), [reactphp](https://reactphp.org) and any other async PHP library based on [Revolt](https://revolt.run).
1818

1919
Make sure to require [php-tokio](https://github.com/danog/php-tokio) as a dependency before proceeding.
2020

@@ -49,11 +49,11 @@ pub fn get_module(module: ModuleBuilder) -> ModuleBuilder {
4949
}
5050
```
5151

52-
Here's the async PHP code we use to interact with the Rust class we just exposed.
52+
Here's the async PHP code we use to interact with the Rust class we just exposed.
5353

5454
The `Client::init` method needs to be called only once in order to initialize the Revolt event loop and link it to the Tokio event loop, as shown by the following code.
5555

56-
See [here &raquo;](https://amphp.org) for more info on async PHP using [amphp](https://amphp.org) + [revolt](https://revolt.run).
56+
See [here &raquo;](https://amphp.org) for more info on async PHP using [amphp](https://amphp.org) + [revolt](https://revolt.run).
5757

5858
```php
5959
<?php declare(strict_types=1);

0 commit comments

Comments
 (0)