use std::ffi::CString;
use super::{class::ClassEntry, types::object::RegisteredClass};
use crate::{
bindings::{
zend_ce_argument_count_error, zend_ce_arithmetic_error, zend_ce_compile_error,
zend_ce_division_by_zero_error, zend_ce_error_exception, zend_ce_exception,
zend_ce_parse_error, zend_ce_throwable, zend_ce_type_error, zend_ce_unhandled_match_error,
zend_ce_value_error, zend_throw_exception_ex,
},
errors::{Error, Result},
php::flags::ClassFlags,
};
pub type PhpResult<T = ()> = std::result::Result<T, PhpException<'static>>;
#[derive(Debug)]
pub struct PhpException<'a> {
message: String,
code: i32,
ex: &'a ClassEntry,
}
impl<'a> PhpException<'a> {
pub fn new(message: String, code: i32, ex: &'a ClassEntry) -> Self {
Self { message, code, ex }
}
pub fn default(message: String) -> Self {
Self::new(message, 0, ClassEntry::exception())
}
pub fn from_class<T: RegisteredClass>(message: String) -> Self {
Self::new(message, 0, T::get_metadata().ce())
}
pub fn throw(self) -> Result<()> {
throw_with_code(self.ex, self.code, &self.message)
}
}
impl<'a> From<String> for PhpException<'a> {
fn from(str: String) -> Self {
Self::default(str)
}
}
impl<'a> From<&str> for PhpException<'a> {
fn from(str: &str) -> Self {
Self::default(str.into())
}
}
pub fn throw(ex: &ClassEntry, message: &str) -> Result<()> {
throw_with_code(ex, 0, message)
}
pub fn throw_with_code(ex: &ClassEntry, code: i32, message: &str) -> Result<()> {
let flags = ex.flags();
if flags.contains(ClassFlags::Interface) || flags.contains(ClassFlags::Abstract) {
return Err(Error::InvalidException(flags));
}
unsafe {
zend_throw_exception_ex(
(ex as *const _) as *mut _,
code as _,
CString::new("%s")?.as_ptr(),
CString::new(message)?.as_ptr(),
)
};
Ok(())
}
#[allow(clippy::unwrap_used)]
impl ClassEntry {
pub fn throwable() -> &'static Self {
unsafe { zend_ce_throwable.as_ref() }.unwrap()
}
pub fn exception() -> &'static Self {
unsafe { zend_ce_exception.as_ref() }.unwrap()
}
pub fn error_exception() -> &'static Self {
unsafe { zend_ce_error_exception.as_ref() }.unwrap()
}
pub fn compile_error() -> &'static Self {
unsafe { zend_ce_compile_error.as_ref() }.unwrap()
}
pub fn parse_error() -> &'static Self {
unsafe { zend_ce_parse_error.as_ref() }.unwrap()
}
pub fn type_error() -> &'static Self {
unsafe { zend_ce_type_error.as_ref() }.unwrap()
}
pub fn argument_count_error() -> &'static Self {
unsafe { zend_ce_argument_count_error.as_ref() }.unwrap()
}
pub fn value_error() -> &'static Self {
unsafe { zend_ce_value_error.as_ref() }.unwrap()
}
pub fn arithmetic_error() -> &'static Self {
unsafe { zend_ce_arithmetic_error.as_ref() }.unwrap()
}
pub fn division_by_zero_error() -> &'static Self {
unsafe { zend_ce_division_by_zero_error.as_ref() }.unwrap()
}
pub fn unhandled_match_error() -> &'static Self {
unsafe { zend_ce_unhandled_match_error.as_ref() }.unwrap()
}
}