From 2e485c227100a293af053bcdfa4d09fd0a3b0c7c Mon Sep 17 00:00:00 2001 From: Anton Vasiliev Date: Fri, 12 Nov 2021 23:39:08 +0000 Subject: [PATCH 01/13] #2321 - Add failing test case --- stub/closures.zep | 22 ++++++++++++++++++++++ tests/Extension/ClosureTest.php | 7 +++++++ 2 files changed, 29 insertions(+) diff --git a/stub/closures.zep b/stub/closures.zep index f37c3d88e..e52aee0e2 100644 --- a/stub/closures.zep +++ b/stub/closures.zep @@ -97,4 +97,26 @@ class Closures { return call_user_func(this->_function, this->_argument); } + + /** + * @issue https://github.com/zephir-lang/zephir/issues/2321 + */ + public function issue2321CallPrivateCallback() -> string + { + return this->issue2321filterQuery("filtered_value"); + } + + private function issue2321filterQuery(string value) -> string + { + return preg_replace_callback( + "/(?:[^%:!\$&\'\(\)\*\+,;=@\/\?]+|%(?![A-Fa-f0-9]{2}))/u", + [this, "doUrlEncode"], + value + ); + } + + private function issue2321doUrlEncode(array matches) -> string + { + return rawurlencode(matches[0]); + } } diff --git a/tests/Extension/ClosureTest.php b/tests/Extension/ClosureTest.php index e84ce190d..bf80607bf 100644 --- a/tests/Extension/ClosureTest.php +++ b/tests/Extension/ClosureTest.php @@ -40,4 +40,11 @@ public function testIssue1036(): void $this->assertTrue($test->issue1036Call()); } + + public function testIssue2321CallPrivateCallbackViaPrivateMethod(): void + { + $test = new Closures(); + + $this->assertSame('filtered_value', $test->issue2321CallPrivateCallback()); + } } From d619bcb00ec08a93ca56ee87d468ae200764633f Mon Sep 17 00:00:00 2001 From: Anton Vasiliev Date: Fri, 12 Nov 2021 23:39:55 +0000 Subject: [PATCH 02/13] #2321 - Partial refactor of `populate_fcic()` function --- kernels/ZendEngine3/fcall.c | 37 ++++++++++++++++++++++++------------- kernels/ZendEngine3/fcall.h | 12 +++++++++--- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/kernels/ZendEngine3/fcall.c b/kernels/ZendEngine3/fcall.c index 447d28104..81294536a 100755 --- a/kernels/ZendEngine3/fcall.c +++ b/kernels/ZendEngine3/fcall.c @@ -298,24 +298,30 @@ static void populate_fcic(zend_fcall_info_cache* fcic, zephir_call_type type, ze case zephir_fcall_method: if (Z_TYPE_P(func) == IS_OBJECT) { #if PHP_VERSION_ID >= 80000 - if (Z_OBJ_HANDLER_P(func, get_closure) && Z_OBJ_HANDLER_P(func, get_closure)(Z_OBJ_P(func), &fcic->calling_scope, &fcic->function_handler, &fcic->object, 0) == SUCCESS) { + if (Z_OBJ_HANDLER_P(func, get_closure)(Z_OBJ_P(func), &fcic->calling_scope, &fcic->function_handler, &fcic->object, 0) == SUCCESS) { #else - if (Z_OBJ_HANDLER_P(func, get_closure) && Z_OBJ_HANDLER_P(func, get_closure)(func, &fcic->calling_scope, &fcic->function_handler, &fcic->object) == SUCCESS) { + if (Z_OBJ_HANDLER_P(func, get_closure)(func, &fcic->calling_scope, &fcic->function_handler, &fcic->object) == SUCCESS) { #endif fcic->called_scope = fcic->calling_scope; break; } - return; - } + if (Z_TYPE_P(this_ptr) == IS_OBJECT) { + fcic->calling_scope = Z_OBJCE_P(this_ptr); + } + return; + } else if (Z_TYPE_P(func) == IS_STRING) { + if (ce) { + fcic->calling_scope = ce; #if PHP_VERSION_ID >= 80000 - if (ce && Z_TYPE_P(func) == IS_STRING) { - fcic->function_handler = zend_hash_find_ptr(&ce->function_table, Z_STR_P(func)); - } + fcic->function_handler = zend_hash_find_ptr(&ce->function_table, Z_STR_P(func)); #endif - fcic->calling_scope = this_ptr ? Z_OBJCE_P(this_ptr) : NULL; - fcic->called_scope = fcic->calling_scope; + } + + return; + } + break; default: @@ -482,10 +488,15 @@ int zephir_call_user_function( return status; } -int zephir_call_func_aparams(zval *return_value_ptr, const char *func_name, uint32_t func_length, - zephir_fcall_cache_entry **cache_entry, int cache_slot, - uint32_t param_count, zval **params) -{ +int zephir_call_func_aparams( + zval *return_value_ptr, + const char *func_name, + uint32_t func_length, + zephir_fcall_cache_entry **cache_entry, + int cache_slot, + uint32_t param_count, + zval **params +) { int status; zval rv, *rvp = return_value_ptr ? return_value_ptr : &rv; diff --git a/kernels/ZendEngine3/fcall.h b/kernels/ZendEngine3/fcall.h index 258136075..26c52a4e2 100755 --- a/kernels/ZendEngine3/fcall.h +++ b/kernels/ZendEngine3/fcall.h @@ -311,9 +311,15 @@ int zephir_call_class_method_aparams( uint32_t param_count, zval **params) ZEPHIR_ATTR_WARN_UNUSED_RESULT; -ZEPHIR_ATTR_WARN_UNUSED_RESULT static inline int zephir_return_call_function(zval *return_value, - const char *func, uint32_t func_len, zephir_fcall_cache_entry **cache_entry, int cache_slot, uint32_t param_count, zval **params) -{ +ZEPHIR_ATTR_WARN_UNUSED_RESULT static inline int zephir_return_call_function( + zval *return_value, + const char *func, + uint32_t func_len, + zephir_fcall_cache_entry **cache_entry, + int cache_slot, + uint32_t param_count, + zval **params +) { zval rv, *rvp = return_value ? return_value : &rv; int status; From faf3f2bcecfc74032dbfe59900b8531e2e922de7 Mon Sep 17 00:00:00 2001 From: Anton Vasiliev Date: Sat, 13 Nov 2021 23:04:16 +0000 Subject: [PATCH 03/13] #2321 - Adjust method name --- stub/closures.zep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stub/closures.zep b/stub/closures.zep index e52aee0e2..bf1366a20 100644 --- a/stub/closures.zep +++ b/stub/closures.zep @@ -110,7 +110,7 @@ class Closures { return preg_replace_callback( "/(?:[^%:!\$&\'\(\)\*\+,;=@\/\?]+|%(?![A-Fa-f0-9]{2}))/u", - [this, "doUrlEncode"], + [this, "issue2321doUrlEncode"], value ); } From 0a30a367a13a259947ac300e5c6f590d804010a5 Mon Sep 17 00:00:00 2001 From: Anton Vasiliev Date: Sat, 13 Nov 2021 23:05:49 +0000 Subject: [PATCH 04/13] #2321 - Refactor `populate_fcic()` function --- kernels/ZendEngine3/fcall.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/kernels/ZendEngine3/fcall.c b/kernels/ZendEngine3/fcall.c index 81294536a..5eb86887b 100755 --- a/kernels/ZendEngine3/fcall.c +++ b/kernels/ZendEngine3/fcall.c @@ -279,19 +279,16 @@ static void populate_fcic(zend_fcall_info_cache* fcic, zephir_call_type type, ze break; case zephir_fcall_ce: + fcic->calling_scope = ce; + #if PHP_VERSION_ID >= 80000 if (ce && Z_TYPE_P(func) == IS_STRING) { fcic->function_handler = zend_hash_find_ptr(&ce->function_table, Z_STR_P(func)); - - fcic->calling_scope = ce; } else if (calling_scope && Z_TYPE_P(func) == IS_STRING) { fcic->function_handler = zend_hash_find_ptr(&calling_scope->function_table, Z_STR_P(func)); fcic->calling_scope = calling_scope; } #endif - // TODO: Check for PHP 7.4 and PHP 8.0, as it rewrite from above - fcic->calling_scope = ce; - fcic->called_scope = ce; break; case zephir_fcall_function: @@ -323,9 +320,6 @@ static void populate_fcic(zend_fcall_info_cache* fcic, zephir_call_type type, ze } break; - - default: - return; } } From 67eaae130d1f871000c31ce82e3bd818965d7807 Mon Sep 17 00:00:00 2001 From: Anton Vasiliev Date: Sat, 13 Nov 2021 23:39:10 +0000 Subject: [PATCH 05/13] #2321 - Fix `zephir_fcall_ce` case --- kernels/ZendEngine3/fcall.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernels/ZendEngine3/fcall.c b/kernels/ZendEngine3/fcall.c index 5eb86887b..e2ca1fcf7 100755 --- a/kernels/ZendEngine3/fcall.c +++ b/kernels/ZendEngine3/fcall.c @@ -280,6 +280,7 @@ static void populate_fcic(zend_fcall_info_cache* fcic, zephir_call_type type, ze case zephir_fcall_ce: fcic->calling_scope = ce; + fcic->called_scope = ce; #if PHP_VERSION_ID >= 80000 if (ce && Z_TYPE_P(func) == IS_STRING) { From 8018a60e4175ece972c7f8398ee7a2ca75146a40 Mon Sep 17 00:00:00 2001 From: Anton Vasiliev Date: Sat, 13 Nov 2021 23:43:08 +0000 Subject: [PATCH 06/13] #2321 - Improve condition in `zephir_fcall_ce` case --- kernels/ZendEngine3/fcall.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/kernels/ZendEngine3/fcall.c b/kernels/ZendEngine3/fcall.c index e2ca1fcf7..c01a53ac4 100755 --- a/kernels/ZendEngine3/fcall.c +++ b/kernels/ZendEngine3/fcall.c @@ -283,11 +283,13 @@ static void populate_fcic(zend_fcall_info_cache* fcic, zephir_call_type type, ze fcic->called_scope = ce; #if PHP_VERSION_ID >= 80000 - if (ce && Z_TYPE_P(func) == IS_STRING) { - fcic->function_handler = zend_hash_find_ptr(&ce->function_table, Z_STR_P(func)); - } else if (calling_scope && Z_TYPE_P(func) == IS_STRING) { - fcic->function_handler = zend_hash_find_ptr(&calling_scope->function_table, Z_STR_P(func)); - fcic->calling_scope = calling_scope; + if (Z_TYPE_P(func) == IS_STRING) { + if (ce) { + fcic->function_handler = zend_hash_find_ptr(&ce->function_table, Z_STR_P(func)); + } else if (calling_scope) { + fcic->function_handler = zend_hash_find_ptr(&calling_scope->function_table, Z_STR_P(func)); + fcic->calling_scope = calling_scope; + } } #endif break; From 61e5ffb41f078a080a981bbaa342f3a6c59b6dd5 Mon Sep 17 00:00:00 2001 From: Anton Vasiliev Date: Sun, 14 Nov 2021 23:10:30 +0000 Subject: [PATCH 07/13] #2321 - Reformat code --- kernels/ZendEngine3/fcall.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/kernels/ZendEngine3/fcall.c b/kernels/ZendEngine3/fcall.c index c01a53ac4..e933ba38c 100755 --- a/kernels/ZendEngine3/fcall.c +++ b/kernels/ZendEngine3/fcall.c @@ -118,14 +118,14 @@ static int zephir_make_fcall_key(zend_string* s, zephir_call_type type, zend_cla if (Z_TYPE_P(function) == IS_STRING) { mth = Z_STRVAL_P(function); mth_len = Z_STRLEN_P(function); - } - else if (Z_TYPE_P(function) == IS_ARRAY) { + } else if (Z_TYPE_P(function) == IS_ARRAY) { zval *method; HashTable *function_hash = Z_ARRVAL_P(function); + if ( - function_hash->nNumOfElements == 2 - && ((method = zend_hash_index_find(function_hash, 1)) != NULL) - && Z_TYPE_P(method) == IS_STRING + function_hash->nNumOfElements == 2 && + ((method = zend_hash_index_find(function_hash, 1)) != NULL) && + Z_TYPE_P(method) == IS_STRING ) { mth = Z_STRVAL_P(method); mth_len = Z_STRLEN_P(method); @@ -452,7 +452,8 @@ int zephir_call_user_function( zval_ptr_dtor(&callable); } - /* Skip caching IF: + /** + * Skip caching IF: * call failed OR there was an exception (to be safe) OR cache key is not defined OR * fcall cache was de-initialized OR we have a slot cache */ @@ -525,10 +526,14 @@ int zephir_call_func_aparams( return status; } -int zephir_call_zval_func_aparams(zval *return_value_ptr, zval *func_name, - zephir_fcall_cache_entry **cache_entry, int cache_slot, - uint32_t param_count, zval **params) -{ +int zephir_call_zval_func_aparams( + zval *return_value_ptr, + zval *func_name, + zephir_fcall_cache_entry **cache_entry, + int cache_slot, + uint32_t param_count, + zval **params +) { int status; zval rv, *rvp = return_value_ptr ? return_value_ptr : &rv; @@ -708,8 +713,7 @@ void zephir_eval_php(zval *str, zval *retval_ptr, char *context) #endif CG(compiler_options) = original_compiler_options; - if (new_op_array) - { + if (new_op_array) { EG(no_extensions) = 1; zend_try { zend_execute(new_op_array, &local_retval); From 599e17113f0543de69ea7c64a5628fbe6502ebea Mon Sep 17 00:00:00 2001 From: Anton Vasiliev Date: Sun, 21 Nov 2021 19:13:48 +0000 Subject: [PATCH 08/13] #2321 - Update `composer.lock` --- composer.lock | 78 +++++++++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/composer.lock b/composer.lock index 89d4d6efe..7c4e3c67d 100644 --- a/composer.lock +++ b/composer.lock @@ -107,20 +107,20 @@ }, { "name": "psr/container", - "version": "1.1.1", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/php-fig/container.git", - "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf" + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf", - "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", "shasum": "" }, "require": { - "php": ">=7.2.0" + "php": ">=7.4.0" }, "type": "library", "autoload": { @@ -149,9 +149,9 @@ ], "support": { "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.1" + "source": "https://github.com/php-fig/container/tree/1.1.2" }, - "time": "2021-03-05T17:36:06+00:00" + "time": "2021-11-05T16:50:12+00:00" }, { "name": "psr/event-dispatcher", @@ -255,16 +255,16 @@ }, { "name": "symfony/console", - "version": "v5.3.7", + "version": "v5.3.10", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "8b1008344647462ae6ec57559da166c2bfa5e16a" + "reference": "d4e409d9fbcfbf71af0e5a940abb7b0b4bad0bd3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/8b1008344647462ae6ec57559da166c2bfa5e16a", - "reference": "8b1008344647462ae6ec57559da166c2bfa5e16a", + "url": "https://api.github.com/repos/symfony/console/zipball/d4e409d9fbcfbf71af0e5a940abb7b0b4bad0bd3", + "reference": "d4e409d9fbcfbf71af0e5a940abb7b0b4bad0bd3", "shasum": "" }, "require": { @@ -334,7 +334,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.3.7" + "source": "https://github.com/symfony/console/tree/v5.3.10" }, "funding": [ { @@ -350,7 +350,7 @@ "type": "tidelift" } ], - "time": "2021-08-25T20:02:16+00:00" + "time": "2021-10-26T09:30:15+00:00" }, { "name": "symfony/deprecation-contracts", @@ -1150,16 +1150,16 @@ }, { "name": "symfony/string", - "version": "v5.3.7", + "version": "v5.3.10", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5" + "reference": "d70c35bb20bbca71fc4ab7921e3c6bda1a82a60c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/8d224396e28d30f81969f083a58763b8b9ceb0a5", - "reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5", + "url": "https://api.github.com/repos/symfony/string/zipball/d70c35bb20bbca71fc4ab7921e3c6bda1a82a60c", + "reference": "d70c35bb20bbca71fc4ab7921e3c6bda1a82a60c", "shasum": "" }, "require": { @@ -1213,7 +1213,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.3.7" + "source": "https://github.com/symfony/string/tree/v5.3.10" }, "funding": [ { @@ -1229,7 +1229,7 @@ "type": "tidelift" } ], - "time": "2021-08-26T08:00:08+00:00" + "time": "2021-10-27T18:21:46+00:00" } ], "packages-dev": [ @@ -1362,16 +1362,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.13.0", + "version": "v4.13.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "50953a2691a922aa1769461637869a0a2faa3f53" + "reference": "63a79e8daa781cac14e5195e63ed8ae231dd10fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/50953a2691a922aa1769461637869a0a2faa3f53", - "reference": "50953a2691a922aa1769461637869a0a2faa3f53", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/63a79e8daa781cac14e5195e63ed8ae231dd10fd", + "reference": "63a79e8daa781cac14e5195e63ed8ae231dd10fd", "shasum": "" }, "require": { @@ -1412,9 +1412,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.1" }, - "time": "2021-09-20T12:20:58+00:00" + "time": "2021-11-03T20:52:16+00:00" }, { "name": "phar-io/manifest", @@ -1756,23 +1756,23 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.7", + "version": "9.2.9", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218" + "reference": "f301eb1453c9e7a1bc912ee8b0ea9db22c60223b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d4c798ed8d51506800b441f7a13ecb0f76f12218", - "reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f301eb1453c9e7a1bc912ee8b0ea9db22c60223b", + "reference": "f301eb1453c9e7a1bc912ee8b0ea9db22c60223b", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.12.0", + "nikic/php-parser": "^4.13.0", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -1821,7 +1821,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.7" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.9" }, "funding": [ { @@ -1829,7 +1829,7 @@ "type": "github" } ], - "time": "2021-09-17T05:39:03+00:00" + "time": "2021-11-19T15:21:02+00:00" }, { "name": "phpunit/php-file-iterator", @@ -2604,16 +2604,16 @@ }, { "name": "sebastian/exporter", - "version": "4.0.3", + "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65" + "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/d89cc98761b8cb5a1a235a6b703ae50d34080e65", - "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/65e8b7db476c5dd267e65eea9cab77584d3cfff9", + "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9", "shasum": "" }, "require": { @@ -2662,14 +2662,14 @@ } ], "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", + "homepage": "https://www.github.com/sebastianbergmann/exporter", "keywords": [ "export", "exporter" ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.3" + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.4" }, "funding": [ { @@ -2677,7 +2677,7 @@ "type": "github" } ], - "time": "2020-09-28T05:24:23+00:00" + "time": "2021-11-11T14:18:36+00:00" }, { "name": "sebastian/global-state", From e0e0cc06d93ee335b783417e8c5f84930fb57255 Mon Sep 17 00:00:00 2001 From: Anton Vasiliev Date: Sun, 21 Nov 2021 20:22:40 +0000 Subject: [PATCH 09/13] #2321 - Merge `bootstrap.php` file into `zephir` file --- Library/bootstrap.php | 30 ------------------------------ zephir | 15 ++++++++++++++- 2 files changed, 14 insertions(+), 31 deletions(-) delete mode 100644 Library/bootstrap.php diff --git a/Library/bootstrap.php b/Library/bootstrap.php deleted file mode 100644 index af05b775f..000000000 --- a/Library/bootstrap.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view - * the LICENSE file that was distributed with this source code. - */ - -namespace Zephir; - -set_error_handler( - static function ($code, $message, $file = '', $line = -1) { - if (error_reporting() & $code) { - throw new \ErrorException($message, 0, $code, (string) $file, $line); - } - } -); - -if (filter_var(getenv('ZEPHIR_DEBUG'), \FILTER_VALIDATE_BOOLEAN)) { - set_exception_handler( - static function (\Throwable $t) { - fwrite(\STDERR, "[ERROR] {$t->getMessage()}".\PHP_EOL); - - exit(1); - } - ); -} diff --git a/zephir b/zephir index 76ce16a52..8ddcc9188 100755 --- a/zephir +++ b/zephir @@ -34,7 +34,20 @@ use Zephir\Parser\Parser; $rootPath = realpath(dirname(__FILE__)); require $rootPath.'/Library/autoload.php'; -require $rootPath.'/Library/bootstrap.php'; + +set_error_handler(static function ($code, $message, $file = '', $line = -1) { + if (error_reporting() & $code) { + throw new ErrorException($message, 0, $code, (string)$file, $line); + } +}); + +if (filter_var(getenv('ZEPHIR_DEBUG'), FILTER_VALIDATE_BOOLEAN)) { + set_exception_handler(static function (Throwable $t) { + fwrite(STDERR, "[ERROR] {$t->getMessage()}". PHP_EOL); + + exit(1); + }); +} $config = Config::fromServer(); From d842d4b43defc21a5e0df54fc3162eaad3f64979 Mon Sep 17 00:00:00 2001 From: Anton Vasiliev Date: Sun, 21 Nov 2021 20:34:32 +0000 Subject: [PATCH 10/13] #2321 - Move out `autoload.php` from `Library/` into `config/` directory --- {Library => config}/autoload.php | 4 +++- phpunit.xml.dist | 2 +- tests/ext-bootstrap.php | 2 +- zephir | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) rename {Library => config}/autoload.php (93%) diff --git a/Library/autoload.php b/config/autoload.php similarity index 93% rename from Library/autoload.php rename to config/autoload.php index 3308474f5..bc4913575 100644 --- a/Library/autoload.php +++ b/config/autoload.php @@ -9,6 +9,8 @@ * the LICENSE file that was distributed with this source code. */ +declare(strict_types=1); + namespace Zephir; use const PHP_BINARY; @@ -51,7 +53,7 @@ } } -if (false == class_exists('Composer\Autoload\ClassLoader', false)) { +if (!class_exists('Composer\Autoload\ClassLoader', false)) { fwrite(STDERR, 'Unable to find the Composer autoloader.'.PHP_EOL); exit(1); diff --git a/phpunit.xml.dist b/phpunit.xml.dist index fcdc56b0d..83bb61a98 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,7 +1,7 @@ diff --git a/tests/ext-bootstrap.php b/tests/ext-bootstrap.php index 9726282c9..f84e0aff3 100644 --- a/tests/ext-bootstrap.php +++ b/tests/ext-bootstrap.php @@ -9,7 +9,7 @@ * the LICENSE file that was distributed with this source code. */ -require_once __DIR__.'/../Library/autoload.php'; +require_once __DIR__.'/../config/autoload.php'; if (!extension_loaded('phalcon')) { include_once __DIR__.'/../prototypes/phalcon.php'; diff --git a/zephir b/zephir index 8ddcc9188..4124c7105 100755 --- a/zephir +++ b/zephir @@ -33,7 +33,7 @@ use Zephir\Parser\Parser; $rootPath = realpath(dirname(__FILE__)); -require $rootPath.'/Library/autoload.php'; +require $rootPath.'/config/autoload.php'; set_error_handler(static function ($code, $message, $file = '', $line = -1) { if (error_reporting() & $code) { From 9e9231adade911e3b3f212419030f8fe1329471a Mon Sep 17 00:00:00 2001 From: Anton Vasiliev Date: Sun, 21 Nov 2021 20:36:19 +0000 Subject: [PATCH 11/13] #2321 - Unify same logic in CompileFile* classes --- Library/AbstractCompilerFile.php | 63 ++++++++++++++ Library/Compiler.php | 2 + Library/CompilerFile.php | 136 +++++++++++------------------- Library/CompilerFileAnonymous.php | 46 ++-------- 4 files changed, 124 insertions(+), 123 deletions(-) create mode 100644 Library/AbstractCompilerFile.php diff --git a/Library/AbstractCompilerFile.php b/Library/AbstractCompilerFile.php new file mode 100644 index 000000000..e99245b10 --- /dev/null +++ b/Library/AbstractCompilerFile.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Zephir; + +abstract class AbstractCompilerFile +{ + /** + * @var string|null + */ + protected ?string $compiledFile = null; + + /** + * @var bool + */ + protected bool $external = false; + + /** + * Returns the path to the compiled file. + * + * @return string|null + */ + public function getCompiledFile(): ?string + { + return $this->compiledFile; + } + + /** + * @return bool + */ + public function isExternal(): bool + { + return $this->external; + } + + /** + * Sets if the class belongs to an external dependency or not. + * + * @param mixed $external + */ + public function setIsExternal($external): void + { + $this->external = (bool) $external; + } + + /** + * Compiles the file. + * + * @param Compiler $compiler + * @param StringsManager $stringsManager + */ + abstract public function compile(Compiler $compiler, StringsManager $stringsManager): void; +} diff --git a/Library/Compiler.php b/Library/Compiler.php index 74c744398..7d10d5f04 100644 --- a/Library/Compiler.php +++ b/Library/Compiler.php @@ -745,6 +745,7 @@ public function generate(bool $fromGenerate = false): bool $files = []; $hash = ''; + /** @var AbstractCompilerFile $compileFile */ foreach ($this->files as $compileFile) { /** * Only compile classes in the local extension, ignore external classes @@ -771,6 +772,7 @@ public function generate(bool $fromGenerate = false): bool /** * Round 3.2. Compile anonymous classes */ + /** @var AbstractCompilerFile $compileFile */ foreach ($this->anonymousFiles as $compileFile) { $compileFile->compile($this, $this->stringManager); $compiledFile = $compileFile->getCompiledFile(); diff --git a/Library/CompilerFile.php b/Library/CompilerFile.php index 9364c2d0f..873f0b5b3 100644 --- a/Library/CompilerFile.php +++ b/Library/CompilerFile.php @@ -9,6 +9,8 @@ * the LICENSE file that was distributed with this source code. */ +declare(strict_types=1); + namespace Zephir; use Psr\Log\LoggerAwareTrait; @@ -21,15 +23,15 @@ use Zephir\Exception\ParseException; use Zephir\FileSystem\FileSystemInterface; +use function count; +use function dirname; use function is_array; /** - * Zephir\CompilerFile. - * * This class represents every file compiled in a project. * Every file may contain a class or an interface. */ -final class CompilerFile implements FileInterface +final class CompilerFile extends AbstractCompilerFile implements FileInterface { use LoggerAwareTrait; @@ -48,11 +50,6 @@ final class CompilerFile implements FileInterface */ private ?string $filePath = null; - /** - * @var bool - */ - private bool $external = false; - /** * Original internal representation (IR) of the file. * @@ -65,11 +62,6 @@ final class CompilerFile implements FileInterface */ private $originalNode; - /** - * @var string|null - */ - private ?string $compiledFile = null; - /** * @var ClassDefinition|null */ @@ -135,40 +127,20 @@ public function setClassName(string $className) } /** - * {@inheritdoc} - * - * @return ClassDefinition + * @return ClassDefinition|null */ - public function getClassDefinition() + public function getClassDefinition(): ?ClassDefinition { $this->classDefinition->setAliasManager($this->aliasManager); return $this->classDefinition; } - public function getFunctionDefinitions() + public function getFunctionDefinitions(): array { return $this->functionDefinitions; } - /** - * Sets if the class belongs to an external dependency or not. - * - * @param bool $external - */ - public function setIsExternal($external): void - { - $this->external = (bool) $external; - } - - /** - * @return bool - */ - public function isExternal(): bool - { - return $this->external; - } - /** * Adds a function to the function definitions. * @@ -244,6 +216,7 @@ public function compileClass(CompilationContext $compilationContext): void * * @param CompilationContext $compilationContext * @param FunctionDefinition $functionDefinition + * @throws Exception */ public function compileFunction(CompilationContext $compilationContext, FunctionDefinition $functionDefinition) { @@ -269,7 +242,7 @@ public function compileFunction(CompilationContext $compilationContext, Function * @param CompilationContext $compilationContext * @param array $topStatement */ - public function compileComment(CompilationContext $compilationContext, $topStatement) + public function compileComment(CompilationContext $compilationContext, array $topStatement): void { $compilationContext->codePrinter->output('/'.$topStatement['value'].'/'); } @@ -278,10 +251,10 @@ public function compileComment(CompilationContext $compilationContext, $topState * Creates a definition for an interface. * * @param string $namespace - * @param array $topStatement - * @param array $docblock + * @param array $topStatement + * @param array|null $docblock */ - public function preCompileInterface($namespace, $topStatement, $docblock) + public function preCompileInterface(string $namespace, array $topStatement, ?array $docblock = null) { $classDefinition = new ClassDefinition($namespace, $topStatement['name']); $classDefinition->setIsExternal($this->external); @@ -343,11 +316,11 @@ public function preCompileInterface($namespace, $topStatement, $docblock) * Creates a definition for a class. * * @param CompilationContext $compilationContext - * @param string $namespace - * @param array $topStatement - * @param array $docblock + * @param string $namespace + * @param array $topStatement + * @param array|null $docblock */ - public function preCompileClass(CompilationContext $compilationContext, $namespace, $topStatement, $docblock) + public function preCompileClass(CompilationContext $compilationContext, string $namespace, array $topStatement, ?array $docblock = null) { $classDefinition = new ClassDefinition($namespace, $topStatement['name']); $classDefinition->setIsExternal($this->external); @@ -364,11 +337,11 @@ public function preCompileClass(CompilationContext $compilationContext, $namespa } if (isset($topStatement['abstract'])) { - $classDefinition->setIsAbstract($topStatement['abstract']); + $classDefinition->setIsAbstract((bool)$topStatement['abstract']); } if (isset($topStatement['final'])) { - $classDefinition->setIsFinal($topStatement['final']); + $classDefinition->setIsFinal((bool)$topStatement['final']); } if (is_array($docblock)) { @@ -637,16 +610,6 @@ public function preCompile(Compiler $compiler) $this->ir = $ir; } - /** - * Returns the path to the compiled file. - * - * @return string - */ - public function getCompiledFile(): string - { - return $this->compiledFile; - } - /** * Check dependencies. * @@ -712,24 +675,28 @@ public function checkDependencies(Compiler $compiler) foreach ($classDefinition->getImplementedInterfaces() as $interface) { if ($compiler->isInterface($interface)) { $interfaceDefinitions[$interface] = $compiler->getClassDefinition($interface); - } else { - if ($compiler->isBundledInterface($interface)) { - $interfaceDefinitions[$interface] = $compiler->getInternalClassDefinition($interface); - } else { - if ($extendedClass !== null) { - $classDefinition->setExtendsClassDefinition(new ClassDefinitionRuntime($extendedClass)); - } - $this->logger->warning( - sprintf( - 'Cannot locate class "%s" when extending interface "%s"', - $interface, - $classDefinition->getCompleteName() - ), - ['nonexistent-class', $this->originalNode] - ); - } + continue; + } + + if ($compiler->isBundledInterface($interface)) { + $interfaceDefinitions[$interface] = $compiler->getInternalClassDefinition($interface); + + continue; + } + + if ($extendedClass !== null) { + $classDefinition->setExtendsClassDefinition(new ClassDefinitionRuntime($extendedClass)); } + + $this->logger->warning( + sprintf( + 'Cannot locate class "%s" when extending interface "%s"', + $interface, + $classDefinition->getCompleteName() + ), + ['nonexistent-class', $this->originalNode] + ); } if (count($interfaceDefinitions) > 0) { @@ -740,12 +707,13 @@ public function checkDependencies(Compiler $compiler) /** * Compiles the file. * - * @param Compiler $compiler + * @param Compiler $compiler * @param StringsManager $stringsManager * - * @throws CompilerException + * @throws Exception + * @throws ReflectionException */ - public function compile(Compiler $compiler, StringsManager $stringsManager) + public function compile(Compiler $compiler, StringsManager $stringsManager): void { if (!$this->ir) { throw new CompilerException('Unable to locate the intermediate representation of the compiled file'); @@ -843,22 +811,20 @@ public function compile(Compiler $compiler, StringsManager $stringsManager) $classDefinition->setOriginalNode($this->originalNode); - $completeName = $classDefinition->getCompleteName(); - - $path = str_replace('\\', \DIRECTORY_SEPARATOR, strtolower($completeName)); + $path = str_replace('\\', \DIRECTORY_SEPARATOR, strtolower($classDefinition->getCompleteName())); $filePath = 'ext/'.$path.'.zep.c'; $filePathHeader = 'ext/'.$path.'.zep.h'; if (strpos($path, \DIRECTORY_SEPARATOR)) { - $dirname = \dirname($filePath); + $dirname = dirname($filePath); if (!is_dir($dirname)) { mkdir($dirname, 0755, true); } } /** - * If the file does not exists we create it for the first time + * If the file does not exist we create it for the first time */ if (!file_exists($filePath)) { file_put_contents($filePath, $codePrinter->getOutput()); @@ -896,7 +862,7 @@ public function applyClassHeaders(CompilationContext $compilationContext) { $classDefinition = $this->classDefinition; - $separators = str_repeat('../', \count(explode('\\', $classDefinition->getCompleteName())) - 1); + $separators = str_repeat('../', count(explode('\\', $classDefinition->getCompleteName())) - 1); $code = ''.PHP_EOL; $code .= '#ifdef HAVE_CONFIG_H'.PHP_EOL; @@ -926,11 +892,11 @@ public function applyClassHeaders(CompilationContext $compilationContext) } } - if (\count($this->headerCBlocks) > 0) { + if (count($this->headerCBlocks) > 0) { $code .= implode(PHP_EOL, $this->headerCBlocks).PHP_EOL; } - /* + /** * Prepend the required files to the header */ $compilationContext->codePrinter->preOutput($code); @@ -954,7 +920,7 @@ public function getFilePath(): string * * @throws CompilerException */ - protected function processShortcuts(array $property, ClassDefinition $classDefinition) + protected function processShortcuts(array $property, ClassDefinition $classDefinition): void { foreach ($property['shortcuts'] as $shortcut) { if ('_' == substr($property['name'], 0, 1)) { @@ -1026,7 +992,7 @@ protected function processShortcuts(array $property, ClassDefinition $classDefin 'type' => 'parameter', 'name' => $name, 'const' => 0, - 'data-type' => 1 == \count($returnsType) ? $returnsType[0] : 'variable', + 'data-type' => 1 == count($returnsType) ? $returnsType[0] : 'variable', 'mandatory' => 0, ], ]), diff --git a/Library/CompilerFileAnonymous.php b/Library/CompilerFileAnonymous.php index b4b54557e..7d904cdb7 100644 --- a/Library/CompilerFileAnonymous.php +++ b/Library/CompilerFileAnonymous.php @@ -24,12 +24,11 @@ * This class represents an anonymous file created to dump * the code produced by an internal closure */ -final class CompilerFileAnonymous implements FileInterface +final class CompilerFileAnonymous extends AbstractCompilerFile implements FileInterface { use LoggerAwareTrait; protected ?string $namespace = null; - protected ?string $compiledFile = null; protected bool $external = false; protected array $headerCBlocks = []; protected ?CompilationContext $context = null; @@ -37,8 +36,6 @@ final class CompilerFileAnonymous implements FileInterface protected Config $config; /** - * CompilerFileAnonymous constructor. - * * @param ClassDefinition $classDefinition * @param Config $config * @param CompilationContext|null $context @@ -59,24 +56,6 @@ public function getClassDefinition(): ClassDefinition return $this->classDefinition; } - /** - * Sets if the class belongs to an external dependency or not. - * - * @param bool $external - */ - public function setIsExternal($external) - { - $this->external = (bool) $external; - } - - /** - * @return bool - */ - public function isExternal(): bool - { - return $this->external; - } - /** * Compiles the class/interface contained in the file. * @@ -96,21 +75,21 @@ private function compileClass(CompilationContext $compilationContext) $separators = str_repeat('../', count(explode('\\', $classDefinition->getCompleteName())) - 1); - $code = ''.PHP_EOL; + $code = PHP_EOL; $code .= '#ifdef HAVE_CONFIG_H'.PHP_EOL; $code .= '#include "'.$separators.'ext_config.h"'.PHP_EOL; $code .= '#endif'.PHP_EOL; - $code .= ''.PHP_EOL; + $code .= PHP_EOL; $code .= '#include '.PHP_EOL; $code .= '#include "'.$separators.'php_ext.h"'.PHP_EOL; $code .= '#include "'.$separators.'ext.h"'.PHP_EOL; - $code .= ''.PHP_EOL; + $code .= PHP_EOL; $code .= '#include '.PHP_EOL; $code .= '#include '.PHP_EOL; $code .= '#include '.PHP_EOL; - $code .= ''.PHP_EOL; + $code .= PHP_EOL; $code .= '#include "kernel/main.h"'.PHP_EOL; @@ -133,12 +112,13 @@ private function compileClass(CompilationContext $compilationContext) /** * Compiles the file. * - * @param Compiler $compiler + * @param Compiler $compiler * @param StringsManager $stringsManager * * @throws Exception + * @throws ReflectionException */ - public function compile(Compiler $compiler, StringsManager $stringsManager) + public function compile(Compiler $compiler, StringsManager $stringsManager): void { /** * Compilation context stores common objects required by compilation entities. @@ -221,16 +201,6 @@ public function compile(Compiler $compiler, StringsManager $stringsManager) $this->compiledFile = $path.'.c'; } - /** - * Returns the path to the compiled file. - * - * @return string - */ - public function getCompiledFile() - { - return $this->compiledFile; - } - /** * {@inheritdoc} * From d5cf3423f3f2a1200b16d55b993b75c9aff58b07 Mon Sep 17 00:00:00 2001 From: Anton Vasiliev Date: Sun, 21 Nov 2021 20:39:11 +0000 Subject: [PATCH 12/13] #2321 - Remove redundant character escapes --- Library/Compiler.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Library/Compiler.php b/Library/Compiler.php index 7d10d5f04..7c668cb66 100644 --- a/Library/Compiler.php +++ b/Library/Compiler.php @@ -1316,13 +1316,13 @@ public function processExtensionGlobals(string $namespace): array * Process compound structures */ foreach ($structures as $structureName => $internalStructure) { - if (preg_match('/^[0-9a-zA-Z\_]$/', $structureName)) { + if (preg_match('/^[0-9a-zA-Z_]$/', $structureName)) { throw new Exception("Struct name: '".$structureName."' contains invalid characters"); } $structBuilder = new Struct('_zephir_struct_'.$structureName, $structureName); foreach ($internalStructure as $field => $global) { - if (preg_match('/^[0-9a-zA-Z\_]$/', $field)) { + if (preg_match('/^[0-9a-zA-Z_]$/', $field)) { throw new Exception("Struct field name: '".$field."' contains invalid characters"); } @@ -1345,7 +1345,7 @@ public function processExtensionGlobals(string $namespace): array * Process single variables */ foreach ($variables as $name => $global) { - if (preg_match('/^[0-9a-zA-Z\_]$/', $name)) { + if (preg_match('/^[0-9a-zA-Z_]$/', $name)) { throw new Exception("Extension global variable name: '".$name."' contains invalid characters"); } @@ -2167,11 +2167,12 @@ private function loadConstantsSources(array $constantsSources) } foreach (file($constantsSource) as $line) { - if (preg_match('/^\#define[ \t]+([A-Z0-9\_]+)[ \t]+([0-9]+)/', $line, $matches)) { + if (preg_match('/^#define[ \t]+([A-Z0-9_]+)[ \t]+([0-9]+)/', $line, $matches)) { $this->constants[$matches[1]] = ['int', $matches[2]]; continue; } - if (preg_match('/^\#define[ \t]+([A-Z0-9\_]+)[ \t]+(\'(.){1}\')/', $line, $matches)) { + + if (preg_match('/^#define[ \t]+([A-Z0-9_]+)[ \t]+(\'(.)\')/', $line, $matches)) { $this->constants[$matches[1]] = ['char', $matches[3]]; } } From 63d1051ee49d05f4775eff9bfc5c16043b6cb7bd Mon Sep 17 00:00:00 2001 From: Anton Vasiliev Date: Mon, 29 Nov 2021 23:10:49 +0000 Subject: [PATCH 13/13] #2321 - Improve `populate_fcic()` function --- kernels/ZendEngine3/fcall.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/kernels/ZendEngine3/fcall.c b/kernels/ZendEngine3/fcall.c index e933ba38c..1df70c4e8 100755 --- a/kernels/ZendEngine3/fcall.c +++ b/kernels/ZendEngine3/fcall.c @@ -297,29 +297,26 @@ static void populate_fcic(zend_fcall_info_cache* fcic, zephir_call_type type, ze case zephir_fcall_function: case zephir_fcall_method: if (Z_TYPE_P(func) == IS_OBJECT) { + if (Z_TYPE_P(this_ptr) == IS_OBJECT) { + fcic->calling_scope = Z_OBJCE_P(this_ptr); + } + #if PHP_VERSION_ID >= 80000 - if (Z_OBJ_HANDLER_P(func, get_closure)(Z_OBJ_P(func), &fcic->calling_scope, &fcic->function_handler, &fcic->object, 0) == SUCCESS) { + if (Z_OBJ_HANDLER_P(func, get_closure)(Z_OBJ_P(func), &fcic->calling_scope, &fcic->function_handler, &fcic->object, 1) == SUCCESS) { #else if (Z_OBJ_HANDLER_P(func, get_closure)(func, &fcic->calling_scope, &fcic->function_handler, &fcic->object) == SUCCESS) { #endif fcic->called_scope = fcic->calling_scope; break; } - - if (Z_TYPE_P(this_ptr) == IS_OBJECT) { - fcic->calling_scope = Z_OBJCE_P(this_ptr); - } - - return; } else if (Z_TYPE_P(func) == IS_STRING) { if (ce) { fcic->calling_scope = ce; + #if PHP_VERSION_ID >= 80000 fcic->function_handler = zend_hash_find_ptr(&ce->function_table, Z_STR_P(func)); #endif } - - return; } break;