diff --git a/src/Php/Translator.php b/src/Php/Translator.php index 9d2bdd55..17fc3e29 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -628,6 +628,30 @@ CODE; } } } + + // Clean up inherited array constants from child classes + foreach ($this->classes as $className => $classDef) { + $ownConstNames = []; + foreach ($classDef->constants as $constant) { + if ($constant->type === self::TYPE_ARRAY) { + $ownConstNames[$constant->name] = true; + } + } + + $parentName = $this->escapeClass($classDef->extends); + while ($parentName && isset($this->classes[$parentName])) { + $parentDef = $this->classes[$parentName]; + foreach ($parentDef->constants as $constant) { + if ($constant->type === self::TYPE_ARRAY && !isset($ownConstNames[$constant->name])) { + $ownConstNames[$constant->name] = true; + $classNameStr = $this->genCharPtr($classDef->getNamespacedName(false), true); + $classConstStr = $this->genCharPtr($constant->name); + $code .= "php::updateConstant($classNameStr, $classConstStr, php::null);\n"; + } + } + $parentName = $this->escapeClass($parentDef->extends); + } + } $code .= '}' . PHP_EOL . PHP_EOL; // php_app_clean end @@ -1376,6 +1400,32 @@ CODE; } } } + + // Propagate array constants to child classes that don't override them + foreach ($this->classes as $className => $classDef) { + $ownConstNames = []; + foreach ($classDef->constants as $constant) { + if ($constant->type === self::TYPE_ARRAY) { + $ownConstNames[$constant->name] = true; + } + } + + $parentName = $this->escapeClass($classDef->extends); + while ($parentName && isset($this->classes[$parentName])) { + $parentDef = $this->classes[$parentName]; + foreach ($parentDef->constants as $constant) { + if ($constant->type === self::TYPE_ARRAY && !isset($ownConstNames[$constant->name])) { + $ownConstNames[$constant->name] = true; + $constName = self::PREFIX . $this->getNativeName($constant->name, $parentDef->namespace, $parentDef->name); + $classNameStr = $this->genCharPtr($classDef->getNamespacedName(false), true); + $classConstStr = $this->genCharPtr($constant->name); + $code .= "php::updateConstant($classNameStr, $classConstStr, {$constName});\n"; + } + } + $parentName = $this->escapeClass($parentDef->extends); + } + } + return $code; } diff --git a/src/Php/UniversalMethodCall.php b/src/Php/UniversalMethodCall.php index c27dfa0d..89fc2d87 100644 --- a/src/Php/UniversalMethodCall.php +++ b/src/Php/UniversalMethodCall.php @@ -319,7 +319,7 @@ trait UniversalMethodCall ], ]; - private const array MUTATING_HANDLERS = ['direct_method_mutate', 'php_fn_ref']; + protected const array MUTATING_HANDLERS = ['direct_method_mutate', 'php_fn_ref']; protected function detectUniversalMethodReturnType(string $type, string $method): ?string { @@ -331,7 +331,7 @@ trait UniversalMethodCall return $ext ? $ext['return_type'] : null; } - private const array TYPE_EXTENSION_PREFIX = [ + protected const array TYPE_EXTENSION_PREFIX = [ CompilerBase::TYPE_INT => 'int', CompilerBase::TYPE_FLOAT => 'float', CompilerBase::TYPE_BOOL => 'bool', @@ -349,7 +349,7 @@ trait UniversalMethodCall return strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $name)); } - private const array TO_CONVERT_FN = [ + protected const array TO_CONVERT_FN = [ CompilerBase::TYPE_BIGINT => ['toInt' => 'php::BigInt::toInt', 'toFloat' => 'php::BigInt::toFloat', 'toString' => 'php::BigInt::toString'], CompilerBase::TYPE_BIGFLOAT => ['toInt' => 'php::BigFloat::toInt', 'toFloat' => 'php::BigFloat::toFloat', 'toString' => 'php::BigFloat::toString'], CompilerBase::TYPE_DECIMAL => ['toInt' => 'php::Decimal::toInt', 'toFloat' => 'php::Decimal::toFloat', 'toString' => 'php::Decimal::toString'], @@ -485,7 +485,7 @@ trait UniversalMethodCall return $kwExt ? $kwExt['return_type'] : null; } - private function buildInternalExtensionMethod(string $type, string $funcName): ?array + protected function buildInternalExtensionMethod(string $type, string $funcName): ?array { $ref = Reflection::getFunction($funcName); if ($ref === null) { @@ -525,7 +525,7 @@ trait UniversalMethodCall ]; } - private function validateExtensionFirstParam(string $type, \PhpAot\Php\Entity\FunctionDef $funcDef): bool + protected function validateExtensionFirstParam(string $type, \PhpAot\Php\Entity\FunctionDef $funcDef): bool { if (empty($funcDef->argInfoList)) { return false; @@ -545,7 +545,7 @@ trait UniversalMethodCall return $paramType === $type; } - private function validateInternalExtensionFirstParam(string $type, string $funcName): bool + protected function validateInternalExtensionFirstParam(string $type, string $funcName): bool { $param = Reflection::getFunctionParameter($funcName, 0); if ($param === null) { @@ -628,7 +628,7 @@ trait UniversalMethodCall * Wrap a non-variable receiver expression in the appropriate type conversion * so that direct C++ method calls (e.g. .get(), .set()) work on the correct type. */ - private function wrapUniversalReceiver(string $type, string $expr): string + protected function wrapUniversalReceiver(string $type, string $expr): string { $convFns = [ self::TYPE_ARRAY => 'toArray', @@ -643,7 +643,7 @@ trait UniversalMethodCall return $expr; } - private function validateUniversalMethodArgs(Node\Expr\MethodCall $expr, string $method, array $def, bool $isVar): void + protected function validateUniversalMethodArgs(Node\Expr\MethodCall $expr, string $method, array $def, bool $isVar): void { $argCount = count($expr->args); $maxArgs = $def['max_args']; @@ -727,7 +727,7 @@ trait UniversalMethodCall return $cppFunc . '(' . implode(', ', $argExprs) . ')'; } - private function buildReceiverArgs(string $receiver, array $args, int $receiverPos): array + protected function buildReceiverArgs(string $receiver, array $args, int $receiverPos): array { $userArgs = []; foreach ($args as $arg) { diff --git a/tests/aot/trait/012.phpt b/tests/aot/trait/012.phpt index ed47835c..0eb56ebd 100644 --- a/tests/aot/trait/012.phpt +++ b/tests/aot/trait/012.phpt @@ -3,7 +3,7 @@ Single Trait with simple trait method --FILE-- ['toInt' => 123,], 'test_fn_2' => ['toInt' => 234, ], 'test_fn_3' => ['toInt' => 333,], diff --git a/tests/aot/trait/013.phpt b/tests/aot/trait/013.phpt new file mode 100644 index 00000000..a34f04a4 --- /dev/null +++ b/tests/aot/trait/013.phpt @@ -0,0 +1,41 @@ +--TEST-- +Single Trait with simple trait method +--FILE-- +foo(); +} +?> +--EXPECT-- +array(1) { + [0]=> + string(3) "foo" +} +array(1) { + [0]=> + string(3) "foo" +} +array(1) { + [0]=> + string(3) "foo" +} \ No newline at end of file