From 525a4e4412496315fbcd17185d56f6be059ee5d4 Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Sat, 8 Aug 2026 20:39:08 +0800 Subject: [PATCH] fix: register TypePHP functions with strict types --- src/Translator.php | 27 +++---------- src/gen_stub.php | 4 +- .../declare/strict_types-default.phpt | 38 +++++++++++++++++++ tests/compiler/declare/strict_types.phpt | 18 ++++----- 4 files changed, 55 insertions(+), 32 deletions(-) create mode 100644 tests/compiler/declare/strict_types-default.phpt diff --git a/src/Translator.php b/src/Translator.php index ffc160d9..177cd755 100644 --- a/src/Translator.php +++ b/src/Translator.php @@ -898,11 +898,11 @@ CODE; } $fullName = $functionDef->getNamespacedName(); $zifName = $this->escapeZendFnName($fullName); - if ($functionDef->namespace) { - $code .= $this->getIndent() . 'ZEND_NAMED_FE("' . $this->escapeString($fullName) . '", ZEND_FN(' . $zifName . '), arginfo_' . $zifName . ')' . PHP_EOL; - } else { - $code .= $this->getIndent() . 'ZEND_FE(' . $zifName . ', arginfo_' . $zifName . ')' . PHP_EOL; - } + // TypePHP is always strict. Store the flag in the registered + // zend_function instead of rewriting shared metadata on every call. + $code .= $this->getIndent() . 'ZEND_RAW_FENTRY("' . $this->escapeString($fullName) + . '", ZEND_FN(' . $zifName . '), arginfo_' . $zifName + . ', ZEND_ACC_STRICT_TYPES, NULL, NULL)' . PHP_EOL; } $code .= $this->getIndent() . "ZEND_FE_END\n};\n// clang-format on" . PHP_EOL . PHP_EOL; @@ -2569,8 +2569,6 @@ CODE; } elseif ($key === 'strict_types') { if (!($declare->value instanceof Node\Scalar\Int_) or $declare->value->value !== 1) { $this->fatalError($v, 'declare(strict_types=0) is not allowed, only strict_types=1 is supported'); - } else { - $this->setStrictTypes(1); } } else { $this->fatalError($v, 'declare(' . $key . '=' . $value . ') is not supported'); @@ -3249,17 +3247,6 @@ CODE; $cppCode .= $this->genWrapperRequiredArgCountCheck($functionDef, $displayName); } - /** - * Tthe current function must be marked with the `ZEND_ACC_STRICT_TYPES` flag. - * This flag is used to ensure that when the function calls other functions through the ZendVM, - * it strictly validates argument types according to the declared mode. - * - * It is important to note that this mechanism only applies to functions dynamically invoked by the ZendVM. - * If the target function is compiled native code, type checking will not be triggered—this is by design in the ZendVM, - * whose philosophy is to trust the C code implementation of compiled internal functions. - */ - $cppCode .= $this->genStrictTypesCode(); - foreach ($functionDef->argInfoList as $k => $argInfo) { $var = 'arg_' . $argInfo->name; if ($argInfo->variadic) { @@ -4996,8 +4983,4 @@ CODE; return $code; } - private function genStrictTypesCode(): string - { - return "execute_data->func->common.fn_flags |= ZEND_ACC_STRICT_TYPES;" . PHP_EOL; - } } diff --git a/src/gen_stub.php b/src/gen_stub.php index 779d39c8..51d9a8b2 100755 --- a/src/gen_stub.php +++ b/src/gen_stub.php @@ -1688,7 +1688,9 @@ class FuncInfo { private function getArginfoFlagsByPhpVersions(): VersionFlags { - $flags = []; + // TypePHP is always strict. Register functions and methods with the + // flag once so dynamic calls made by native bodies inherit that mode. + $flags = ["ZEND_ACC_STRICT_TYPES"]; if ($this->isMethod()) { if ($this->flags & Modifiers::PROTECTED) { diff --git a/tests/compiler/declare/strict_types-default.phpt b/tests/compiler/declare/strict_types-default.phpt new file mode 100644 index 00000000..a14b9410 --- /dev/null +++ b/tests/compiler/declare/strict_types-default.phpt @@ -0,0 +1,38 @@ +--TEST-- +TypePHP enables strict types without a declare directive +--FILE-- + +--EXPECT-- +main=TypeError +function=TypeError +method=TypeError diff --git a/tests/compiler/declare/strict_types.phpt b/tests/compiler/declare/strict_types.phpt index b2cfc285..120d14cc 100644 --- a/tests/compiler/declare/strict_types.phpt +++ b/tests/compiler/declare/strict_types.phpt @@ -4,14 +4,14 @@ declare: strict types 1 ---EXPECTF-- -Fatal error: Uncaught TypeError: parse_url(): Argument #1 ($url) must be of type string, int given in %s:%d -Stack trace: -#0 %s -#1 %s -#2 {main} - thrown in %s on line %d - +--EXPECT-- +TypeError