Skip to content

Commit 2cd365a

Browse files
authored
Add crate phper-doc for documentation purpose. (#72)
1 parent 8f58b49 commit 2cd365a

File tree

23 files changed

+613
-142
lines changed

23 files changed

+613
-142
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ members = [
1616
"phper-macros",
1717
"phper-sys",
1818
"phper-test",
19+
"phper-doc",
1920

2021
# internal
2122
"examples/complex",

README.md

Lines changed: 6 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,16 @@
1010

1111
The framework that allows us to write PHP extensions using pure and safe Rust whenever possible.
1212

13+
## Document & Tutorial
14+
15+
- Document: <https://docs.rs/phper>
16+
- Tutorial: <https://docs.rs/phper-doc/>
17+
1318
## Requirement
1419

1520
### Necessary
1621

17-
- **rust** 1.56 or later
22+
- **rust** 1.65 or later
1823
- **libclang** 9.0 or later
1924
- **php** 7.0 or later
2025

@@ -43,83 +48,6 @@ The framework that allows us to write PHP extensions using pure and safe Rust wh
4348
- [x] disable
4449
- [ ] enable
4550

46-
## Usage
47-
48-
1. Make sure `libclang` and `php` is installed.
49-
50-
```bash
51-
# If you are using debian like linux system:
52-
sudo apt install llvm-10-dev libclang-10-dev php-cli
53-
```
54-
55-
1. Create you cargo project, suppose your application is called myapp.
56-
57-
```bash
58-
cargo new myapp
59-
```
60-
61-
1. Add the dependencies and metadata to you Cargo project.
62-
63-
```toml
64-
[lib]
65-
crate-type = ["cdylib"]
66-
67-
[dependencies]
68-
phper = "<LATEST VERSION>"
69-
```
70-
71-
1. Create the `build.rs` ( Adapting MacOS ).
72-
73-
```rust,no_run
74-
fn main() {
75-
#[cfg(target_os = "macos")]
76-
{
77-
println!("cargo:rustc-link-arg=-undefined");
78-
println!("cargo:rustc-link-arg=dynamic_lookup");
79-
}
80-
}
81-
```
82-
83-
1. Write you owned extension logic in `lib.rs`.
84-
85-
```rust
86-
use phper::{php_get_module, modules::Module};
87-
88-
#[php_get_module]
89-
pub fn get_module() -> Module {
90-
let mut module = Module::new(
91-
env!("CARGO_CRATE_NAME"),
92-
env!("CARGO_PKG_VERSION"),
93-
env!("CARGO_PKG_AUTHORS"),
94-
);
95-
96-
// ...
97-
98-
module
99-
}
100-
```
101-
102-
1. Build and install, if your php isn't installed globally, you should specify the path of `php-config`.
103-
104-
```bash
105-
# Optional, specify if php isn't installed globally.
106-
# export PHP_CONFIG=<Your path of php-config>
107-
108-
# Build libmyapp.so.
109-
cargo build --release
110-
111-
# Install to php extension path.
112-
cp target/release/libmyapp.so `${PHP_CONFIG:=php-config} --extension-dir`
113-
```
114-
115-
1. Edit your `php.ini`, add the below line.
116-
117-
```ini
118-
extension = myapp
119-
```
120-
121-
1. Enjoy.
122-
12351
## Examples
12452

12553
See [examples](https://github.com/phper-framework/phper/tree/master/examples).

examples/http-client/Cargo.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@ license = { workspace = true }
2121
crate-type = ["lib", "cdylib"]
2222

2323
[dependencies]
24-
anyhow = "1.0.66"
25-
bytes = "1.3.0"
26-
indexmap = "1.9.2"
2724
phper = { version = "0.6.0", path = "../../phper" }
2825
reqwest = { version = "0.11.13", features = ["blocking", "cookies"] }
2926
thiserror = "1.0.37"

examples/http-client/src/client.rs

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,57 +8,59 @@
88
// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
99
// See the Mulan PSL v2 for more details.
1010

11-
use crate::{
12-
errors::HttpClientError,
13-
request::REQUEST_BUILDER_CLASS_NAME,
14-
utils::{replace_and_get, replace_and_set},
15-
};
11+
use crate::{errors::HttpClientError, request::REQUEST_BUILDER_CLASS_NAME};
1612
use phper::{
1713
alloc::ToRefOwned,
1814
classes::{ClassEntry, StatefulClass, Visibility},
1915
functions::Argument,
2016
};
2117
use reqwest::blocking::{Client, ClientBuilder};
22-
use std::time::Duration;
18+
use std::{mem::take, time::Duration};
2319

2420
const HTTP_CLIENT_BUILDER_CLASS_NAME: &str = "HttpClient\\HttpClientBuilder";
2521
const HTTP_CLIENT_CLASS_NAME: &str = "HttpClient\\HttpClient";
2622

2723
pub fn make_client_builder_class() -> StatefulClass<ClientBuilder> {
24+
// `new_with_default_state` means initialize the state of `ClientBuilder` as
25+
// `Default::default`.
2826
let mut class = StatefulClass::new_with_default_state(HTTP_CLIENT_BUILDER_CLASS_NAME);
2927

28+
// Inner call the `ClientBuilder::timeout`.
3029
class.add_method(
3130
"timeout",
3231
Visibility::Public,
3332
|this, arguments| {
3433
let ms = arguments[0].expect_long()?;
35-
let state: &mut ClientBuilder = this.as_mut_state();
36-
replace_and_set(state, |builder| {
37-
builder.timeout(Duration::from_millis(ms as u64))
38-
});
34+
let state = this.as_mut_state();
35+
let builder: ClientBuilder = take(state);
36+
*state = builder.timeout(Duration::from_millis(ms as u64));
3937
Ok::<_, HttpClientError>(this.to_ref_owned())
4038
},
4139
vec![Argument::by_val("ms")],
4240
);
4341

42+
// Inner call the `ClientBuilder::cookie_store`.
4443
class.add_method(
4544
"cookie_store",
4645
Visibility::Public,
4746
|this, arguments| {
4847
let enable = arguments[0].expect_bool()?;
49-
let state: &mut ClientBuilder = this.as_mut_state();
50-
replace_and_set(state, |builder| builder.cookie_store(enable));
48+
let state = this.as_mut_state();
49+
let builder: ClientBuilder = take(state);
50+
*state = builder.cookie_store(enable);
5151
Ok::<_, HttpClientError>(this.to_ref_owned())
5252
},
5353
vec![Argument::by_val("enable")],
5454
);
5555

56+
// Inner call the `ClientBuilder::build`, and wrap the result `Client` in
57+
// Object.
5658
class.add_method(
5759
"build",
5860
Visibility::Public,
5961
|this, _arguments| {
60-
let state = this.as_mut_state();
61-
let client = replace_and_get(state, ClientBuilder::build)?;
62+
let state = take(this.as_mut_state());
63+
let client = ClientBuilder::build(state)?;
6264
let mut object = ClassEntry::from_globals(HTTP_CLIENT_CLASS_NAME)?.init_object()?;
6365
unsafe {
6466
*object.as_mut_state() = Some(client);
@@ -80,7 +82,7 @@ pub fn make_client_class() -> StatefulClass<Option<Client>> {
8082
"get",
8183
Visibility::Public,
8284
|this, arguments| {
83-
let url = arguments[0].as_z_str().unwrap().to_str().unwrap();
85+
let url = arguments[0].expect_z_str()?.to_str().unwrap();
8486
let client = this.as_state().as_ref().unwrap();
8587
let request_builder = client.get(url);
8688
let mut object = ClassEntry::from_globals(REQUEST_BUILDER_CLASS_NAME)?.init_object()?;
@@ -96,7 +98,7 @@ pub fn make_client_class() -> StatefulClass<Option<Client>> {
9698
"post",
9799
Visibility::Public,
98100
|this, arguments| {
99-
let url = arguments[0].as_z_str().unwrap().to_str().unwrap();
101+
let url = arguments[0].expect_z_str()?.to_str().unwrap();
100102
let client = this.as_state().as_ref().unwrap();
101103
let request_builder = client.post(url);
102104
let mut object = ClassEntry::from_globals(REQUEST_BUILDER_CLASS_NAME)?.init_object()?;

examples/http-client/src/errors.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@
1010

1111
use phper::classes::{ClassEntry, StatefulClass};
1212

13+
/// The exception class name of extension.
1314
const EXCEPTION_CLASS_NAME: &str = "HttpClient\\HttpClientException";
1415

16+
/// The struct implemented `phper::Throwable` will throw php Exception
17+
/// when return as `Err(e)` in extension functions.
1518
#[derive(Debug, thiserror::Error, phper::Throwable)]
1619
#[throwable_class(EXCEPTION_CLASS_NAME)]
1720
pub enum HttpClientError {
21+
/// Generally, implement `From` for `phper::Error`.
1822
#[error(transparent)]
1923
#[throwable(transparent)]
2024
Phper(#[from] phper::Error),
@@ -31,6 +35,7 @@ pub enum HttpClientError {
3135

3236
pub fn make_exception_class() -> StatefulClass<()> {
3337
let mut exception_class = StatefulClass::new(EXCEPTION_CLASS_NAME);
38+
// The `extends` is same as the PHP class `extends`.
3439
exception_class.extends("Exception");
3540
exception_class
3641
}

examples/http-client/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ pub mod client;
2020
pub mod errors;
2121
pub mod request;
2222
pub mod response;
23-
pub mod utils;
2423

2524
#[php_get_module]
2625
pub fn get_module() -> Module {

examples/http-client/src/request.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
99
// See the Mulan PSL v2 for more details.
1010

11-
use crate::{errors::HttpClientError, response::RESPONSE_CLASS_NAME, utils::replace_and_get};
11+
use crate::{errors::HttpClientError, response::RESPONSE_CLASS_NAME};
1212
use phper::classes::{ClassEntry, StatefulClass, Visibility};
1313
use reqwest::blocking::RequestBuilder;
14+
use std::mem::take;
1415

1516
pub const REQUEST_BUILDER_CLASS_NAME: &str = "HttpClient\\RequestBuilder";
1617

@@ -24,8 +25,8 @@ pub fn make_request_builder_class() -> StatefulClass<Option<RequestBuilder>> {
2425
"send",
2526
Visibility::Public,
2627
|this, _arguments| {
27-
let state = this.as_mut_state();
28-
let response = replace_and_get(state, |builder| builder.unwrap().send())?;
28+
let state = take(this.as_mut_state());
29+
let response = state.unwrap().send()?;
2930
let mut object = ClassEntry::from_globals(RESPONSE_CLASS_NAME)?.new_object([])?;
3031
unsafe {
3132
*object.as_mut_state() = Some(response);

examples/http-client/src/response.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@
88
// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
99
// See the Mulan PSL v2 for more details.
1010

11-
use crate::{errors::HttpClientError, utils::replace_and_get};
11+
use crate::errors::HttpClientError;
1212
use phper::{
1313
arrays::{InsertKey, ZArray},
1414
classes::{StatefulClass, Visibility},
1515
values::ZVal,
1616
};
1717
use reqwest::blocking::Response;
18+
use std::mem::take;
1819

1920
pub const RESPONSE_CLASS_NAME: &str = "HttpClient\\Response";
2021

@@ -25,12 +26,10 @@ pub fn make_response_class() -> StatefulClass<Option<Response>> {
2526
"body",
2627
Visibility::Public,
2728
|this, _arguments| {
28-
let response = this.as_mut_state();
29-
let body = replace_and_get(response, |response| {
30-
response
31-
.ok_or(HttpClientError::ResponseHadRead)
32-
.and_then(|response| response.bytes().map_err(Into::into))
33-
})?;
29+
let response = take(this.as_mut_state());
30+
let body = response
31+
.ok_or(HttpClientError::ResponseHadRead)
32+
.and_then(|response| response.bytes().map_err(Into::into))?;
3433
Ok::<_, HttpClientError>(body.to_vec())
3534
},
3635
vec![],

examples/http-client/src/utils.rs

Lines changed: 0 additions & 20 deletions
This file was deleted.

phper-alloc/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@
1010

1111
[package]
1212
name = "phper-alloc"
13+
description = "Alloc related items for phper crate."
14+
keywords = ["php", "alloc"]
1315
version = { workspace = true }
1416
authors = { workspace = true }
1517
edition = { workspace = true }
1618
rust-version = { workspace = true }
17-
description = "Alloc related items for phper crate."
1819
repository = { workspace = true }
1920
license = { workspace = true }
20-
keywords = ["php", "alloc"]
2121

2222
[dependencies]
2323
phper-sys = { version = "0.6.0", path = "../phper-sys" }

0 commit comments

Comments
 (0)