11//! Apis relate to [crate::sys::zend_function_entry].
22//!
3- //! TODO Add php function call.
43//! TODO Add lambda.
54
65use std:: { mem:: zeroed, os:: raw:: c_char} ;
76
87use crate :: {
98 alloc:: EBox ,
109 classes:: Visibility ,
11- errors:: { ArgumentCountError , CallFunctionError } ,
10+ errors:: { ArgumentCountError , CallFunctionError , CallMethodError } ,
1211 objects:: Object ,
1312 strings:: ZendString ,
1413 sys:: * ,
1514 utils:: ensure_end_with_zero,
1615 values:: { ExecuteData , SetVal , Val } ,
1716} ;
18- use std:: { marker:: PhantomData , ptr :: null_mut , str :: Utf8Error } ;
17+ use std:: { marker:: PhantomData , mem :: size_of , ptr :: null_mut } ;
1918
2019pub ( crate ) trait Callable {
2120 fn call ( & self , execute_data : & mut ExecuteData , arguments : & mut [ Val ] , return_value : & mut Val ) ;
@@ -225,10 +224,73 @@ impl ZendFunction {
225224 & mut self . inner
226225 }
227226
228- pub fn get_name ( & self ) -> Result < String , Utf8Error > {
227+ pub fn get_name ( & self ) -> EBox < ZendString > {
229228 unsafe {
230229 let s = phper_get_function_or_method_name ( self . as_ptr ( ) ) ;
231- ZendString :: from_raw ( s) . to_string ( )
230+ ZendString :: from_raw ( s)
231+ }
232+ }
233+
234+ pub ( crate ) fn call_method < T : ' static > (
235+ & mut self ,
236+ object : & mut Object < T > ,
237+ arguments : & mut [ Val ] ,
238+ ) -> crate :: Result < EBox < Val > > {
239+ let mut ret_val = EBox :: new ( Val :: undef ( ) ) ;
240+
241+ let mut fci = zend_fcall_info {
242+ size : size_of :: < zend_fcall_info > ( ) ,
243+ function_name : Val :: undef ( ) . into_inner ( ) ,
244+ retval : ret_val. as_mut_ptr ( ) ,
245+ params : arguments. as_mut_ptr ( ) . cast ( ) ,
246+ object : object. as_mut_ptr ( ) ,
247+ param_count : arguments. len ( ) as u32 ,
248+ #[ cfg( phper_major_version = "8" ) ]
249+ named_params : null_mut ( ) ,
250+ #[ cfg( phper_major_version = "7" ) ]
251+ no_separation : 1 ,
252+ #[ cfg( all( phper_major_version = "7" , phper_minor_version = "0" ) ) ]
253+ function_table : null_mut ( ) ,
254+ #[ cfg( all( phper_major_version = "7" , phper_minor_version = "0" ) ) ]
255+ symbol_table : null_mut ( ) ,
256+ } ;
257+
258+ let called_scope = unsafe {
259+ let mut called_scope = object. get_class ( ) . as_ptr ( ) as * mut zend_class_entry ;
260+ if called_scope. is_null ( ) {
261+ called_scope = self . inner . common . scope ;
262+ }
263+ called_scope
264+ } ;
265+
266+ let mut fcc = zend_fcall_info_cache {
267+ function_handler : self . as_mut_ptr ( ) ,
268+ calling_scope : null_mut ( ) ,
269+ called_scope,
270+ object : object. as_mut_ptr ( ) ,
271+ #[ cfg( all(
272+ phper_major_version = "7" ,
273+ any(
274+ phper_minor_version = "0" ,
275+ phper_minor_version = "1" ,
276+ phper_minor_version = "2" ,
277+ )
278+ ) ) ]
279+ initialized : 1 ,
280+ } ;
281+
282+ unsafe {
283+ if zend_call_function ( & mut fci, & mut fcc) != ZEND_RESULT_CODE_SUCCESS
284+ || ret_val. get_type ( ) . is_undef ( )
285+ {
286+ Err ( CallMethodError :: new (
287+ object. get_class ( ) . get_name ( ) . to_string ( ) ?,
288+ self . get_name ( ) . to_string ( ) ?,
289+ )
290+ . into ( ) )
291+ } else {
292+ Ok ( ret_val)
293+ }
232294 }
233295 }
234296}
@@ -262,6 +324,7 @@ unsafe extern "C" fn invoke(execute_data: *mut zend_execute_data, return_value:
262324 if num_args < required_num_args {
263325 let func_name = execute_data. func ( ) . get_name ( ) ;
264326 let result = func_name
327+ . to_string ( )
265328 . map ( |func_name| {
266329 Err :: < ( ) , _ > ( ArgumentCountError :: new (
267330 func_name,
@@ -323,7 +386,23 @@ pub(crate) const fn create_zend_arg_info(
323386 }
324387}
325388
326- pub fn call ( fn_name : & str , arguments : & [ Val ] ) -> Result < EBox < Val > , CallFunctionError > {
389+ /// Call user function by name.
390+ ///
391+ /// # Examples
392+ ///
393+ /// ```
394+ /// use phper::{arrays::Array, functions::call, values::Val};
395+ ///
396+ /// fn example() -> phper::Result<()> {
397+ /// let mut arr = Array::new();
398+ /// arr.insert("a", Val::new(1));
399+ /// arr.insert("b", Val::new(2));
400+ /// let ret = call("json_encode", &mut [Val::new(arr)])?;
401+ /// assert_eq!(ret.as_string()?, r#"{"a":1,"b":2}"#);
402+ /// Ok(())
403+ /// }
404+ /// ```
405+ pub fn call ( fn_name : & str , arguments : & mut [ Val ] ) -> Result < EBox < Val > , CallFunctionError > {
327406 let mut func = Val :: new ( fn_name) ;
328407 let mut ret = EBox :: new ( Val :: null ( ) ) ;
329408 unsafe {
@@ -333,8 +412,9 @@ pub fn call(fn_name: &str, arguments: &[Val]) -> Result<EBox<Val>, CallFunctionE
333412 func. as_mut_ptr ( ) ,
334413 ret. as_mut_ptr ( ) ,
335414 arguments. len ( ) as u32 ,
336- arguments. as_ptr ( ) as * const Val as * mut Val as * mut zval ,
337- ) {
415+ arguments. as_mut_ptr ( ) . cast ( ) ,
416+ ) && !ret. get_type ( ) . is_undef ( )
417+ {
338418 Ok ( ret)
339419 } else {
340420 Err ( CallFunctionError :: new ( fn_name. to_owned ( ) ) )
0 commit comments