Skip to content

Commit 7443c14

Browse files
committed
Add argument infos.
1 parent c663ca6 commit 7443c14

File tree

4 files changed

+106
-11
lines changed

4 files changed

+106
-11
lines changed

examples/hello/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use phper::{
22
c_str_ptr,
33
classes::{Class, MethodEntity, StdClass, This},
4-
functions::create_zend_arg_info,
4+
functions::{create_zend_arg_info, Argument},
55
ini::Policy,
66
modules::{read_global_module, write_global_module, Module, ModuleArgs},
77
php_get_module,
@@ -43,7 +43,7 @@ pub extern "C" fn get_module(module: &mut Module) {
4343
module.on_request_shutdown(|_| true);
4444

4545
// register functions
46-
module.add_function("hello_say_hello", say_hello);
46+
module.add_function("hello_say_hello", say_hello, vec![Argument::by_val("name")]);
4747
module.add_function(
4848
"hello_get_all_ini",
4949
|_: &mut [Val]| -> Result<String, Exception> {
@@ -55,6 +55,7 @@ pub extern "C" fn get_module(module: &mut Module) {
5555

5656
Ok(String::new())
5757
},
58+
vec![],
5859
);
5960

6061
// register classes

phper/src/functions.rs

Lines changed: 76 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
use crate::{
22
classes::Method,
33
ini::create_ini_entry_ex,
4-
sys::{
5-
_zend_get_parameters_array_ex, phper_z_strval_p, phper_zval_zval, zend_arg_info,
6-
zend_ce_exception, zend_execute_data, zend_function_entry, zend_ini_entry_def,
7-
zend_internal_arg_info, zend_throw_exception, zend_uchar, zif_handler, zval,
8-
},
4+
sys::*,
95
throws::Throwable,
106
values::{ExecuteData, SetVal, Val},
117
};
@@ -40,6 +36,55 @@ pub struct FunctionEntry {
4036
pub(crate) struct FunctionEntity {
4137
pub(crate) name: String,
4238
pub(crate) handler: Box<dyn Function>,
39+
pub(crate) arguments: Vec<Argument>,
40+
}
41+
42+
pub struct Argument {
43+
pub(crate) name: String,
44+
pub(crate) pass_by_ref: bool,
45+
pub(crate) required: bool,
46+
}
47+
48+
impl Argument {
49+
pub fn by_val(name: impl ToString) -> Self {
50+
let mut name = name.to_string();
51+
name.push('\0');
52+
Self {
53+
name,
54+
pass_by_ref: false,
55+
required: true,
56+
}
57+
}
58+
59+
pub fn by_ref(name: impl ToString) -> Self {
60+
let mut name = name.to_string();
61+
name.push('\0');
62+
Self {
63+
name,
64+
pass_by_ref: true,
65+
required: true,
66+
}
67+
}
68+
69+
pub fn by_val_optional(name: impl ToString) -> Self {
70+
let mut name = name.to_string();
71+
name.push('\0');
72+
Self {
73+
name,
74+
pass_by_ref: false,
75+
required: false,
76+
}
77+
}
78+
79+
pub fn by_ref_optional(name: impl ToString) -> Self {
80+
let mut name = name.to_string();
81+
name.push('\0');
82+
Self {
83+
name,
84+
pass_by_ref: true,
85+
required: false,
86+
}
87+
}
4388
}
4489

4590
pub(crate) unsafe extern "C" fn invoke(
@@ -49,14 +94,38 @@ pub(crate) unsafe extern "C" fn invoke(
4994
let execute_data = ExecuteData::from_mut(execute_data);
5095
let return_value = Val::from_mut(return_value);
5196

97+
// TODO I don't know why this field is zero.
5298
let num_args = execute_data.common_num_args();
5399
let arg_info = execute_data.common_arg_info();
54100

101+
let mut num_args = 0isize;
102+
for i in 0..10isize {
103+
let buf = transmute::<_, [u8; size_of::<zend_arg_info>()]>(*arg_info.offset(i as isize));
104+
if buf == zeroed::<[u8; size_of::<zend_arg_info>()]>() {
105+
num_args = i;
106+
break;
107+
}
108+
}
109+
if num_args == 0 {
110+
unreachable!();
111+
}
112+
num_args += 1;
113+
55114
let last_arg_info = arg_info.offset(num_args as isize);
56115
let handler = (*last_arg_info).name as *const Box<dyn Function>;
57116
let handler = handler.as_ref().expect("handler is null");
58117

59-
// TODO Do num args check
118+
// Check arguments count.
119+
if execute_data.num_args() < execute_data.common_required_num_args() {
120+
let s = format!(
121+
"expects at least {} parameter(s), {} given\0",
122+
execute_data.common_required_num_args(),
123+
execute_data.num_args()
124+
);
125+
php_error_docref(null(), E_WARNING as i32, s.as_ptr().cast());
126+
().set_val(return_value);
127+
return;
128+
}
60129

61130
let mut arguments = execute_data.get_parameters_array();
62131

@@ -103,7 +172,7 @@ pub const fn create_zend_arg_info(
103172
}
104173
}
105174

106-
#[cfg(any(phper_php_version = "7.1", phper_php_version = "7.0",))]
175+
#[cfg(any(phper_php_version = "7.1", phper_php_version = "7.0"))]
107176
{
108177
zend_internal_arg_info {
109178
name,

phper/src/modules.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{
22
c_str_ptr,
33
classes::{Class, ClassEntity, ClassEntry},
4-
functions::{invoke, Function, FunctionEntity},
4+
functions::{create_zend_arg_info, invoke, Argument, Function, FunctionEntity},
55
ini::{IniEntity, IniValue, Policy, StrPtrBox},
66
sys::*,
77
};
@@ -209,13 +209,19 @@ impl Module {
209209
})
210210
}
211211

212-
pub fn add_function(&mut self, name: impl ToString, handler: impl Function + 'static) {
212+
pub fn add_function(
213+
&mut self,
214+
name: impl ToString,
215+
handler: impl Function + 'static,
216+
arguments: Vec<Argument>,
217+
) {
213218
let mut name = name.to_string();
214219
name.push('\0');
215220

216221
self.function_entities.push(FunctionEntity {
217222
name,
218223
handler: Box::new(handler),
224+
arguments,
219225
});
220226
}
221227

@@ -270,6 +276,20 @@ impl Module {
270276

271277
for f in &self.function_entities {
272278
let mut infos = Vec::new();
279+
280+
let require_arg_count = f.arguments.iter().filter(|arg| arg.required).count();
281+
infos.push(create_zend_arg_info(
282+
require_arg_count as *const c_char,
283+
false,
284+
));
285+
286+
for arg in &f.arguments {
287+
infos.push(create_zend_arg_info(
288+
arg.name.as_ptr().cast(),
289+
arg.pass_by_ref,
290+
));
291+
}
292+
273293
infos.push(unsafe { zeroed::<zend_internal_arg_info>() });
274294

275295
let mut last_arg_info = unsafe { zeroed::<zend_internal_arg_info>() };

phper/src/values.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ impl ExecuteData {
5050
(*self.inner.func).common.num_args
5151
}
5252

53+
#[inline]
54+
pub unsafe fn common_required_num_args(&self) -> u32 {
55+
(*self.inner.func).common.required_num_args
56+
}
57+
5358
#[inline]
5459
pub unsafe fn common_arg_info(&self) -> *mut zend_arg_info {
5560
(*self.inner.func).common.arg_info

0 commit comments

Comments
 (0)