Skip to content

Commit 3f50e7e

Browse files
authored
Merge pull request #214 from davidcole1340/throw-exception-object
Add support for throwing Exception objects
2 parents 9fa97a4 + 6fdd6a3 commit 3f50e7e

File tree

3 files changed

+70
-2
lines changed

3 files changed

+70
-2
lines changed

allowed_bindings.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ bind! {
112112
zend_string,
113113
zend_string_init_interned,
114114
zend_throw_exception_ex,
115+
zend_throw_exception_object,
115116
zend_type,
116117
zend_value,
117118
zend_wrong_parameters_count_error,

docsrs_bindings.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2242,6 +2242,9 @@ extern "C" {
22422242
...
22432243
) -> *mut zend_object;
22442244
}
2245+
extern "C" {
2246+
pub fn zend_throw_exception_object(exception: *mut zval);
2247+
}
22452248
extern "C" {
22462249
pub fn zend_do_implement_interface(ce: *mut zend_class_entry, iface: *mut zend_class_entry);
22472250
}

src/exception.rs

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ use crate::{
66
class::RegisteredClass,
77
error::{Error, Result},
88
ffi::zend_throw_exception_ex,
9+
ffi::zend_throw_exception_object,
910
flags::ClassFlags,
11+
types::Zval,
1012
zend::{ce, ClassEntry},
1113
};
1214

@@ -25,6 +27,7 @@ pub struct PhpException {
2527
message: String,
2628
code: i32,
2729
ex: &'static ClassEntry,
30+
object: Option<Zval>,
2831
}
2932

3033
impl PhpException {
@@ -36,7 +39,12 @@ impl PhpException {
3639
/// * `code` - Integer code to go inside the exception.
3740
/// * `ex` - Exception type to throw.
3841
pub fn new(message: String, code: i32, ex: &'static ClassEntry) -> Self {
39-
Self { message, code, ex }
42+
Self {
43+
message,
44+
code,
45+
ex,
46+
object: None,
47+
}
4048
}
4149

4250
/// Creates a new default exception instance, using the default PHP
@@ -59,10 +67,25 @@ impl PhpException {
5967
Self::new(message, 0, T::get_metadata().ce())
6068
}
6169

70+
/// Set the Zval object for the exception.
71+
///
72+
/// Exceptions can be based of instantiated Zval objects when you are throwing a custom exception with
73+
/// stateful properties.
74+
///
75+
/// # Parameters
76+
///
77+
/// * `object` - The Zval object.
78+
pub fn set_object(&mut self, object: Option<Zval>) {
79+
self.object = object;
80+
}
81+
6282
/// Throws the exception, returning nothing inside a result if successful
6383
/// and an error otherwise.
6484
pub fn throw(self) -> Result<()> {
65-
throw_with_code(self.ex, self.code, &self.message)
85+
match self.object {
86+
Some(object) => throw_object(object),
87+
None => throw_with_code(self.ex, self.code, &self.message),
88+
}
6689
}
6790
}
6891

@@ -146,3 +169,44 @@ pub fn throw_with_code(ex: &ClassEntry, code: i32, message: &str) -> Result<()>
146169
};
147170
Ok(())
148171
}
172+
173+
/// Throws an exception object.
174+
///
175+
/// Returns a result containing nothing if the exception was successfully
176+
/// thrown.
177+
///
178+
/// # Parameters
179+
///
180+
/// * `object` - The zval of type object
181+
///
182+
/// # Examples
183+
///
184+
/// ```no_run
185+
/// use ext_php_rs::prelude::*;
186+
/// use ext_php_rs::exception::throw_object;
187+
/// use crate::ext_php_rs::convert::IntoZval;
188+
///
189+
/// #[php_class]
190+
/// #[extends(ext_php_rs::zend::ce::exception())]
191+
/// pub struct JsException {
192+
/// #[prop(flags = ext_php_rs::flags::PropertyFlags::Public)]
193+
/// message: String,
194+
/// #[prop(flags = ext_php_rs::flags::PropertyFlags::Public)]
195+
/// code: i32,
196+
/// #[prop(flags = ext_php_rs::flags::PropertyFlags::Public)]
197+
/// file: String,
198+
/// }
199+
///
200+
/// #[php_module]
201+
/// pub fn get_module(module: ModuleBuilder) -> ModuleBuilder {
202+
/// module
203+
/// }
204+
///
205+
/// let error = JsException { message: "A JS error occurred.".to_string(), code: 100, file: "index.js".to_string() };
206+
/// throw_object( error.into_zval(true).unwrap() );
207+
/// ```
208+
pub fn throw_object(zval: Zval) -> Result<()> {
209+
let mut zv = core::mem::ManuallyDrop::new(zval);
210+
unsafe { zend_throw_exception_object(core::ptr::addr_of_mut!(zv).cast()) };
211+
Ok(())
212+
}

0 commit comments

Comments
 (0)