-
-
Notifications
You must be signed in to change notification settings - Fork 79
Description
I have been struggling trying to implement the following:
<?php
final class FooException extends Exception {
public static function from_bar(string $bar): self {
return new self("Bar: " . $bar);
}
}I tried the following:
#[derive(Debug)]
#[php_class]
#[extends(ce::exception)]
pub struct FooException {}
#[php_impl]
impl FooException {
pub fn from_bar() -> Zval {
let zval: Zval = ZendClassObject::new(FooException {}).into_zval(false).unwrap();
zval
}
}this results in an error when calling FooException::from_bar() ( trying to call non-static method statically ).
i tried making from_bar() into a function, but this also didn't work, as non of the exception properties were initialized, the exception will always not have a backtrace, ( file being "" , and line being 0 )
I initially tried to create the object and call it's constructor:
this one works, but it's the same as before, backtrace is completely missing, while it works perfectly for "normal" classes, it fails for Exceptions, i believe there's a zend function that i should call on the exception object before/after constructing it, but i can't find it ( yet ) in the ZEND API.
use ext_php_rs::error::Result;
use ext_php_rs::ffi;
use ext_php_rs::types::Zval;
use ext_php_rs::zend::ClassEntry;
pub fn construct(class: &ClassEntry, arguments: &[Zval]) -> Result<Zval> {
let len = arguments.len();
let class_ptr = class as *const _ as *mut _;
let constructor_ptr = class.constructor;
let object = unsafe {
let zend_object = ffi::zend_objects_new(class_ptr);
ffi::object_properties_init(zend_object, class_ptr);
ffi::zend_call_known_function(
constructor_ptr,
zend_object,
class_ptr,
std::ptr::null_mut(),
len as _,
arguments.as_ptr() as _,
std::ptr::null_mut(),
);
zend_object
.as_mut()
.expect("error: failed to allocate memory for object")
};
let mut result = Zval::new();
result.set_object(object);
Ok(result)
}
pub extern "C" fn from_bar(ex: &mut ExecuteData, retval: &mut Zval) {
if ex.parser().parse().is_err() {
return;
}
let ce = /* exception class entry */;
let c = construct(ce, &["bar!.".into_zval(false).unwrap()]).unwrap();
*retval = c;
}So the solution i found, is the following, which is extremely slow:
macro_rules! throw {
($ce:expr, $message:expr) => {
let e: ::ext_php_rs::exception::PhpException =
::ext_php_rs::exception::PhpException::new($message.to_string(), 0, $ce);
e.throw()
.expect(&format!("Failed to throw exception: {}", $message));
};
}
pub extern "C" fn from_bar(ex: &mut ExecuteData, retval: &mut Zval) {
if ex.parser().parse().is_err() {
return;
}
let ce = /* exception class entry */;
throw!(ce, "bar!");
let object = ExecutorGlobals::take_exception().unwrap();
retval.set_object(object.into_raw());
}any help would be appreciated :)