Skip to content

[breaking] add argument and return value type-hints #187

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Mar 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/complex/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ pub fn get_module() -> Module {
// register functions
module
.add_function("complex_say_hello", say_hello)
.argument(Argument::by_val("name"));
.argument(Argument::new("name"));
module.add_function("complex_throw_exception", throw_exception);
module.add_function("complex_get_all_ini", |_: &mut [ZVal]| {
let mut arr = ZArray::new();
Expand Down Expand Up @@ -91,7 +91,7 @@ pub fn get_module() -> Module {
Ok(())
},
)
.argument(Argument::by_val("foo"));
.argument(Argument::new("foo"));
module.add_class(foo_class);

// register extra info
Expand Down
2 changes: 1 addition & 1 deletion examples/hello/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub fn get_module() -> Module {
// Register function `say_hello`, with one argument `name`.
module
.add_function("say_hello", say_hello)
.argument(Argument::by_val("name"));
.argument(Argument::new("name"));

module
}
8 changes: 4 additions & 4 deletions examples/http-client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub fn make_client_builder_class(client_class: ClientClass) -> ClassEntity<Clien
*state = builder.timeout(Duration::from_millis(ms as u64));
Ok::<_, phper::Error>(this.to_ref_owned())
})
.argument(Argument::by_val("ms"));
.argument(Argument::new("ms"));

// Inner call the `ClientBuilder::cookie_store`.
class
Expand All @@ -50,7 +50,7 @@ pub fn make_client_builder_class(client_class: ClientClass) -> ClassEntity<Clien
*state = builder.cookie_store(enable);
Ok::<_, phper::Error>(this.to_ref_owned())
})
.argument(Argument::by_val("enable"));
.argument(Argument::new("enable"));

// Inner call the `ClientBuilder::build`, and wrap the result `Client` in
// Object.
Expand Down Expand Up @@ -85,7 +85,7 @@ pub fn make_client_class(
*object.as_mut_state() = Some(request_builder);
Ok::<_, phper::Error>(object)
})
.argument(Argument::by_val("url"));
.argument(Argument::new("url"));

class
.add_method("post", Visibility::Public, move |this, arguments| {
Expand All @@ -96,7 +96,7 @@ pub fn make_client_class(
*object.as_mut_state() = Some(request_builder);
Ok::<_, phper::Error>(object)
})
.argument(Argument::by_val("url"));
.argument(Argument::new("url"));

class
}
6 changes: 3 additions & 3 deletions examples/http-server/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ pub fn make_response_class() -> ClassEntity<Response<Body>> {

Ok::<_, phper::Error>(())
})
.argument(Argument::by_val("name"))
.argument(Argument::by_val("value"));
.argument(Argument::new("name"))
.argument(Argument::new("value"));

// Register the end method with public visibility, accept `data` parameters.
class
Expand All @@ -54,7 +54,7 @@ pub fn make_response_class() -> ClassEntity<Response<Body>> {
*response.body_mut() = arguments[0].expect_z_str()?.to_bytes().to_vec().into();
Ok::<_, phper::Error>(())
})
.argument(Argument::by_val("data"));
.argument(Argument::new("data"));

class
}
4 changes: 2 additions & 2 deletions examples/http-server/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ pub fn make_server_class(

Ok::<_, phper::Error>(())
})
.arguments([Argument::by_val("host"), Argument::by_val("port")]);
.arguments([Argument::new("host"), Argument::new("port")]);

// Register the onRequest method, with public visibility, insert the handle into
// global ON_REQUEST_HANDLERS map.
Expand All @@ -80,7 +80,7 @@ pub fn make_server_class(
});
Ok::<_, phper::Error>(())
})
.argument(Argument::by_val("handle"));
.argument(Argument::new("handle"));

// Register the start method, with public visibility, this method will start and
// http server, listen on the addr, and block.
Expand Down
10 changes: 5 additions & 5 deletions examples/logging/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub fn get_module() -> Module {
echo!("Hello, {}!", message);
Ok(())
})
.argument(Argument::by_val("message"));
.argument(Argument::new("message"));

module
.add_function("log_notice", |params: &mut [ZVal]| -> phper::Result<()> {
Expand All @@ -45,7 +45,7 @@ pub fn get_module() -> Module {
notice!("Something happened: {}", message);
Ok(())
})
.argument(Argument::by_val("message"));
.argument(Argument::new("message"));

module
.add_function("log_warning", |params: &mut [ZVal]| -> phper::Result<()> {
Expand All @@ -58,7 +58,7 @@ pub fn get_module() -> Module {
warning!("Something warning: {}", message);
Ok(())
})
.argument(Argument::by_val("message"));
.argument(Argument::new("message"));

module
.add_function("log_error", |params: &mut [ZVal]| -> phper::Result<()> {
Expand All @@ -70,7 +70,7 @@ pub fn get_module() -> Module {
error!("Something gone failed: {}", message);
Ok(())
})
.argument(Argument::by_val("message"));
.argument(Argument::new("message"));

module
.add_function(
Expand All @@ -85,7 +85,7 @@ pub fn get_module() -> Module {
Ok(())
},
)
.argument(Argument::by_val("message"));
.argument(Argument::new("message"));

module
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ Full example is <https://github.com/phper-framework/phper/tree/master/examples/h
);

// Register function `say_hello`, with one argument `name`.
module.add_function("say_hello", say_hello).argument(Argument::by_val("name"));
module.add_function("say_hello", say_hello).argument(Argument::new("name"));

module
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ Now let's begin to finish the logic.
*state = builder.timeout(Duration::from_millis(ms as u64));
Ok::<_, phper::Error>(this.to_ref_owned())
})
.argument(Argument::by_val("ms"));
.argument(Argument::new("ms"));

// Inner call the `ClientBuilder::cookie_store`.
class
Expand All @@ -222,7 +222,7 @@ Now let's begin to finish the logic.
*state = builder.cookie_store(enable);
Ok::<_, phper::Error>(this.to_ref_owned())
})
.argument(Argument::by_val("enable"));
.argument(Argument::new("enable"));

// Inner call the `ClientBuilder::build`, and wrap the result `Client` in
// Object.
Expand Down
45 changes: 43 additions & 2 deletions phper-doc/doc/_06_module/_02_register_functions/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub fn get_module() -> Module {
let name = arguments[0].expect_z_str()?.to_str()?;
echo!("Hello, {}!\n", name);
Ok(())
}).argument(Argument::by_val("name"));
}).argument(Argument::new("name"));

module
}
Expand Down Expand Up @@ -71,7 +71,7 @@ pub fn get_module() -> Module {
let count = arguments[0].expect_mut_z_ref()?;
*count.val_mut().expect_mut_long()? += 100;
Ok(())
}).argument(Argument::by_ref("count"));
}).argument(Argument::new("count").by_ref());

module
}
Expand All @@ -80,3 +80,44 @@ pub fn get_module() -> Module {
Here, the argument is registered as
[`Argument::by_ref`](phper::functions::Argument::by_ref). Therefore, the type of
the `count` parameter is no longer long, but a reference.

## Argument and return type modifiers

Arguments can have type-hints, nullability and default values applied. Here we define a function that accepts
a nullable class (in this case, an interface), and a string with a default value:

```rust,no_run
use phper::{modules::Module, php_get_module, functions::Argument, echo};
use phper::types::ArgumentTypeHint;

#[php_get_module]
pub fn get_module() -> Module {
let mut module = Module::new(
env!("CARGO_CRATE_NAME"),
env!("CARGO_PKG_VERSION"),
env!("CARGO_PKG_AUTHORS"),
);

module.add_function("my_function", |_| -> phper::Result<()> {
Ok(())
})
.argument(Argument::new("a_class").with_type_hint(ArgumentTypeHint::ClassEntry(String::from(r"\MyNamespace\MyInterface"))).allow_null())
.argument(Argument::new("name").with_type_hint(ArgumentTypeHint::String).with_default_value("'my_default'"))
.argument(Argument::new("optional_bool").with_type_hint(ArgumentTypeHint::Bool).optional());

module
}
```

The output of `php --re` for this function would look like:

```txt
Function [ <internal:integration> function my_function ] {

- Parameters [3] {
Parameter #0 [ <required> ?class_name $a_class ]
Parameter #1 [ <optional> string $name = 'my_default' ]
Parameter #2 [ <optional> bool $optional_bool = <default> ]
}
}
```
28 changes: 25 additions & 3 deletions phper-doc/doc/_06_module/_06_register_class/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,29 @@ foo.add_static_method(
let name = arguments[0].expect_z_str()?.to_str()?;
Ok::<_, phper::Error>(format!("Hello, {}!\n", name))
},
).argument(Argument::by_val("name"));
).argument(Argument::new("name"));
```

## Argument and return type modifiers

Methods may add argument and return typehints as per functions. For example:

```rust,no_run
use phper::classes::{ClassEntity, ClassEntry, Visibility};
use phper::functions::{Argument, ReturnType};
use phper::types::{ArgumentTypeHint, ReturnTypeHint};

let mut foo = ClassEntity::new("Foo");
foo.add_method(
"test",
Visibility::Public,
|_this, _arguments| -> phper::Result<()> {
Ok(())
},
)
.argument(Argument::new("a_string").with_type_hint(ArgumentTypeHint::String))
.argument(Argument::new("an_interface").with_type_hint(ArgumentTypeHint::ClassEntry(String::from(r"\MyNamespace\MyInterface"))))
.return_type(ReturnType::new(ReturnTypeHint::Bool).allow_null());
```

## Add constants
Expand Down Expand Up @@ -148,8 +170,8 @@ class.add_method(
Ok::<_, phper::Error>(())
},
)
.argument(Argument::by_val("key"))
.argument(Argument::by_val("value"));
.argument(Argument::new("key"))
.argument(Argument::new("value"));
```

Equivalent to the following PHP code (hides the implementation details):
Expand Down
2 changes: 1 addition & 1 deletion phper-doc/doc/_06_module/_07_register_interface/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ use phper::objects::StateObj;
use phper::values::ZVal;

let mut foo = InterfaceEntity::new("Foo");
foo.add_method("doSomethings").argument(Argument::by_val("name"));
foo.add_method("doSomethings").argument(Argument::new("name"));
```

Note that abstract has no method body, so you don't need to add the handler to the method.
Expand Down
Loading
Loading