• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

davidcole1340 / ext-php-rs / 15788182852

20 Jun 2025 09:32PM UTC coverage: 22.034%. Remained the same
15788182852

Pull #460

github

web-flow
Merge d4fc01bb5 into 660f308c0
Pull Request #460: chore(clippy): flowing lifetimes warning and clippy::mut_from_ref

6 of 56 new or added lines in 13 files covered. (10.71%)

3 existing lines in 2 files now uncovered.

871 of 3953 relevant lines covered (22.03%)

2.35 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

7.32
/src/types/callable.rs
1
//! Types related to callables in PHP (anonymous functions, functions, etc).
2

3
use std::{convert::TryFrom, ops::Deref, ptr};
4

5
use crate::{
6
    convert::{FromZval, IntoZvalDyn},
7
    error::{Error, Result},
8
    ffi::_call_user_function_impl,
9
    flags::DataType,
10
    zend::ExecutorGlobals,
11
};
12

13
use super::Zval;
14

15
/// Acts as a wrapper around a callable [`Zval`]. Allows the owner to call the
16
/// [`Zval`] as if it was a PHP function through the [`try_call`] method.
17
///
18
/// [`try_call`]: #method.try_call
19
#[derive(Debug)]
20
pub struct ZendCallable<'a>(OwnedZval<'a>);
21

22
impl<'a> ZendCallable<'a> {
23
    /// Attempts to create a new [`ZendCallable`] from a zval.
24
    ///
25
    /// # Parameters
26
    ///
27
    /// * `callable` - The underlying [`Zval`] that is callable.
28
    ///
29
    /// # Errors
30
    ///
31
    /// Returns an error if the [`Zval`] was not callable.
32
    pub fn new(callable: &'a Zval) -> Result<Self> {
1✔
33
        if callable.is_callable() {
1✔
34
            Ok(Self(OwnedZval::Reference(callable)))
×
35
        } else {
36
            Err(Error::Callable)
1✔
37
        }
38
    }
39

40
    /// Attempts to create a new [`ZendCallable`] by taking ownership of a Zval.
41
    /// Returns a result containing the callable if the zval was callable.
42
    ///
43
    /// # Parameters
44
    ///
45
    /// * `callable` - The underlying [`Zval`] that is callable.
46
    ///
47
    /// # Errors
48
    ///
49
    /// * [`Error::Callable`] - If the zval was not callable.
50
    pub fn new_owned(callable: Zval) -> Result<Self> {
×
51
        if callable.is_callable() {
×
52
            Ok(Self(OwnedZval::Owned(callable)))
×
53
        } else {
54
            Err(Error::Callable)
×
55
        }
56
    }
57

58
    /// Attempts to create a new [`ZendCallable`] from a function name. Returns
59
    /// a result containing the callable if the function existed and was
60
    /// callable.
61
    ///
62
    /// # Parameters
63
    ///
64
    /// * `name` - Name of the callable function.
65
    ///
66
    /// # Errors
67
    ///
68
    /// Returns an error if the function does not exist or is not callable.
69
    ///
70
    /// # Example
71
    ///
72
    /// ```no_run
73
    /// use ext_php_rs::types::ZendCallable;
74
    ///
75
    /// let strpos = ZendCallable::try_from_name("strpos").unwrap();
76
    /// let result = strpos.try_call(vec![&"hello", &"e"]).unwrap();
77
    /// assert_eq!(result.long(), Some(1));
78
    /// ```
79
    pub fn try_from_name(name: &str) -> Result<Self> {
×
80
        let mut callable = Zval::new();
×
81
        callable.set_string(name, false)?;
×
82

83
        Self::new_owned(callable)
×
84
    }
85

86
    /// Attempts to call the callable with a list of arguments to pass to the
87
    /// function.
88
    ///
89
    /// You should not call this function directly, rather through the
90
    /// [`call_user_func`] macro.
91
    ///
92
    /// # Parameters
93
    ///
94
    /// * `params` - A list of parameters to call the function with.
95
    ///
96
    /// # Returns
97
    ///
98
    /// Returns the result wrapped in [`Ok`] upon success.
99
    ///
100
    /// # Errors
101
    ///
102
    /// * If calling the callable fails, or an exception is thrown, an [`Err`]
103
    ///   is returned.
104
    /// * If the number of parameters exceeds `u32::MAX`.
105
    ///
106
    /// # Example
107
    ///
108
    /// ```no_run
109
    /// use ext_php_rs::types::ZendCallable;
110
    ///
111
    /// let strpos = ZendCallable::try_from_name("strpos").unwrap();
112
    /// let result = strpos.try_call(vec![&"hello", &"e"]).unwrap();
113
    /// assert_eq!(result.long(), Some(1));
114
    /// ```
115
    // TODO: Measure this
116
    #[allow(clippy::inline_always)]
117
    #[inline(always)]
118
    pub fn try_call(&self, params: Vec<&dyn IntoZvalDyn>) -> Result<Zval> {
×
119
        if !self.0.is_callable() {
×
120
            return Err(Error::Callable);
×
121
        }
122

123
        let mut retval = Zval::new();
×
124
        let len = params.len();
×
125
        let params = params
×
126
            .into_iter()
127
            .map(|val| val.as_zval(false))
×
128
            .collect::<Result<Vec<_>>>()?;
129
        let packed = params.into_boxed_slice();
×
130

131
        let result = unsafe {
132
            #[allow(clippy::used_underscore_items)]
133
            _call_user_function_impl(
NEW
134
                ptr::null_mut(),
×
135
                ptr::from_ref(self.0.as_ref()).cast_mut(),
×
NEW
136
                &raw mut retval,
×
137
                len.try_into()?,
×
138
                packed.as_ptr().cast_mut(),
×
NEW
139
                ptr::null_mut(),
×
140
            )
141
        };
142

143
        if result < 0 {
×
144
            Err(Error::Callable)
×
145
        } else if let Some(e) = ExecutorGlobals::take_exception() {
×
146
            Err(Error::Exception(e))
×
147
        } else {
148
            Ok(retval)
×
149
        }
150
    }
151
}
152

153
impl<'a> FromZval<'a> for ZendCallable<'a> {
154
    const TYPE: DataType = DataType::Callable;
155

156
    fn from_zval(zval: &'a Zval) -> Option<Self> {
×
157
        ZendCallable::new(zval).ok()
×
158
    }
159
}
160

161
impl TryFrom<Zval> for ZendCallable<'_> {
162
    type Error = Error;
163

164
    fn try_from(value: Zval) -> Result<Self> {
×
165
        ZendCallable::new_owned(value)
×
166
    }
167
}
168

169
/// A container for a zval. Either contains a reference to a zval or an owned
170
/// zval.
171
#[derive(Debug)]
172
enum OwnedZval<'a> {
173
    Reference(&'a Zval),
174
    Owned(Zval),
175
}
176

177
impl OwnedZval<'_> {
178
    fn as_ref(&self) -> &Zval {
×
179
        match self {
×
180
            OwnedZval::Reference(zv) => zv,
×
181
            OwnedZval::Owned(zv) => zv,
×
182
        }
183
    }
184
}
185

186
impl Deref for OwnedZval<'_> {
187
    type Target = Zval;
188

189
    fn deref(&self) -> &Self::Target {
×
190
        self.as_ref()
×
191
    }
192
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc