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

extphprs / ext-php-rs / 25379640517

05 May 2026 01:34PM UTC coverage: 72.479% (+6.2%) from 66.241%
25379640517

Pull #734

github

ptondereau
ci(build): skip cargo test on macOS until libphp is available

shivammathur/setup-php's Homebrew formulas (NTS php@x.y and
-debug-zts) do not ship a libphp shared library at
<php-config --prefix>/lib. With macos-latest now running macos-15
(ld-prime + chained fixups by default), the test binary aborts at
image load with "symbol not found in flat namespace" before any
test runs, since undefined PHP runtime data symbols can no longer
be deferred to runtime via -Wl,-undefined,dynamic_lookup.

The previous carve-out only excluded macOS + Rust nightly. Widen
it to all macOS variants. Build coverage on macOS still runs in
the step above. Restore the test step for macOS once a libphp is
wired into the runner (Homebrew --enable-embed build, or a custom
install step).
Pull Request #734: feat!: PHP 8 union, intersection, DNF, and class-union type hints

2871 of 3074 new or added lines in 21 files covered. (93.4%)

3 existing lines in 2 files now uncovered.

11514 of 15886 relevant lines covered (72.48%)

33.34 hits per line

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

6.12
/src/error.rs
1
//! Error and result types returned from the library functions.
2

3
use std::{
4
    error::Error as ErrorTrait,
5
    ffi::{CString, NulError},
6
    fmt::Display,
7
    num::TryFromIntError,
8
};
9

10
use crate::{
11
    boxed::ZBox,
12
    exception::PhpException,
13
    ffi::php_error_docref,
14
    flags::{ClassFlags, DataType, ErrorType, ZvalTypeFlags},
15
    types::ZendObject,
16
};
17

18
/// The main result type which is passed by the library.
19
pub type Result<T, E = Error> = std::result::Result<T, E>;
20

21
/// The main error type which is passed by the library inside the custom
22
/// [`Result`] type.
23
#[derive(Debug)]
24
#[non_exhaustive]
25
pub enum Error {
26
    /// An incorrect number of arguments was given to a PHP function.
27
    ///
28
    /// The enum carries two integers - the first representing the minimum
29
    /// number of arguments expected, and the second representing the number of
30
    /// arguments that were received.
31
    IncorrectArguments(usize, usize),
32
    /// There was an error converting a Zval into a primitive type.
33
    ///
34
    /// The enum carries the data type of the Zval.
35
    ZvalConversion(DataType),
36
    /// The type of the Zval is unknown.
37
    ///
38
    /// The enum carries the integer representation of the type of Zval.
39
    UnknownDatatype(u32),
40
    /// Attempted to convert a [`ZvalTypeFlags`] struct to a [`DataType`].
41
    /// The flags did not contain a datatype.
42
    ///
43
    /// The enum carries the flags that were attempted to be converted to a
44
    /// [`DataType`].
45
    InvalidTypeToDatatype(ZvalTypeFlags),
46
    /// The function called was called in an invalid scope (calling
47
    /// class-related functions inside of a non-class bound function).
48
    InvalidScope,
49
    /// The pointer inside a given type was invalid, either null or pointing to
50
    /// garbage.
51
    InvalidPointer,
52
    /// The given property name does not exist.
53
    InvalidProperty,
54
    /// The string could not be converted into a C-string due to the presence of
55
    /// a NUL character.
56
    InvalidCString,
57
    /// The string could not be converted into a valid Utf8 string
58
    InvalidUtf8,
59
    /// Could not call the given function.
60
    Callable,
61
    /// An object was expected.
62
    Object,
63
    /// An invalid exception type was thrown.
64
    InvalidException(ClassFlags),
65
    /// Converting integer arguments resulted in an overflow.
66
    IntegerOverflow,
67
    /// An exception was thrown in a function.
68
    Exception(ZBox<ZendObject>),
69
    /// A failure occurred while registering the stream wrapper
70
    StreamWrapperRegistrationFailure,
71
    /// A failure occurred while unregistering the stream wrapper
72
    StreamWrapperUnregistrationFailure,
73
    /// The SAPI write function is not available
74
    SapiWriteUnavailable,
75
    /// Failed to make an object lazy (PHP 8.4+)
76
    LazyObjectFailed,
77
    /// The argument's PHP type has no equivalent in PHP's legacy
78
    /// `Z_EXPECTED_*` discriminant enum (compound types, or scalar
79
    /// `DataType` variants without a slot). For these arguments, format the
80
    /// declared type via [`crate::args::Arg::ty`] and report the error
81
    /// through `zend_argument_type_error` or [`crate::exception::PhpException`]
82
    /// instead.
83
    NoExpectedTypeDiscriminant,
84
}
85

86
impl Display for Error {
87
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
×
88
        match self {
×
89
            Error::IncorrectArguments(n, expected) => write!(
×
90
                f,
×
91
                "Expected at least {expected} arguments, got {n} arguments."
92
            ),
93
            Error::ZvalConversion(ty) => write!(
×
94
                f,
×
95
                "Could not convert Zval from type {ty} into primitive type."
96
            ),
97
            Error::UnknownDatatype(dt) => write!(f, "Unknown datatype {dt}."),
×
98
            Error::InvalidTypeToDatatype(dt) => {
×
99
                write!(f, "Type flags did not contain a datatype: {dt:?}")
×
100
            }
101
            Error::InvalidScope => write!(f, "Invalid scope."),
×
102
            Error::InvalidPointer => write!(f, "Invalid pointer."),
×
103
            Error::InvalidProperty => write!(f, "Property does not exist on object."),
×
104
            Error::InvalidCString => write!(
×
105
                f,
×
106
                "String given contains NUL-bytes which cannot be present in a C string."
107
            ),
108
            Error::InvalidUtf8 => write!(f, "Invalid Utf8 byte sequence."),
×
109
            Error::Callable => write!(f, "Could not call given function."),
×
110
            Error::Object => write!(f, "An object was expected."),
×
111
            Error::InvalidException(flags) => {
×
112
                write!(f, "Invalid exception type was thrown: {flags:?}")
×
113
            }
114
            Error::IntegerOverflow => {
115
                write!(f, "Converting integer arguments resulted in an overflow.")
×
116
            }
117
            Error::Exception(e) => write!(f, "Exception was thrown: {e:?}"),
×
118
            Error::StreamWrapperRegistrationFailure => {
119
                write!(f, "A failure occurred while registering the stream wrapper")
×
120
            }
121
            Error::StreamWrapperUnregistrationFailure => {
122
                write!(
×
123
                    f,
×
124
                    "A failure occurred while unregistering the stream wrapper"
125
                )
126
            }
127
            Error::SapiWriteUnavailable => {
128
                write!(f, "The SAPI write function is not available")
×
129
            }
130
            Error::LazyObjectFailed => {
131
                write!(f, "Failed to make the object lazy")
×
132
            }
NEW
133
            Error::NoExpectedTypeDiscriminant => write!(
×
NEW
134
                f,
×
135
                "Argument type has no PHP Z_EXPECTED_* discriminant; format Arg::ty() and use zend_argument_type_error or PhpException instead."
136
            ),
137
        }
138
    }
×
139
}
140

141
impl ErrorTrait for Error {}
142

143
impl From<NulError> for Error {
144
    fn from(_: NulError) -> Self {
1✔
145
        Self::InvalidCString
1✔
146
    }
1✔
147
}
148

149
impl From<TryFromIntError> for Error {
150
    fn from(_value: TryFromIntError) -> Self {
×
151
        Self::IntegerOverflow
×
152
    }
×
153
}
154

155
impl From<Error> for PhpException {
156
    fn from(err: Error) -> Self {
×
157
        Self::default(err.to_string())
×
158
    }
×
159
}
160

161
/// Trigger an error that is reported in PHP the same way `trigger_error()` is.
162
///
163
/// See specific error type descriptions at <https://www.php.net/manual/en/errorfunc.constants.php>.
164
///
165
/// # Panics
166
///
167
/// * If the error type bits exceed `i32::MAX`.
168
pub fn php_error(type_: &ErrorType, message: &str) {
×
169
    let Ok(c_string) = CString::new(message) else {
×
170
        return;
×
171
    };
172

173
    unsafe {
×
174
        php_error_docref(
×
175
            std::ptr::null(),
×
176
            type_.bits().try_into().expect("Error type flags overflown"),
×
177
            c_string.as_ptr(),
×
178
        );
×
179
    }
×
180
}
×
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

© 2026 Coveralls, Inc