From 349d4977930cd21124e75cfb3136b89c4dce2018 Mon Sep 17 00:00:00 2001 From: David Date: Sun, 18 Apr 2021 15:52:02 +1200 Subject: [PATCH] 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. --- example/skel/src/lib.rs | 5 +- example/skel/test.php | 4 +- src/php/errors.rs | 66 ----------------------- src/php/exceptions.rs | 117 ++++++++++++++++++++++++++++++++++++++++ src/php/mod.rs | 2 +- 5 files changed, 125 insertions(+), 69 deletions(-) delete mode 100644 src/php/errors.rs create mode 100644 src/php/exceptions.rs diff --git a/example/skel/src/lib.rs b/example/skel/src/lib.rs index 3a03145..2a0d898 100644 --- a/example/skel/src/lib.rs +++ b/example/skel/src/lib.rs @@ -2,8 +2,9 @@ use ext_php_rs::{ call_user_func, info_table_end, info_table_row, info_table_start, parse_args, php::{ args::{Arg, ArgParser}, - class::ClassBuilder, + class::{ClassBuilder, ClassEntry}, enums::DataType, + exceptions::throw, execution_data::ExecutionData, flags::MethodFlags, function::FunctionBuilder, @@ -148,6 +149,8 @@ pub extern "C" fn skeleton_version(execute_data: &mut ExecutionData, _retval: &m return; } + throw(ClassEntry::exception(), "Hello!"); + let result = format!( "x: {}, y: {}, z: {}", x.val::().unwrap_or_default(), diff --git a/example/skel/test.php b/example/skel/test.php index 48856e3..79ce4ae 100644 --- a/example/skel/test.php +++ b/example/skel/test.php @@ -2,9 +2,11 @@ $x = new TestClass(); +skeleton_version(1, 2); + var_dump($x->call(function ($v1, $v2) { // var_dump($v1, $v2); // echo "Hello, world! I'm a callable.".PHP_EOL; // return "Ok rust"; return 0; -})); \ No newline at end of file +})); diff --git a/src/php/errors.rs b/src/php/errors.rs deleted file mode 100644 index 6e9907f..0000000 --- a/src/php/errors.rs +++ /dev/null @@ -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() } - } -} diff --git a/src/php/exceptions.rs b/src/php/exceptions.rs new file mode 100644 index 0000000..37cf6c0 --- /dev/null +++ b/src/php/exceptions.rs @@ -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() + } +} diff --git a/src/php/mod.rs b/src/php/mod.rs index 90b9d02..978b52f 100644 --- a/src/php/mod.rs +++ b/src/php/mod.rs @@ -3,7 +3,7 @@ pub mod args; pub mod class; pub mod enums; -pub mod errors; +pub mod exceptions; pub mod execution_data; pub mod flags; pub mod function;