Skip to content
Closed
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
12 changes: 10 additions & 2 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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) {
Expand All @@ -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(())
}

Expand Down
2 changes: 1 addition & 1 deletion crates/macros/src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions guide/src/macros/function.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<T, E>`

You can also return a `Result` from the function. The error variant will be
Expand Down
8 changes: 8 additions & 0 deletions src/builders/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down
18 changes: 18 additions & 0 deletions src/types/zval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Self> {
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()))
}
}
4 changes: 4 additions & 0 deletions src/zend/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
}
}

Expand Down
15 changes: 12 additions & 3 deletions src/zend/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
}
}
Expand Down
36 changes: 36 additions & 0 deletions tests/src/integration/variadic_args.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

require "_utils.php";

$a = 'a';
$b = 'b';
$c = 'c';

// Passing arguments as references
$args = test_variadic_optional_args();
assert(count($args) === 0, 'Expected no arguments to be returned');

$args = test_variadic_optional_args($a);
assert(count($args) === 1, 'Expected to have 1 argument');

$args = test_variadic_optional_args($a, $b, $c);
assert(count($args) === 3, 'Expected to have 3 argument');
assert($args[1] === $b, 'Expected second argument to have a value of \$b aka "b"');
assert($args[2] === $c, 'Expected third argument to have a value of \$c aka "c"');

// Must have arguments.. so catch ArgumentCountError errors!
assert_exception_thrown('test_variadic_args');

// Values directly passed
test_variadic_add_optional(1, 2, 3); // 1

$count = test_variadic_add_optional(11); // 11
assert($count === 11, 'Allow only one argument');

$numbers = test_variadic_add_required(1, 2, 3, 4);
assert($numbers === [1, 2, 3, 4], 'Must return a array of numbers');

$types = test_variadic_all_types('a', 1, ['abc', 'def', 0.01], true, new stdClass);
assert(gettype(end($types[2])) === 'double', 'Type of argument 2 and its last element should be a float of 0.01');
assert($types[3], 'Arg 4 should be boolean true');
assert($types[4] instanceof stdClass, 'Last argument is an instance of an StdClass');
4 changes: 4 additions & 0 deletions tests/src/integration/variadic_args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#[test]
fn test_variadic_optional_args() {
assert!(crate::integration::run_php("variadic_args.php"));
}
34 changes: 33 additions & 1 deletion tests/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#![cfg_attr(windows, feature(abi_vectorcall))]
use ext_php_rs::{binary::Binary, prelude::*, types::ZendObject, types::Zval};
use ext_php_rs::{
binary::Binary,
prelude::*,
types::{ZendObject, Zval},
};
use std::collections::HashMap;

#[php_function]
Expand Down Expand Up @@ -72,6 +76,33 @@ pub fn test_callable(call: ZendCallable, a: String) -> Zval {
call.try_call(vec![&a]).expect("Failed to call function")
}

// Rust type &[&Zval] must be converted because to Vec<Zval> because of
// lifetime hell.
#[php_function(optional = "params")]
pub fn test_variadic_optional_args(params: &[&Zval]) -> Vec<Zval> {
params.iter().map(|x| x.shallow_clone()).collect()
}

#[php_function]
pub fn test_variadic_args(params: &[&Zval]) -> Vec<Zval> {
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<Zval> {
numbers.iter().map(|x| x.shallow_clone()).collect()
}

#[php_function(optional = "everything")]
pub fn test_variadic_all_types(everything: &[&Zval]) -> Vec<Zval> {
everything.iter().map(|x| x.shallow_clone()).collect()
}

#[php_class]
pub struct TestClass {
string: String,
Expand Down Expand Up @@ -184,4 +215,5 @@ mod integration {
mod object;
mod string;
mod types;
mod variadic_args;
}
Loading