ext_php_rs/zend/
function.rs1use std::{fmt::Debug, os::raw::c_char, ptr};
4
5use crate::{
6 convert::IntoZvalDyn,
7 error::Result,
8 ffi::{
9 zend_call_known_function, zend_fetch_function_str, zend_function, zend_function_entry,
10 zend_hash_str_find_ptr_lc,
11 },
12 flags::FunctionType,
13 types::Zval,
14};
15
16use super::ClassEntry;
17
18pub type FunctionEntry = zend_function_entry;
20
21impl Debug for FunctionEntry {
22 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23 f.debug_struct("_zend_function_entry")
24 .field("fname", &self.fname)
25 .field("arg_info", &self.arg_info)
26 .field("num_args", &self.num_args)
27 .field("flags", &self.flags)
28 .finish()
29 }
30}
31
32impl FunctionEntry {
33 #[must_use]
35 pub fn end() -> Self {
36 Self {
37 fname: ptr::null::<c_char>(),
38 handler: None,
39 arg_info: ptr::null(),
40 num_args: 0,
41 flags: 0,
42 #[cfg(php84)]
43 doc_comment: ptr::null(),
44 #[cfg(php84)]
45 frameless_function_infos: ptr::null(),
46 }
47 }
48
49 #[must_use]
52 pub fn into_raw(self) -> *mut Self {
53 Box::into_raw(Box::new(self))
54 }
55}
56
57pub type Function = zend_function;
59
60impl Function {
61 #[must_use]
63 pub fn function_type(&self) -> FunctionType {
64 FunctionType::from(unsafe { self.type_ })
65 }
66
67 #[must_use]
69 pub fn try_from_function(name: &str) -> Option<Self> {
70 unsafe {
71 let res = zend_fetch_function_str(name.as_ptr().cast::<c_char>(), name.len());
72 if res.is_null() {
73 return None;
74 }
75 Some(*res)
76 }
77 }
78
79 #[must_use]
81 pub fn try_from_method(class: &str, name: &str) -> Option<Self> {
82 match ClassEntry::try_find(class) {
83 None => None,
84 Some(ce) => unsafe {
85 let res = zend_hash_str_find_ptr_lc(
86 &raw const ce.function_table,
87 name.as_ptr().cast::<c_char>(),
88 name.len(),
89 )
90 .cast::<zend_function>();
91 if res.is_null() {
92 return None;
93 }
94 Some(*res)
95 },
96 }
97 }
98
99 #[allow(clippy::inline_always)]
129 #[inline(always)]
130 pub fn try_call(&self, params: Vec<&dyn IntoZvalDyn>) -> Result<Zval> {
131 let mut retval = Zval::new();
132 let len = params.len();
133 let params = params
134 .into_iter()
135 .map(|val| val.as_zval(false))
136 .collect::<Result<Vec<_>>>()?;
137 let packed = params.into_boxed_slice();
138
139 unsafe {
140 zend_call_known_function(
141 ptr::from_ref(self).cast_mut(),
142 ptr::null_mut(),
143 ptr::null_mut(),
144 &raw mut retval,
145 len.try_into()?,
146 packed.as_ptr().cast_mut(),
147 ptr::null_mut(),
148 );
149 };
150
151 Ok(retval)
152 }
153}