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, MethodFlags},
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 pub(crate) fn add_flags(&mut self, flags: MethodFlags) {
50 cfg_if::cfg_if! {
51 if #[cfg(php86)] {
52 self.flags |= u64::from(flags.bits());
53 } else {
54 self.flags |= flags.bits();
55 }
56 }
57 }
58}
59
60pub type Function = zend_function;
62
63impl Function {
64 pub fn function_type(&self) -> Result<FunctionType> {
73 FunctionType::try_from(unsafe { self.type_ })
74 }
75
76 #[inline]
78 #[must_use]
79 pub fn try_from_function(name: &str) -> Option<Self> {
80 unsafe {
81 let res = zend_fetch_function_str(name.as_ptr().cast::<c_char>(), name.len());
82 if res.is_null() {
83 return None;
84 }
85 Some(*res)
86 }
87 }
88
89 #[must_use]
91 pub fn try_from_method(class: &str, name: &str) -> Option<Self> {
92 match ClassEntry::try_find(class) {
93 None => None,
94 Some(ce) => unsafe {
95 let res = zend_hash_str_find_ptr_lc(
96 &raw const ce.function_table,
97 name.as_ptr().cast::<c_char>(),
98 name.len(),
99 )
100 .cast::<zend_function>();
101 if res.is_null() {
102 return None;
103 }
104 Some(*res)
105 },
106 }
107 }
108
109 #[allow(clippy::inline_always)]
139 #[inline(always)]
140 pub fn try_call(&self, params: Vec<&dyn IntoZvalDyn>) -> Result<Zval> {
141 let mut retval = Zval::new();
142 let len = params.len();
143 let params = params
144 .into_iter()
145 .map(|val| val.as_zval(false))
146 .collect::<Result<Vec<_>>>()?;
147 let packed = params.into_boxed_slice();
148
149 unsafe {
150 zend_call_known_function(
151 ptr::from_ref(self).cast_mut(),
152 ptr::null_mut(),
153 ptr::null_mut(),
154 &raw mut retval,
155 len.try_into()?,
156 packed.as_ptr().cast_mut(),
157 ptr::null_mut(),
158 );
159 };
160
161 Ok(retval)
162 }
163}