Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
42 changes: 42 additions & 0 deletions phper-doc/doc/_06_module/_02_register_functions/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,45 @@ 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;
use std::ffi::CString;

#[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::by_val("a_class").with_type_hint(ArgumentTypeHint::ClassEntry(String::from(r"\MyNamespace\MyInterface"))).allow_null())
.argument(Argument::by_val("name").with_type_hint(ArgumentTypeHint::String).with_default_value(CString::new("'my_default'").unwrap()))
.argument(Argument::by_val("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> ]
}
}
```
22 changes: 22 additions & 0 deletions phper-doc/doc/_06_module/_06_register_class/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,28 @@ foo.add_static_method(
).argument(Argument::by_val("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::by_val("a_string").with_type_hint(ArgumentTypeHint::String))
.argument(Argument::by_val("an_interface").with_type_hint(ArgumentTypeHint::ClassEntry(String::from(r"\MyNamespace\MyInterface"))))
.return_type(ReturnType::by_val(ReturnTypeHint::Bool).allow_null());
```

## Add constants
Interfaces can have public constants. Value can be string|int|bool|float|null.

Expand Down
51 changes: 51 additions & 0 deletions phper-sys/php_wrapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -480,8 +480,59 @@ phper_zend_begin_arg_with_return_type_info_ex(bool return_reference,
#undef const
}

zend_internal_arg_info
phper_zend_begin_arg_with_return_obj_info_ex(bool return_reference,
uintptr_t required_num_args,
const char* class_name,
bool allow_null) {
#define static
#define const
#if PHP_VERSION_ID >= 70200
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(info, return_reference,
required_num_args,
class_name, allow_null)
#else
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(
info, return_reference, required_num_args,
class_name, NULL, allow_null)
#endif
ZEND_END_ARG_INFO()
return info[0];
#undef static
#undef const
}

zend_internal_arg_info phper_zend_arg_info(bool pass_by_ref, const char *name) {
zend_internal_arg_info info[] = {ZEND_ARG_INFO(pass_by_ref, )};
info[0].name = name;
return info[0];
}

zend_internal_arg_info phper_zend_arg_info_with_type(bool pass_by_ref,
const char *name,
uint32_t type_hint,
bool allow_null,
const char *default_value) {
#if PHP_VERSION_ID >= 70200
zend_internal_arg_info info[] = {
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(pass_by_ref, , type_hint, allow_null, default_value)
};
#else
zend_internal_arg_info info[] = {
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(pass_by_ref, , type_hint, NULL, allow_null, default_value)
};
#endif
info[0].name = name;
return info[0];
}

zend_internal_arg_info phper_zend_arg_obj_info(bool pass_by_ref,
const char *name,
const char *class_name,
bool allow_null) {
zend_internal_arg_info info[] = {
ZEND_ARG_OBJ_INFO(pass_by_ref, , class_name, allow_null)
};
info[0].name = name;
return info[0];
}
10 changes: 10 additions & 0 deletions phper/src/classes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use std::{
marker::PhantomData,
mem::{ManuallyDrop, replace, size_of, zeroed},
os::raw::c_int,
ptr,
ptr::null_mut,
rc::Rc,
slice,
Expand All @@ -48,6 +49,7 @@ pub fn array_access_class<'a>() -> &'a ClassEntry {
}

/// Wrapper of [zend_class_entry].
#[derive(Clone)]
#[repr(transparent)]
pub struct ClassEntry {
inner: zend_class_entry,
Expand Down Expand Up @@ -221,6 +223,14 @@ impl Debug for ClassEntry {
}
}

impl PartialEq for ClassEntry {
fn eq(&self, other: &Self) -> bool {
ptr::eq(self as *const _, other as *const _)
}
}

impl Eq for ClassEntry {}

#[allow(clippy::useless_conversion)]
fn find_global_class_entry_ptr(name: impl AsRef<str>) -> *mut zend_class_entry {
let name = name.as_ref();
Expand Down
Loading
Loading