Skip to content

Commit d8a5a09

Browse files
committed
Cleanup docs
1 parent c87dc4b commit d8a5a09

File tree

3 files changed

+134
-134
lines changed

3 files changed

+134
-134
lines changed

guide/src/SUMMARY.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,14 @@
2424
- [Class Object](./types/class_object.md)
2525
- [Closure](./types/closure.md)
2626
- [Functions & methods](./types/functions.md)
27-
- [Async futures](./macros/impl.md#async)
27+
- [Async futures](./macros/async_impl.md)
2828
- [Macros](./macros/index.md)
2929
- [Module](./macros/module.md)
3030
- [Module Startup Function](./macros/module_startup.md)
3131
- [Function](./macros/function.md)
3232
- [Classes](./macros/classes.md)
3333
- [`impl`s](./macros/impl.md)
34+
- [async `impl`s](./macros/async_impl.md)
3435
- [Constants](./macros/constant.md)
3536
- [`ZvalConvert`](./macros/zval_convert.md)
3637
- [Exceptions](./exceptions.md)

guide/src/macros/async_impl.md

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# `#[php_async_impl]`
2+
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.
4+
5+
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).
6+
7+
Traits annotated with `#[php_impl]` can freely expose any async function, using `await` and any async Rust library.
8+
9+
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 »](#async-example).
10+
11+
Also, make sure to invoke `EventLoop::shutdown` in the request shutdown handler to clean up the tokio event loop before finishing the request.
12+
13+
## Async example
14+
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.
16+
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).
18+
19+
Make sure to require [php-tokio](https://github.com/danog/php-tokio) as a dependency before proceeding.
20+
21+
```rust,ignore
22+
use ext_php_rs::prelude::*;
23+
use php_tokio::{php_async_impl, EventLoop};
24+
25+
#[php_class]
26+
struct Client {}
27+
28+
#[php_async_impl]
29+
impl Client {
30+
pub fn init() -> PhpResult<u64> {
31+
EventLoop::init()
32+
}
33+
pub fn wakeup() -> PhpResult<()> {
34+
EventLoop::wakeup()
35+
}
36+
pub async fn get(url: &str) -> anyhow::Result<String> {
37+
Ok(reqwest::get(url).await?.text().await?)
38+
}
39+
}
40+
41+
pub extern "C" fn request_shutdown(_type: i32, _module_number: i32) -> i32 {
42+
EventLoop::shutdown();
43+
0
44+
}
45+
46+
#[php_module]
47+
pub fn get_module(module: ModuleBuilder) -> ModuleBuilder {
48+
module.request_shutdown_function(request_shutdown)
49+
}
50+
```
51+
52+
Here's the async PHP code we use to interact with the Rust class we just exposed.
53+
54+
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.
55+
56+
See [here &raquo;](https://amphp.org) for more info on async PHP using [amphp](https://amphp.org) + [revolt](https://revolt.run).
57+
58+
```php
59+
<?php declare(strict_types=1);
60+
61+
namespace Reqwest;
62+
63+
use Revolt\EventLoop;
64+
65+
use function Amp\async;
66+
use function Amp\Future\await;
67+
68+
final class Client
69+
{
70+
private static ?string $id = null;
71+
72+
public static function init(): void
73+
{
74+
if (self::$id !== null) {
75+
return;
76+
}
77+
78+
$f = \fopen("php://fd/".\Client::init(), 'r+');
79+
\stream_set_blocking($f, false);
80+
self::$id = EventLoop::onReadable($f, fn () => \Client::wakeup());
81+
}
82+
83+
public static function reference(): void
84+
{
85+
EventLoop::reference(self::$id);
86+
}
87+
public static function unreference(): void
88+
{
89+
EventLoop::unreference(self::$id);
90+
}
91+
92+
public static function __callStatic(string $name, array $args): mixed
93+
{
94+
return \Client::$name(...$args);
95+
}
96+
}
97+
98+
99+
Client::init();
100+
101+
function test(int $delay): void
102+
{
103+
$url = "https://httpbin.org/delay/$delay";
104+
$t = time();
105+
echo "Making async reqwest to $url that will return after $delay seconds...".PHP_EOL;
106+
Client::get($url);
107+
$t = time() - $t;
108+
echo "Got response from $url after ~".$t." seconds!".PHP_EOL;
109+
};
110+
111+
$futures = [];
112+
$futures []= async(test(...), 5);
113+
$futures []= async(test(...), 5);
114+
$futures []= async(test(...), 5);
115+
116+
await($futures);
117+
```
118+
119+
Result:
120+
121+
```
122+
Making async reqwest to https://httpbin.org/delay/5 that will return after 5 seconds...
123+
Making async reqwest to https://httpbin.org/delay/5 that will return after 5 seconds...
124+
Making async reqwest to https://httpbin.org/delay/5 that will return after 5 seconds...
125+
Got response from https://httpbin.org/delay/5 after ~5 seconds!
126+
Got response from https://httpbin.org/delay/5 after ~5 seconds!
127+
Got response from https://httpbin.org/delay/5 after ~5 seconds!
128+
```
129+
130+
[`php_function`]: ./function.md

guide/src/macros/impl.md

Lines changed: 2 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ implementations cannot be exported to PHP.
88
If you do not want a function exported to PHP, you should place it in a separate
99
`impl` block.
1010

11-
If you want to use async Rust, use `#[php_async_impl]`, instead: see [here &raquo;](#async) for more info.
11+
If you want to use async Rust, use `#[php_async_impl]`, instead: see [here &raquo;](./async_impl.md) for more info.
1212

1313
## Methods
1414

@@ -65,20 +65,6 @@ the attribute, the function is not exported to PHP like a regular method.
6565

6666
Constructors cannot use the visibility or rename attributes listed above.
6767

68-
### Async
69-
70-
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.
71-
72-
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).
73-
74-
Traits annotated with `#[php_impl]` can freely expose any async function, using `await` and any async Rust library.
75-
76-
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).
77-
78-
Also, make sure to invoke `EventLoop::shutdown` in the request shutdown handler to clean up the tokio event loop before finishing the request.
79-
80-
See [here &raquo;](#async-example) for the full example.
81-
8268
## Constants
8369

8470
Constants are defined as regular Rust `impl` constants. Any type that implements
@@ -178,121 +164,4 @@ var_dump(Human::get_max_age()); // int(100)
178164
var_dump(Human::MAX_AGE); // int(100)
179165
```
180166

181-
### Async example
182-
183-
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.
184-
185-
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).
186-
187-
Make sure to require [php-tokio](https://github.com/danog/php-tokio) as a dependency before proceeding.
188-
189-
```rust,ignore
190-
use ext_php_rs::prelude::*;
191-
use php_tokio::{php_async_impl, EventLoop};
192-
193-
#[php_class]
194-
struct Client {}
195-
196-
#[php_async_impl]
197-
impl Client {
198-
pub fn init() -> PhpResult<u64> {
199-
EventLoop::init()
200-
}
201-
pub fn wakeup() -> PhpResult<()> {
202-
EventLoop::wakeup()
203-
}
204-
pub async fn get(url: &str) -> anyhow::Result<String> {
205-
Ok(reqwest::get(url).await?.text().await?)
206-
}
207-
}
208-
209-
pub extern "C" fn request_shutdown(_type: i32, _module_number: i32) -> i32 {
210-
EventLoop::shutdown();
211-
0
212-
}
213-
214-
#[php_module]
215-
pub fn get_module(module: ModuleBuilder) -> ModuleBuilder {
216-
module.request_shutdown_function(request_shutdown)
217-
}
218-
```
219-
220-
Here's the async PHP code we use to interact with the Rust class we just exposed.
221-
222-
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.
223-
224-
See [here &raquo;](https://amphp.org) for more info on async PHP using [amphp](https://amphp.org) + [revolt](https://revolt.run).
225-
226-
```php
227-
<?php declare(strict_types=1);
228-
229-
namespace Reqwest;
230-
231-
use Revolt\EventLoop;
232-
233-
use function Amp\async;
234-
use function Amp\Future\await;
235-
236-
final class Client
237-
{
238-
private static ?string $id = null;
239-
240-
public static function init(): void
241-
{
242-
if (self::$id !== null) {
243-
return;
244-
}
245-
246-
$f = \fopen("php://fd/".\Client::init(), 'r+');
247-
\stream_set_blocking($f, false);
248-
self::$id = EventLoop::onReadable($f, fn () => \Client::wakeup());
249-
}
250-
251-
public static function reference(): void
252-
{
253-
EventLoop::reference(self::$id);
254-
}
255-
public static function unreference(): void
256-
{
257-
EventLoop::unreference(self::$id);
258-
}
259-
260-
public static function __callStatic(string $name, array $args): mixed
261-
{
262-
return \Client::$name(...$args);
263-
}
264-
}
265-
266-
267-
Client::init();
268-
269-
function test(int $delay): void
270-
{
271-
$url = "https://httpbin.org/delay/$delay";
272-
$t = time();
273-
echo "Making async reqwest to $url that will return after $delay seconds...".PHP_EOL;
274-
Client::get($url);
275-
$t = time() - $t;
276-
echo "Got response from $url after ~".$t." seconds!".PHP_EOL;
277-
};
278-
279-
$futures = [];
280-
$futures []= async(test(...), 5);
281-
$futures []= async(test(...), 5);
282-
$futures []= async(test(...), 5);
283-
284-
await($futures);
285-
```
286-
287-
Result:
288-
289-
```
290-
Making async reqwest to https://httpbin.org/delay/5 that will return after 5 seconds...
291-
Making async reqwest to https://httpbin.org/delay/5 that will return after 5 seconds...
292-
Making async reqwest to https://httpbin.org/delay/5 that will return after 5 seconds...
293-
Got response from https://httpbin.org/delay/5 after ~5 seconds!
294-
Got response from https://httpbin.org/delay/5 after ~5 seconds!
295-
Got response from https://httpbin.org/delay/5 after ~5 seconds!
296-
```
297-
298-
[`php_function`]: ./function.md
167+
[`php_async_impl`]: ./async_impl.md

0 commit comments

Comments
 (0)