Skip to content

Commit 945c946

Browse files
committed
docs(macro): update documentation for builder pattern
1 parent 6786183 commit 945c946

File tree

20 files changed

+413
-170
lines changed

20 files changed

+413
-170
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/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/classes.md

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,10 @@ There are also additional macros that modify the class. These macros **must** be
1616
placed underneath the `#[php_class]` attribute.
1717

1818
- `#[extends(ce)]` - Sets the parent class of the class. Can only be used once.
19-
`ce` must be a valid Rust expression when it is called inside the
20-
`#[php_module]` function.
19+
`ce` must be a function with the signature `fn() -> &'static ClassEntry`.
2120
- `#[implements(ce)]` - Implements the given interface on the class. Can be used
22-
multiple times. `ce` must be a valid Rust expression when it is called inside
23-
the `#[php_module]` function.
21+
multiple times. `ce` must be a valid function with the signature
22+
`fn() -> &'static ClassEntry`.
2423

2524
You may also use the `#[prop]` attribute on a struct field to use the field as a
2625
PHP property. By default, the field will be accessible from PHP publicly with
@@ -67,18 +66,20 @@ This example creates a PHP class `Human`, adding a PHP property `address`.
6766
```rust,no_run
6867
# #![cfg_attr(windows, feature(abi_vectorcall))]
6968
# extern crate ext_php_rs;
70-
# use ext_php_rs::prelude::*;
69+
use ext_php_rs::prelude::*;
70+
7171
#[php_class]
7272
pub struct Human {
7373
name: String,
7474
age: i32,
7575
#[prop]
7676
address: String,
7777
}
78-
# #[php_module]
79-
# pub fn get_module(module: ModuleBuilder) -> ModuleBuilder {
80-
# module
81-
# }
78+
79+
#[php_module]
80+
pub fn get_module(module: ModuleBuilder) -> ModuleBuilder {
81+
module.class::<Human>()
82+
}
8283
# fn main() {}
8384
```
8485

@@ -88,11 +89,14 @@ it in the `Redis\Exception` namespace:
8889
```rust,no_run
8990
# #![cfg_attr(windows, feature(abi_vectorcall))]
9091
# extern crate ext_php_rs;
91-
use ext_php_rs::prelude::*;
92-
use ext_php_rs::{exception::PhpException, zend::ce};
92+
use ext_php_rs::{
93+
prelude::*,
94+
exception::PhpException,
95+
zend::ce
96+
};
9397
9498
#[php_class(name = "Redis\\Exception\\RedisException")]
95-
#[extends(ce::exception())]
99+
#[extends(ce::exception)]
96100
#[derive(Default)]
97101
pub struct RedisException;
98102
@@ -101,25 +105,33 @@ pub struct RedisException;
101105
pub fn throw_exception() -> PhpResult<i32> {
102106
Err(PhpException::from_class::<RedisException>("Not good!".into()))
103107
}
104-
# #[php_module]
105-
# pub fn get_module(module: ModuleBuilder) -> ModuleBuilder {
106-
# module
107-
# }
108+
109+
#[php_module]
110+
pub fn get_module(module: ModuleBuilder) -> ModuleBuilder {
111+
module
112+
.class::<RedisException>()
113+
.function(wrap_function!(throw_exception))
114+
}
108115
# fn main() {}
109116
```
110117

111118
## Implementing an Interface
112119

113-
To implement an interface, use `#[implements(ce)]` where `ce` is an expression returning a `ClassEntry`.
120+
To implement an interface, use `#[implements(ce)]` where `ce` is an function returning a `ClassEntry`.
114121
The following example implements [`ArrayAccess`](https://www.php.net/manual/en/class.arrayaccess.php):
115-
```rust,no_run
122+
123+
````rust,no_run
116124
# #![cfg_attr(windows, feature(abi_vectorcall))]
117125
# extern crate ext_php_rs;
118-
use ext_php_rs::prelude::*;
119-
use ext_php_rs::{exception::PhpResult, types::Zval, zend::ce};
126+
use ext_php_rs::{
127+
prelude::*,
128+
exception::PhpResult,
129+
types::Zval,
130+
zend::ce,
131+
};
120132
121133
#[php_class]
122-
#[implements(ce::arrayaccess())]
134+
#[implements(ce::arrayaccess)]
123135
#[derive(Default)]
124136
pub struct EvenNumbersArray;
125137
@@ -154,9 +166,10 @@ impl EvenNumbersArray {
154166
Err("Setting values is not supported".into())
155167
}
156168
}
157-
# #[php_module]
158-
# pub fn get_module(module: ModuleBuilder) -> ModuleBuilder {
159-
# module
160-
# }
169+
170+
#[php_module]
171+
pub fn get_module(module: ModuleBuilder) -> ModuleBuilder {
172+
module.class::<EvenNumbersArray>()
173+
}
161174
# fn main() {}
162-
```
175+
````

0 commit comments

Comments
 (0)