ext_php_rs/
error.rs

1//! Error and result types returned from the library functions.
2
3use std::{
4    error::Error as ErrorTrait,
5    ffi::{CString, NulError},
6    fmt::Display,
7};
8
9use crate::{
10    boxed::ZBox,
11    exception::PhpException,
12    ffi::php_error_docref,
13    flags::{ClassFlags, DataType, ErrorType, ZvalTypeFlags},
14    types::ZendObject,
15};
16
17/// The main result type which is passed by the library.
18pub type Result<T, E = Error> = std::result::Result<T, E>;
19
20/// The main error type which is passed by the library inside the custom
21/// [`Result`] type.
22#[derive(Debug)]
23#[non_exhaustive]
24pub enum Error {
25    /// An incorrect number of arguments was given to a PHP function.
26    ///
27    /// The enum carries two integers - the first representing the minimum
28    /// number of arguments expected, and the second representing the number of
29    /// arguments that were received.
30    IncorrectArguments(usize, usize),
31    /// There was an error converting a Zval into a primitive type.
32    ///
33    /// The enum carries the data type of the Zval.
34    ZvalConversion(DataType),
35    /// The type of the Zval is unknown.
36    ///
37    /// The enum carries the integer representation of the type of Zval.
38    UnknownDatatype(u32),
39    /// Attempted to convert a [`ZvalTypeFlags`] struct to a [`DataType`].
40    /// The flags did not contain a datatype.
41    ///
42    /// The enum carries the flags that were attempted to be converted to a
43    /// [`DataType`].
44    InvalidTypeToDatatype(ZvalTypeFlags),
45    /// The function called was called in an invalid scope (calling
46    /// class-related functions inside of a non-class bound function).
47    InvalidScope,
48    /// The pointer inside a given type was invalid, either null or pointing to
49    /// garbage.
50    InvalidPointer,
51    /// The given property name does not exist.
52    InvalidProperty,
53    /// The string could not be converted into a C-string due to the presence of
54    /// a NUL character.
55    InvalidCString,
56    /// The string could not be converted into a valid Utf8 string
57    InvalidUtf8,
58    /// Could not call the given function.
59    Callable,
60    /// An object was expected.
61    Object,
62    /// An invalid exception type was thrown.
63    InvalidException(ClassFlags),
64    /// Converting integer arguments resulted in an overflow.
65    IntegerOverflow,
66    /// An exception was thrown in a function.
67    Exception(ZBox<ZendObject>),
68    /// A failure occurred while registering the stream wrapper
69    StreamWrapperRegistrationFailure,
70    /// A failure occurred while unregistering the stream wrapper
71    StreamWrapperUnregistrationFailure,
72}
73
74impl Display for Error {
75    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76        match self {
77            Error::IncorrectArguments(n, expected) => write!(
78                f,
79                "Expected at least {expected} arguments, got {n} arguments."
80            ),
81            Error::ZvalConversion(ty) => write!(
82                f,
83                "Could not convert Zval from type {ty} into primitive type."
84            ),
85            Error::UnknownDatatype(dt) => write!(f, "Unknown datatype {dt}."),
86            Error::InvalidTypeToDatatype(dt) => {
87                write!(f, "Type flags did not contain a datatype: {dt:?}")
88            }
89            Error::InvalidScope => write!(f, "Invalid scope."),
90            Error::InvalidPointer => write!(f, "Invalid pointer."),
91            Error::InvalidProperty => write!(f, "Property does not exist on object."),
92            Error::InvalidCString => write!(
93                f,
94                "String given contains NUL-bytes which cannot be present in a C string."
95            ),
96            Error::InvalidUtf8 => write!(f, "Invalid Utf8 byte sequence."),
97            Error::Callable => write!(f, "Could not call given function."),
98            Error::Object => write!(f, "An object was expected."),
99            Error::InvalidException(flags) => {
100                write!(f, "Invalid exception type was thrown: {flags:?}")
101            }
102            Error::IntegerOverflow => {
103                write!(f, "Converting integer arguments resulted in an overflow.")
104            }
105            Error::Exception(e) => write!(f, "Exception was thrown: {e:?}"),
106            Error::StreamWrapperRegistrationFailure => {
107                write!(f, "A failure occurred while registering the stream wrapper")
108            }
109            Error::StreamWrapperUnregistrationFailure => {
110                write!(
111                    f,
112                    "A failure occurred while unregistering the stream wrapper"
113                )
114            }
115        }
116    }
117}
118
119impl ErrorTrait for Error {}
120
121impl From<NulError> for Error {
122    fn from(_: NulError) -> Self {
123        Self::InvalidCString
124    }
125}
126
127impl From<Error> for PhpException {
128    fn from(err: Error) -> Self {
129        Self::default(err.to_string())
130    }
131}
132
133/// Trigger an error that is reported in PHP the same way `trigger_error()` is.
134///
135/// See specific error type descriptions at <https://www.php.net/manual/en/errorfunc.constants.php>.
136pub fn php_error(type_: ErrorType, message: &str) {
137    let c_string = match CString::new(message) {
138        Ok(string) => string,
139        Err(_) => {
140            return;
141        }
142    };
143
144    unsafe { php_error_docref(std::ptr::null(), type_.bits() as _, c_string.as_ptr()) }
145}