Added ability to throw exceptions (#21)

* Exceptions have static lifetimes

* Added functions for throwing exceptions

Changed the `ClassEntry` implementation to unwrap the result before
returning, as these types are guaranteed to be valid. Also replaced the
'a lifetime with 'static lifetimes.
This commit is contained in:
David 2021-04-18 15:52:02 +12:00 committed by GitHub
parent 35808d9e49
commit 349d497793
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 125 additions and 69 deletions

View File

@ -2,8 +2,9 @@ use ext_php_rs::{
call_user_func, info_table_end, info_table_row, info_table_start, parse_args, call_user_func, info_table_end, info_table_row, info_table_start, parse_args,
php::{ php::{
args::{Arg, ArgParser}, args::{Arg, ArgParser},
class::ClassBuilder, class::{ClassBuilder, ClassEntry},
enums::DataType, enums::DataType,
exceptions::throw,
execution_data::ExecutionData, execution_data::ExecutionData,
flags::MethodFlags, flags::MethodFlags,
function::FunctionBuilder, function::FunctionBuilder,
@ -148,6 +149,8 @@ pub extern "C" fn skeleton_version(execute_data: &mut ExecutionData, _retval: &m
return; return;
} }
throw(ClassEntry::exception(), "Hello!");
let result = format!( let result = format!(
"x: {}, y: {}, z: {}", "x: {}, y: {}, z: {}",
x.val::<ZendLong>().unwrap_or_default(), x.val::<ZendLong>().unwrap_or_default(),

View File

@ -2,9 +2,11 @@
$x = new TestClass(); $x = new TestClass();
skeleton_version(1, 2);
var_dump($x->call(function ($v1, $v2) { var_dump($x->call(function ($v1, $v2) {
// var_dump($v1, $v2); // var_dump($v1, $v2);
// echo "Hello, world! I'm a callable.".PHP_EOL; // echo "Hello, world! I'm a callable.".PHP_EOL;
// return "Ok rust"; // return "Ok rust";
return 0; return 0;
})); }));

View File

@ -1,66 +0,0 @@
//! Contains all the base PHP throwables, including `Throwable` and `Exception`.
use super::class::ClassEntry;
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,
};
impl ClassEntry {
/// Returns the base `Throwable` class.
pub fn throwable<'a>() -> Option<&'a Self> {
unsafe { zend_ce_throwable.as_ref() }
}
/// Returns the base `Exception` class.
pub fn exception<'a>() -> Option<&'a Self> {
unsafe { zend_ce_exception.as_ref() }
}
/// Returns the base `ErrorException` class.
pub fn error_exception<'a>() -> Option<&'a Self> {
unsafe { zend_ce_error_exception.as_ref() }
}
/// Returns the base `CompileError` class.
pub fn compile_error<'a>() -> Option<&'a Self> {
unsafe { zend_ce_compile_error.as_ref() }
}
/// Returns the base `ParseError` class.
pub fn parse_error<'a>() -> Option<&'a Self> {
unsafe { zend_ce_parse_error.as_ref() }
}
/// Returns the base `TypeError` class.
pub fn type_error<'a>() -> Option<&'a Self> {
unsafe { zend_ce_type_error.as_ref() }
}
/// Returns the base `ArgumentCountError` class.
pub fn argument_count_error<'a>() -> Option<&'a Self> {
unsafe { zend_ce_argument_count_error.as_ref() }
}
/// Returns the base `ValueError` class.
pub fn value_error<'a>() -> Option<&'a Self> {
unsafe { zend_ce_value_error.as_ref() }
}
/// Returns the base `ArithmeticError` class.
pub fn arithmetic_error<'a>() -> Option<&'a Self> {
unsafe { zend_ce_arithmetic_error.as_ref() }
}
/// Returns the base `DivisionByZeroError` class.
pub fn division_by_zero_error<'a>() -> Option<&'a Self> {
unsafe { zend_ce_division_by_zero_error.as_ref() }
}
/// Returns the base `UnhandledMatchError` class.
pub fn unhandled_match_error<'a>() -> Option<&'a Self> {
unsafe { zend_ce_unhandled_match_error.as_ref() }
}
}

117
src/php/exceptions.rs Normal file
View File

@ -0,0 +1,117 @@
//! Contains all the base PHP throwables, including `Throwable` and `Exception`.
use super::class::ClassEntry;
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,
},
functions::c_str,
};
/// Throws an exception with a given message. See [`ClassEntry`] for some built-in exception
/// types.
///
/// # Parameters
///
/// * `ex` - The exception type to throw.
/// * `message` - The message to display when throwing the exception.
///
/// # Examples
///
/// ```no_run
/// use ext_php_rs::php::{class::ClassEntry, exceptions::throw};
///
/// throw(ClassEntry::compile_error(), "This is a CompileError.");
/// ```
pub fn throw(ex: &ClassEntry, message: &str) {
throw_with_code(ex, 0, message);
}
/// Throws an exception with a given message and status code. See [`ClassEntry`] for some built-in
/// exception types.
///
/// # Parameters
///
/// * `ex` - The exception type to throw.
/// * `code` - The status code to use when throwing the exception.
/// * `message` - The message to display when throwing the exception.
///
/// # Examples
///
/// ```no_run
/// use ext_php_rs::php::{class::ClassEntry, exceptions::throw_with_code};
///
/// throw_with_code(ClassEntry::compile_error(), 123, "This is a CompileError.");
/// ```
pub fn throw_with_code(ex: &ClassEntry, code: i32, message: &str) {
// SAFETY: We are given a reference to a `ClassEntry` therefore when we cast it to a pointer it
// will be valid.
unsafe {
zend_throw_exception_ex(
(ex as *const _) as *mut _,
code as _,
c_str("%s"),
c_str(message),
)
};
}
impl ClassEntry {
/// Returns the base `Throwable` class.
pub fn throwable() -> &'static Self {
unsafe { zend_ce_throwable.as_ref() }.unwrap()
}
/// Returns the base `Exception` class.
pub fn exception() -> &'static Self {
unsafe { zend_ce_exception.as_ref() }.unwrap()
}
/// Returns the base `ErrorException` class.
pub fn error_exception() -> &'static Self {
unsafe { zend_ce_error_exception.as_ref() }.unwrap()
}
/// Returns the base `CompileError` class.
pub fn compile_error() -> &'static Self {
unsafe { zend_ce_compile_error.as_ref() }.unwrap()
}
/// Returns the base `ParseError` class.
pub fn parse_error() -> &'static Self {
unsafe { zend_ce_parse_error.as_ref() }.unwrap()
}
/// Returns the base `TypeError` class.
pub fn type_error() -> &'static Self {
unsafe { zend_ce_type_error.as_ref() }.unwrap()
}
/// Returns the base `ArgumentCountError` class.
pub fn argument_count_error() -> &'static Self {
unsafe { zend_ce_argument_count_error.as_ref() }.unwrap()
}
/// Returns the base `ValueError` class.
pub fn value_error() -> &'static Self {
unsafe { zend_ce_value_error.as_ref() }.unwrap()
}
/// Returns the base `ArithmeticError` class.
pub fn arithmetic_error() -> &'static Self {
unsafe { zend_ce_arithmetic_error.as_ref() }.unwrap()
}
/// Returns the base `DivisionByZeroError` class.
pub fn division_by_zero_error() -> &'static Self {
unsafe { zend_ce_division_by_zero_error.as_ref() }.unwrap()
}
/// Returns the base `UnhandledMatchError` class.
pub fn unhandled_match_error() -> &'static Self {
unsafe { zend_ce_unhandled_match_error.as_ref() }.unwrap()
}
}

View File

@ -3,7 +3,7 @@
pub mod args; pub mod args;
pub mod class; pub mod class;
pub mod enums; pub mod enums;
pub mod errors; pub mod exceptions;
pub mod execution_data; pub mod execution_data;
pub mod flags; pub mod flags;
pub mod function; pub mod function;