diff --git a/build.rs b/build.rs index bcaabb4161..5232564972 100644 --- a/build.rs +++ b/build.rs @@ -16,7 +16,7 @@ use bindgen::RustTarget; use impl_::Provider; const MIN_PHP_API_VER: u32 = 20200930; -const MAX_PHP_API_VER: u32 = 20230831; +const MAX_PHP_API_VER: u32 = 20240924; pub trait PHPProvider<'a>: Sized { /// Create a new PHP provider. @@ -230,7 +230,11 @@ fn check_php_version(info: &PHPInfo) -> Result<()> { const PHP_83_API_VER: u32 = 20230831; - println!("cargo::rustc-check-cfg=cfg(php80, php81, php82, php83, php_zts, php_debug, docs)"); + const PHP_84_API_VER: u32 = 20240924; + + println!( + "cargo::rustc-check-cfg=cfg(php80, php81, php82, php83, php84, php_zts, php_debug, docs)" + ); println!("cargo:rustc-cfg=php80"); if (PHP_81_API_VER..PHP_82_API_VER).contains(&version) { @@ -245,6 +249,10 @@ fn check_php_version(info: &PHPInfo) -> Result<()> { println!("cargo:rustc-cfg=php83"); } + if version >= PHP_84_API_VER { + println!("cargo:rustc-cfg=php84"); + } + Ok(()) } diff --git a/crates/macros/src/function.rs b/crates/macros/src/function.rs index 670d32fedc..6fe52995a2 100644 --- a/crates/macros/src/function.rs +++ b/crates/macros/src/function.rs @@ -188,7 +188,7 @@ pub fn build_arg_parser<'a>( None }); - if rest_optional && !arg.nullable && arg.default.is_none() { + if rest_optional && !arg.nullable && arg.default.is_none() && !arg.variadic { bail!( "Parameter `{}` must be a variant of `Option` or have a default value as it is optional.", arg.name diff --git a/guide/src/macros/function.md b/guide/src/macros/function.md index 4538180f86..f3f32d678f 100644 --- a/guide/src/macros/function.md +++ b/guide/src/macros/function.md @@ -108,14 +108,27 @@ the `...$args` syntax. # use ext_php_rs::prelude::*; # use ext_php_rs::types::Zval; /// This can be called from PHP as `add(1, 2, 3, 4, 5)` +/// note: it requires to set numbers with one or arguments #[php_function] pub fn add(number: u32, numbers:&[&Zval]) -> u32 { + println!("Extra numbers: {:?}", numbers); + // numbers is a slice of 4 Zvals all of type long + number +} + +/// Having optional numbers can be done like: +/// This can be called from PHP as `add(1)`, with no addional numbers given +#[php_function(optional = "numbers")] +pub fn add_optional(number: u32, numbers:&[&Zval]) -> u32 { + println!("Optional numbers: {:?}", numbers); // numbers is a slice of 4 Zvals all of type long number } # fn main() {} ``` +Checkout more example in our [tests](https://github.com/davidcole1340/ext-php-rs/tree/master/tests/src/integration/variadic_args.php) location. + ## Returning `Result` You can also return a `Result` from the function. The error variant will be diff --git a/src/builders/function.rs b/src/builders/function.rs index 60eddcc962..99f74f7e2d 100644 --- a/src/builders/function.rs +++ b/src/builders/function.rs @@ -55,6 +55,10 @@ impl<'a> FunctionBuilder<'a> { arg_info: ptr::null(), num_args: 0, flags: 0, // TBD? + #[cfg(php84)] + doc_comment: ptr::null(), + #[cfg(php84)] + frameless_function_infos: ptr::null(), }, args: vec![], n_req: None, @@ -79,6 +83,10 @@ impl<'a> FunctionBuilder<'a> { arg_info: ptr::null(), num_args: 0, flags: MethodFlags::Abstract.bits(), + #[cfg(php84)] + doc_comment: ptr::null(), + #[cfg(php84)] + frameless_function_infos: ptr::null(), }, args: vec![], n_req: None, diff --git a/src/types/zval.rs b/src/types/zval.rs index d2381d5bb4..b8a819d5df 100644 --- a/src/types/zval.rs +++ b/src/types/zval.rs @@ -718,3 +718,21 @@ impl<'a> FromZvalMut<'a> for &'a mut Zval { Some(zval) } } + +impl<'a> FromZvalMut<'a> for &'a [&'a Zval] { + const TYPE: DataType = DataType::Array; + + fn from_zval_mut(zval: &'a mut Zval) -> Option { + let mut slice: Vec<&'a Zval> = Vec::new(); + + // Check if the input Zval is an array and convert it into a slice of references + if let Some(a) = zval.array() { + // Collect references to each element in the array + slice = a.values().collect(); + } else { + slice.push(zval); + } + + Some(Box::leak(slice.into_boxed_slice())) + } +} diff --git a/src/zend/function.rs b/src/zend/function.rs index 6e6dd1a39e..a16ea1e61a 100644 --- a/src/zend/function.rs +++ b/src/zend/function.rs @@ -38,6 +38,10 @@ impl FunctionEntry { arg_info: ptr::null(), num_args: 0, flags: 0, + #[cfg(php84)] + doc_comment: ptr::null(), + #[cfg(php84)] + frameless_function_infos: ptr::null(), } } diff --git a/src/zend/handlers.rs b/src/zend/handlers.rs index 7e88a7e053..d8f8ac148e 100644 --- a/src/zend/handlers.rs +++ b/src/zend/handlers.rs @@ -238,9 +238,18 @@ impl ZendObjectHandlers { let mut zv = Zval::new(); val.get(self_, &mut zv)?; - #[allow(clippy::unnecessary_mut_passed)] - if zend_is_true(&mut zv) == 1 { - return Ok(1); + cfg_if::cfg_if! { + if #[cfg(php84)] { + #[allow(clippy::unnecessary_mut_passed)] + if zend_is_true(&mut zv) { + return Ok(1); + } + } else { + #[allow(clippy::unnecessary_mut_passed)] + if zend_is_true(&mut zv) == 1 { + return Ok(1); + } + } } } } diff --git a/tests/src/integration/variadic_args.php b/tests/src/integration/variadic_args.php new file mode 100644 index 0000000000..4855bdcd5d --- /dev/null +++ b/tests/src/integration/variadic_args.php @@ -0,0 +1,36 @@ + Zval { call.try_call(vec![&a]).expect("Failed to call function") } +// Rust type &[&Zval] must be converted because to Vec because of +// lifetime hell. +#[php_function(optional = "params")] +pub fn test_variadic_optional_args(params: &[&Zval]) -> Vec { + params.iter().map(|x| x.shallow_clone()).collect() +} + +#[php_function] +pub fn test_variadic_args(params: &[&Zval]) -> Vec { + params.iter().map(|x| x.shallow_clone()).collect() +} + +#[php_function(optional = "_numbers")] +pub fn test_variadic_add_optional(number: u32, _numbers: &[&Zval]) -> u32 { + number +} + +#[php_function] +pub fn test_variadic_add_required(numbers: &[&Zval]) -> Vec { + numbers.iter().map(|x| x.shallow_clone()).collect() +} + +#[php_function(optional = "everything")] +pub fn test_variadic_all_types(everything: &[&Zval]) -> Vec { + everything.iter().map(|x| x.shallow_clone()).collect() +} + #[php_class] pub struct TestClass { string: String, @@ -184,4 +215,5 @@ mod integration { mod object; mod string; mod types; + mod variadic_args; }