diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..ddf2c8f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,42 @@ +name: CI + +on: + push: + branches: + - main + pull_request: + +jobs: + test: + name: "Build and test" + runs-on: ubuntu-latest + continue-on-error: false + strategy: + fail-fast: false + matrix: + php: ['8.3', '8.4', '8.5'] + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + tools: phpize + + - name: Set up + run: phpize + + - name: Configure + run: ./configure --enable-custom_cast + + - name: Make and install + run: sudo make -j"$(nproc)" install + + - name: Run tests + run: >- + REPORT_EXIT_STATUS=1 + NO_INTERACTION=1 + TEST_PHP_EXECUTABLE=$(which php) + php run-tests.php -n --show-diff tests diff --git a/custom_cast.c b/custom_cast.c index d0c2a30..f59e056 100644 --- a/custom_cast.c +++ b/custom_cast.c @@ -267,25 +267,22 @@ static zend_result custom_cast_do_cast( /** * Ensure that the flags for a class entry correspond to a userland class */ -static void require_user_class(uint32_t flags) { +static const char* require_user_class(uint32_t flags) { // Must actually be on a class if (flags & ZEND_ACC_ENUM) { - zend_error_noreturn(E_ERROR, "Cannot apply #[CustomCasting\\CustomCastable] to enum"); + return "Cannot apply #[CustomCasting\\CustomCastable] to enum"; } if (flags & ZEND_ACC_INTERFACE) { - zend_error_noreturn(E_ERROR, "Cannot apply #[CustomCasting\\CustomCastable] to interface"); + return "Cannot apply #[CustomCasting\\CustomCastable] to interface"; } if (flags & ZEND_ACC_TRAIT) { - zend_error_noreturn(E_ERROR, "Cannot apply #[CustomCasting\\CustomCastable] to trait"); + return "Cannot apply #[CustomCasting\\CustomCastable] to trait"; } // Use ce->type != ZEND_INTERNAL_CLASS if (flags & ZEND_ACC_LINKED) { - zend_error_noreturn( - E_ERROR, - "#[CustomCasting\\CustomCastable] is for user classes, internal classes can set a custom cast handler" - ); + return "#[CustomCasting\\CustomCastable] is for user classes, internal classes can set a custom cast handler"; } - + return NULL; } /** @@ -378,12 +375,27 @@ static void ensure_class_has_interface(zend_class_entry *scope) { scope->interface_names = newInterfaceSet; } +#if PHP_VERSION_ID < 80500 static void validate_custom_castable( zend_attribute *attr, uint32_t target, zend_class_entry *scope) +#else +static zend_string *validate_custom_castable( + zend_attribute *attr, uint32_t target, zend_class_entry *scope) +#endif { - require_user_class(scope->ce_flags); + const char *error = require_user_class(scope->ce_flags); + if (error != NULL) { +#if PHP_VERSION_ID < 80500 + zend_error_noreturn(E_ERROR, error); +#else + return zend_string_init(error, strlen(error), 0); +#endif + } ensure_class_has_interface(scope); scope->default_object_handlers = &custom_cast_obj_handlers; +#if PHP_VERSION_ID >= 80500 + return NULL; +#endif } static void setup_CustomCastable_as_attribute(zend_class_entry *class_entry) { diff --git a/tests/attribute_on_wrong/attribute_on_class_missing.phpt b/tests/attribute_on_wrong/attribute_on_class_missing.phpt index 6c8577c..6849b21 100644 --- a/tests/attribute_on_wrong/attribute_on_class_missing.phpt +++ b/tests/attribute_on_wrong/attribute_on_class_missing.phpt @@ -13,4 +13,4 @@ class Demo { ?> --EXPECTF-- -Fatal error: Class Demo contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (CustomCasting\HasCustomCast::__doCast) in %s on line %d \ No newline at end of file +Fatal error: Class Demo contains 1 abstract method and must therefore be declared abstract or implement the remaining method%rs?%r (CustomCasting\HasCustomCast::__doCast) in %s on line %d \ No newline at end of file