From 3e07456291b053d7e13a4388fd01e3ee196fac9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Wed, 7 Oct 2020 12:33:58 +0200 Subject: [PATCH 1/9] Add support for declaring class entries in stubs --- Zend/zend_exceptions.c | 35 +- Zend/zend_exceptions.stub.php | 51 +- Zend/zend_exceptions_arginfo.h | 167 +++++- Zend/zend_generators.c | 11 +- Zend/zend_generators.stub.php | 10 +- Zend/zend_generators_arginfo.h | 30 +- build/gen_stub.php | 549 +++++++++++++++++- ext/curl/curl_file.stub.php | 12 +- ext/curl/curl_file_arginfo.h | 19 +- ext/dom/php_dom.stub.php | 2 + ext/dom/php_dom_arginfo.h | 2 +- ext/intl/common/common.stub.php | 5 +- ext/intl/common/common_arginfo.h | 14 +- ext/intl/common/common_enum.cpp | 9 +- .../resourcebundle/resourcebundle.stub.php | 5 +- .../resourcebundle/resourcebundle_arginfo.h | 14 +- .../resourcebundle/resourcebundle_class.c | 13 +- .../transliterator/transliterator.stub.php | 8 +- .../transliterator/transliterator_arginfo.h | 15 +- .../transliterator/transliterator_class.c | 21 +- ext/libxml/libxml.c | 32 +- ext/libxml/libxml.stub.php | 19 +- ext/libxml/libxml_arginfo.h | 46 +- ext/pdo/pdo.c | 2 +- ext/pdo/pdo.stub.php | 6 + ext/pdo/pdo_arginfo.h | 7 +- ext/pdo/pdo_stmt.c | 11 +- ext/pdo/pdo_stmt.stub.php | 8 +- ext/pdo/pdo_stmt_arginfo.h | 27 +- ext/simplexml/simplexml.c | 10 +- ext/simplexml/simplexml.stub.php | 5 +- ext/simplexml/simplexml_arginfo.h | 24 +- ext/spl/spl_iterators.stub.php | 3 + ext/spl/spl_iterators_arginfo.h | 2 +- ext/standard/user_filters.stub.php | 5 + ext/standard/user_filters_arginfo.h | 2 +- ext/tokenizer/tokenizer.c | 30 +- ext/tokenizer/tokenizer.stub.php | 10 +- ext/tokenizer/tokenizer_arginfo.h | 38 +- ext/xml/xml.c | 5 +- ext/xml/xml.stub.php | 6 +- ext/xml/xml_arginfo.h | 14 +- ext/zend_test/test.c | 58 +- ext/zend_test/test.stub.php | 31 +- ext/zend_test/test_arginfo.h | 114 +++- ext/zip/php_zip.stub.php | 3 + ext/zip/php_zip_arginfo.h | 2 +- 47 files changed, 1264 insertions(+), 248 deletions(-) diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index e93526689d15a..15f4ad42c4856 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -765,8 +765,8 @@ void zend_register_default_exception(void) /* {{{ */ { zend_class_entry ce; - REGISTER_MAGIC_INTERFACE(throwable, Throwable); - zend_class_implements(zend_ce_throwable, 1, zend_ce_stringable); + zend_ce_throwable = register_class_Throwable(zend_ce_stringable); + zend_ce_throwable->interface_gets_implemented = zend_implement_throwable; memcpy(&default_exception_handlers, &std_object_handlers, sizeof(zend_object_handlers)); default_exception_handlers.clone_obj = NULL; @@ -777,8 +777,7 @@ void zend_register_default_exception(void) /* {{{ */ zend_class_implements(zend_ce_exception, 1, zend_ce_throwable); declare_exception_properties(zend_ce_exception); - INIT_CLASS_ENTRY(ce, "ErrorException", class_ErrorException_methods); - zend_ce_error_exception = zend_register_internal_class_ex(&ce, zend_ce_exception); + zend_ce_error_exception = register_class_ErrorException(zend_ce_exception); zend_ce_error_exception->create_object = zend_error_exception_new; zend_declare_property_long(zend_ce_error_exception, "severity", sizeof("severity")-1, E_ERROR, ZEND_ACC_PROTECTED); @@ -788,39 +787,31 @@ void zend_register_default_exception(void) /* {{{ */ zend_class_implements(zend_ce_error, 1, zend_ce_throwable); declare_exception_properties(zend_ce_error); - INIT_CLASS_ENTRY(ce, "CompileError", class_CompileError_methods); - zend_ce_compile_error = zend_register_internal_class_ex(&ce, zend_ce_error); + zend_ce_compile_error = register_class_CompileError(zend_ce_error); zend_ce_compile_error->create_object = zend_default_exception_new; - INIT_CLASS_ENTRY(ce, "ParseError", class_ParseError_methods); - zend_ce_parse_error = zend_register_internal_class_ex(&ce, zend_ce_compile_error); + zend_ce_parse_error = register_class_ParseError(zend_ce_compile_error); zend_ce_parse_error->create_object = zend_default_exception_new; - INIT_CLASS_ENTRY(ce, "TypeError", class_TypeError_methods); - zend_ce_type_error = zend_register_internal_class_ex(&ce, zend_ce_error); + zend_ce_type_error = register_class_TypeError(zend_ce_error); zend_ce_type_error->create_object = zend_default_exception_new; - INIT_CLASS_ENTRY(ce, "ArgumentCountError", class_ArgumentCountError_methods); - zend_ce_argument_count_error = zend_register_internal_class_ex(&ce, zend_ce_type_error); + zend_ce_argument_count_error = register_class_ArgumentCountError(zend_ce_type_error); zend_ce_argument_count_error->create_object = zend_default_exception_new; - INIT_CLASS_ENTRY(ce, "ValueError", class_ValueError_methods); - zend_ce_value_error = zend_register_internal_class_ex(&ce, zend_ce_error); + zend_ce_value_error = register_class_ValueError(zend_ce_error); zend_ce_value_error->create_object = zend_default_exception_new; - INIT_CLASS_ENTRY(ce, "ArithmeticError", class_ArithmeticError_methods); - zend_ce_arithmetic_error = zend_register_internal_class_ex(&ce, zend_ce_error); + zend_ce_arithmetic_error = register_class_ArithmeticError(zend_ce_error); zend_ce_arithmetic_error->create_object = zend_default_exception_new; - INIT_CLASS_ENTRY(ce, "DivisionByZeroError", class_DivisionByZeroError_methods); - zend_ce_division_by_zero_error = zend_register_internal_class_ex(&ce, zend_ce_arithmetic_error); + zend_ce_division_by_zero_error = register_class_DivisionByZeroError(zend_ce_arithmetic_error); zend_ce_division_by_zero_error->create_object = zend_default_exception_new; - INIT_CLASS_ENTRY(zend_ce_unwind_exit, "UnwindExit", NULL); - - INIT_CLASS_ENTRY(ce, "UnhandledMatchError", NULL); - zend_ce_unhandled_match_error = zend_register_internal_class_ex(&ce, zend_ce_error); + zend_ce_unhandled_match_error = register_class_UnhandledMatchError(zend_ce_error); zend_ce_unhandled_match_error->create_object = zend_default_exception_new; + + INIT_CLASS_ENTRY(zend_ce_unwind_exit, "UnwindExit", NULL); } /* }}} */ diff --git a/Zend/zend_exceptions.stub.php b/Zend/zend_exceptions.stub.php index 11c1d500d3075..28cf456ab260f 100644 --- a/Zend/zend_exceptions.stub.php +++ b/Zend/zend_exceptions.stub.php @@ -1,6 +1,9 @@ ce_flags |= ZEND_ACC_FINAL | ZEND_ACC_NO_DYNAMIC_PROPERTIES; + zend_ce_generator = register_class_Generator(zend_ce_iterator); zend_ce_generator->create_object = zend_generator_create; zend_ce_generator->serialize = zend_class_serialize_deny; zend_ce_generator->unserialize = zend_class_unserialize_deny; - /* get_iterator has to be assigned *after* implementing the interface */ - zend_class_implements(zend_ce_generator, 1, zend_ce_iterator); zend_ce_generator->get_iterator = zend_generator_get_iterator; memcpy(&zend_generator_handlers, &std_object_handlers, sizeof(zend_object_handlers)); @@ -1132,7 +1126,6 @@ void zend_register_generator_ce(void) /* {{{ */ zend_generator_handlers.clone_obj = NULL; zend_generator_handlers.get_constructor = zend_generator_get_constructor; - INIT_CLASS_ENTRY(ce, "ClosedGeneratorException", NULL); - zend_ce_ClosedGeneratorException = zend_register_internal_class_ex(&ce, zend_ce_exception); + zend_ce_ClosedGeneratorException = register_class_ClosedGeneratorException(zend_ce_exception); } /* }}} */ diff --git a/Zend/zend_generators.stub.php b/Zend/zend_generators.stub.php index f2e47616bad1d..879fdb3642733 100644 --- a/Zend/zend_generators.stub.php +++ b/Zend/zend_generators.stub.php @@ -1,7 +1,11 @@ ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES; + zend_class_implements(class_entry, 1, class_entry_Iterator); + + return class_entry; +} + +zend_class_entry *register_class_ClosedGeneratorException(zend_class_entry *class_entry_Exception) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "ClosedGeneratorException", class_ClosedGeneratorException_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_Exception); + + return class_entry; +} + diff --git a/build/gen_stub.php b/build/gen_stub.php index 319446ef41183..9d8d68c94c3a6 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -2,11 +2,13 @@ forceRegeneration || $stubHash !== $oldStubHash) && file_put_contents($arginfoFile, $arginfoCode)) { echo "Saved $arginfoFile\n"; @@ -63,11 +66,15 @@ function processStubFile(string $stubFile, Context $context): ?FileInfo { foreach ($fileInfo->getAllFuncInfos() as $funcInfo) { $funcInfo->discardInfoForOldPhpVersions(); } + foreach ($fileInfo->getAllPropertyInfos() as $propertyInfo) { + $propertyInfo->discardInfoForOldPhpVersions(); + } + $arginfoCode = generateArgInfoCode($fileInfo, $stubHash); if (($context->forceRegeneration || $stubHash !== $oldStubHash) && file_put_contents($legacyFile, $arginfoCode)) { echo "Saved $legacyFile\n"; } - } + } return $fileInfo; } catch (Exception $e) { @@ -457,6 +464,24 @@ public function getDefaultValueAsMethodSynopsisString(): ?string { } } +class PropertyName { + /** @var string */ + public $class; + /** @var string */ + public $property; + + public function __construct(string $class, string $property) + { + $this->class = $class; + $this->property = $property; + } + + public function __toString() + { + return $this->class . "::$" . $this->property; + } +} + interface FunctionOrMethodName { public function getDeclaration(): string; public function getArgInfoName(): string; @@ -804,6 +829,14 @@ public function getFunctionEntry(): string { } } + public function discardInfoForOldPhpVersions(): void { + $this->return->type = null; + foreach ($this->args as $arg) { + $arg->type = null; + $arg->defaultValue = null; + } + } + private function getFlagsAsArginfoString(): string { $flags = "ZEND_ACC_PUBLIC"; @@ -831,6 +864,32 @@ private function getFlagsAsArginfoString(): string return $flags; } +} + +class PropertyInfo +{ + /** @var PropertyName */ + public $name; + /** @var int */ + public $flags; + /** @var bool */ + public $isKnownName; + /** @var bool */ + public $isDeprecated; + /** @var Type|null */ + public $type; + /** @var Expr|null */ + public $defaultValue; + + public function __construct(PropertyName $name, int $flags, bool $isKnownName, bool $isDeprecated, ?Type $type, ?Expr $defaultValue) + { + $this->name = $name; + $this->flags = $flags; + $this->isKnownName = $isKnownName; + $this->isDeprecated = $isDeprecated; + $this->type = $type; + $this->defaultValue = $defaultValue; + } /** * @param FuncInfo[] $funcMap @@ -941,11 +1000,181 @@ public function getMethodSynopsisElement(array $funcMap, array $aliasMap, DOMDoc } public function discardInfoForOldPhpVersions(): void { - $this->return->type = null; - foreach ($this->args as $arg) { - $arg->type = null; - $arg->defaultValue = null; + $this->type = null; + } + + public function getDeclaration(): string { + $code = "\n"; + + $propertyName = $this->name->property; + + $defaultValueConstant = false; + if ($this->defaultValue === null) { + $defaultValue = null; + $defaultValueType = "undefined"; + } else { + $evaluator = new ConstExprEvaluator( + function (Expr $expr) use (&$defaultValueConstant) { + if ($expr instanceof Expr\ConstFetch) { + $defaultValueConstant = true; + return null; + } + + throw new Exception("Property $this->name has an unsupported default value"); + } + ); + $defaultValue = $evaluator->evaluateDirectly($this->defaultValue); + $defaultValueType = gettype($defaultValue); + } + + if ($defaultValueConstant) { + echo "Skipping code generation for property $this->name, because it has a constant default value\n"; + return ""; + } + + if ($this->type) { + $typeFlags = $this->type->tryToRepresentableType(); + if ($typeFlags === null) { + echo "Skipping code generation for property $this->name, because it has an unimplemented type\n"; + return ""; + } + + if ($typeFlags->classType) { + $simpleType = $this->type->tryToSimpleType(); + if ($simpleType) { + $typeCode = "(zend_type) ZEND_TYPE_INIT_CE(class_entry_" . str_replace("\\", "_", $typeFlags->classType->name) . ", " . ((int) $this->type->isNullable()) . ", 0)"; + } else { + throw new Exception("Property $this->name has an unsupported union type"); + } + } else { + $typeCode = "(zend_type) ZEND_TYPE_INIT_MASK(" . $typeFlags->toTypeMask() . ")"; + } + + $code .= $this->initializeValue($defaultValueType, $defaultValue); + + if ($this->isKnownName) { + $nameCode = "ZSTR_KNOWN(ZEND_STR_" . strtoupper($propertyName) . ")"; + } else { + $code .= "\tzend_string *property_{$propertyName}_name = zend_string_init(\"$propertyName\", sizeof(\"$propertyName\") - 1, 1);\n"; + $nameCode = "property_{$propertyName}_name"; + } + + $code .= "\tzend_declare_typed_property(class_entry, $nameCode, &property_{$propertyName}_default_value, " . $this->getFlagsAsString() . ", NULL, $typeCode);\n"; + if (!$this->isKnownName) { + $code .= "\tzend_string_release(property_{$propertyName}_name);\n"; + } + } else { + if ($this->isKnownName) { + Throw new Exception("Non-typed property $this->name cannot be annotated as @known"); + } + + switch ($defaultValueType) { + case "undefined": // intentional fallthrough + case "NULL": + $code .= "\tzend_declare_property_null(class_entry, \"$propertyName\", sizeof(\"$propertyName\") - 1, " . $this->getFlagsAsString() . ");\n"; + break; + + case "boolean": + $code .= "\tzend_declare_property_bool(class_entry, \"$propertyName\", sizeof(\"$propertyName\") - 1, " . ((int) $defaultValue) . ", " . $this->getFlagsAsString() . ");\n"; + break; + + case "integer": + $code .= "\tzend_declare_property_long(class_entry, \"$propertyName\", sizeof(\"$propertyName\") - 1, " . $defaultValue . ", " . $this->getFlagsAsString() . ");\n"; + break; + + case "double": + $code .= "\tzend_declare_property_double(class_entry, \"$propertyName\", sizeof(\"$propertyName\") - 1, " . $defaultValue . ", " . $this->getFlagsAsString() . ");\n"; + break; + + case "string": + $code .= "\tzend_declare_property_string(class_entry, \"$propertyName\", sizeof(\"$propertyName\") - 1, \"" . $defaultValue . "\", " . $this->getFlagsAsString() . ");\n"; + break; + + case "array": + $code .= $this->initializeValue($defaultValueType, $defaultValue); + $code .= "\tzend_declare_property_ex(class_entry, \"$propertyName\", sizeof(\"$propertyName\") - 1, property_{$propertyName}_default_value, " . $this->getFlagsAsString() . ");\n"; + break; + + default: + throw new Exception("Property $this->name has an invalid default value"); + } + } + + return $code; + } + + /** + * @param mixed $value + */ + private function initializeValue(string $type, $value): string + { + $name = $this->name->property; + $zvalName = "property_{$name}_default_value"; + + $code = "\tzval $zvalName;\n"; + + switch ($type) { + case "undefined": + $code .= "\tZVAL_UNDEF(&$zvalName);\n"; + break; + + case "NULL": + $code .= "\tZVAL_NULL(&$zvalName);\n"; + break; + + case "boolean": + $code .= "\tZVAL_BOOL(&$zvalName, " . ((int) $value) . ");\n"; + break; + + case "integer": + $code .= "\tZVAL_LONG(&$zvalName, $value);\n"; + break; + + case "double": + $code .= "\tZVAL_DOUBLE(&$zvalName, $value);\n"; + break; + + case "string": + if (empty($value)) { + $code .= "\tZVAL_EMPTY_STRING(&$zvalName);\n"; + } else { + $code .= "\tZVAL_STRING(&$zvalName, \"$value\");\n"; + } + break; + + case "array": + if (empty($value)) { + $code .= "\tZVAL_EMPTY_ARRAY(&$zvalName);\n"; + } else { + throw new Exception("Unimplemented property default value"); + } + break; + + default: + throw new Exception("Invalid property default value"); + } + + return $code; + } + + private function getFlagsAsString(): string + { + $flags = "ZEND_ACC_PUBLIC"; + if ($this->flags & Class_::MODIFIER_PROTECTED) { + $flags = "ZEND_ACC_PROTECTED"; + } elseif ($this->flags & Class_::MODIFIER_PRIVATE) { + $flags = "ZEND_ACC_PRIVATE"; + } + + if ($this->flags & Class_::MODIFIER_STATIC) { + $flags .= "|ZEND_ACC_STATIC"; + } + + if ($this->isDeprecated) { + $flags .= "|ZEND_ACC_DEPRECATED"; } + + return $flags; } private function appendMethodSynopsisTypeToElement(DOMDocument $doc, DOMElement $elementToAppend, Type $type) { @@ -968,13 +1197,153 @@ private function appendMethodSynopsisTypeToElement(DOMDocument $doc, DOMElement class ClassInfo { /** @var Name */ public $name; + /** @var int */ + public $flags; + /** @var string */ + public $type; + /** @var string|null */ + public $alias; + /** @var bool */ + public $isDeprecated; + /** @var bool */ + public $isStrictProperties; + /** @var Name[] */ + public $extends; + /** @var Name[] */ + public $implements; + /** @var PropertyInfo[] */ + public $propertyInfos; /** @var FuncInfo[] */ public $funcInfos; - public function __construct(Name $name, array $funcInfos) { + /** + * @param Name[] $extends + * @param Name[] $implements + * @param PropertyInfo[] $propertyInfos + * @param FuncInfo[] $funcInfos + */ + public function __construct( + Name $name, + int $flags, + string $type, + ?string $alias, + bool $isDeprecated, + bool $isStrictProperties, + array $extends, + array $implements, + array $propertyInfos, + array $funcInfos + ) { $this->name = $name; + $this->flags = $flags; + $this->type = $type; + $this->alias = $alias; + $this->isDeprecated = $isDeprecated; + $this->isStrictProperties = $isStrictProperties; + $this->extends = $extends; + $this->implements = $implements; + $this->propertyInfos = $propertyInfos; $this->funcInfos = $funcInfos; } + + public function getRegistration(): string + { + $params = []; + foreach ($this->extends as $extends) { + $params[] = "zend_class_entry *class_entry_" . implode("_", $extends->parts); + } + foreach ($this->implements as $implements) { + $params[] = "zend_class_entry *class_entry_" . implode("_", $implements->parts); + } + foreach ($this->propertyInfos as $property) { + $type = $property->type; + if ($type === null) { + continue; + } + + $representableType = $type->tryToRepresentableType(); + if ($representableType && $representableType->classType) { + $params[] = "zend_class_entry *class_entry_" . str_replace("\\", "_", $representableType->classType->name); + } + } + $params = array_unique($params); + + $escapedName = implode("_", $this->name->parts); + + $code = "zend_class_entry *register_class_$escapedName(" . implode(", ", $params) . ")\n"; + + $code .= "{\n"; + $code .= "\tzend_class_entry ce, *class_entry;\n\n"; + if (count($this->name->parts) > 1) { + $className = array_pop($this->name->parts); + $namespace = $this->name->toCodeString(); + + $code .= "\tINIT_NS_CLASS_ENTRY(ce, \"$namespace\", \"$className\", class_{$escapedName}_methods);\n"; + } else { + $code .= "\tINIT_CLASS_ENTRY(ce, \"$this->name\", class_{$escapedName}_methods);\n"; + } + + if ($this->type === "class" || $this->type === "trait") { + $code .= "\tclass_entry = zend_register_internal_class_ex(&ce, " . (isset($this->extends[0]) ? "class_entry_" . str_replace("\\", "_", $this->extends[0]) : "NULL") . ");\n"; + } else { + $code .= "\tclass_entry = zend_register_internal_interface(&ce);\n"; + } + if ($this->getFlagsAsString()) { + $code .= "\tclass_entry->ce_flags |= " . $this->getFlagsAsString() . ";\n"; + } + + $implements = array_map( + function (Name $item) { + return "class_entry_" . implode("_", $item->parts); + }, + $this->type === "interface" ? $this->extends : $this->implements + ); + + if (!empty($implements)) { + $code .= "\tzend_class_implements(class_entry, " . count($implements) . ", " . implode(", ", $implements) . ");\n"; + } + + if ($this->alias) { + $code .= "\tzend_register_class_alias(\"" . str_replace("\\", "_", $this->alias) . "\", class_entry);\n"; + } + + foreach ($this->propertyInfos as $property) { + $code .= $property->getDeclaration(); + } + + $code .= "\n\treturn class_entry;\n"; + + $code .= "}\n\n"; + + return $code; + } + + private function getFlagsAsString(): string + { + $flags = []; + + if ($this->type === "trait") { + $flags[] = "ZEND_ACC_TRAIT"; + } + + if ($this->flags & Class_::MODIFIER_FINAL) { + $flags[] = "ZEND_ACC_FINAL"; + } + + if ($this->flags & Class_::MODIFIER_ABSTRACT) { + $flags[] = "ZEND_ACC_ABSTRACT"; + } + + if ($this->isDeprecated) { + $flags[] = "ZEND_ACC_DEPRECATED"; + } + + if ($this->isStrictProperties) { + $flags[] = "ZEND_ACC_NO_DYNAMIC_PROPERTIES"; + } + + return implode("|", $flags); + } } class FileInfo { @@ -988,6 +1357,10 @@ class FileInfo { public $declarationPrefix = ""; /** @var bool */ public $generateLegacyArginfo = false; + /** @var bool */ + public $generateClassEntries = false; + /** @var bool */ + public $generateLegacyClassEntries = false; /** * @return iterable @@ -998,6 +1371,15 @@ public function getAllFuncInfos(): iterable { yield from $classInfo->funcInfos; } } + + /** + * @return iterable + */ + public function getAllPropertyInfos(): iterable { + foreach ($this->classInfos as $classInfo) { + yield from $classInfo->propertyInfos; + } + } } class DocCommentTag { @@ -1209,6 +1591,106 @@ function parseFunctionLike( } } +function parseProperty( + Name $class, + int $flags, + Stmt\PropertyProperty $property, + ?Node $type, + ?DocComment $comment +): PropertyInfo { + $isDeprecated = false; + $isKnownName = false; + $docType = false; + + if ($comment) { + $tags = parseDocComment($comment); + foreach ($tags as $tag) { + if ($tag->name === 'deprecated') { + $isDeprecated = true; + } else if ($tag->name === 'known') { + $isKnownName = true; + } else if ($tag->name === 'var') { + $docType = true; + } + } + } + + $propertyType = $type ? Type::fromNode($type) : null; + if ($propertyType === null && !$docType) { + throw new Exception("Missing type for property $class::\$$property->name"); + } + + if ($property->default instanceof Expr\ConstFetch && + $property->default->name->toLowerString() === "null" && + $propertyType && !$propertyType->isNullable() + ) { + $simpleType = $propertyType->tryToSimpleType(); + if ($simpleType === null) { + throw new Exception( + "Property $class::\$$property->name has null default, but is not nullable"); + } + } + + return new PropertyInfo( + new PropertyName($class->__toString(), $property->name->__toString()), + $flags, + $isKnownName, + $isDeprecated, + $propertyType, + $property->default + ); +} + +/** + * @param PropertyInfo[] $properties + * @param FuncInfo[] $methods + */ +function parseClass(Name $name, Stmt\ClassLike $class, array $properties, array $methods): ClassInfo { + $flags = $class instanceof Class_ ? $class->flags : 0; + $comment = $class->getDocComment(); + $alias = null; + $isDeprecated = false; + $isStrictProperties = false; + + if ($comment) { + $tags = parseDocComment($comment); + foreach ($tags as $tag) { + if ($tag->name === 'alias') { + $alias = $tag->getValue(); + } else if ($tag->name === 'deprecated') { + $isDeprecated = true; + } else if ($tag->name === 'strict-properties') { + $isStrictProperties = true; + } + } + } + + $extends = []; + $implements = []; + + if ($class instanceof Class_) { + if ($class->extends) { + $extends[] = $class->extends; + } + $implements = $class->implements; + } elseif ($class instanceof Interface_) { + $extends = $class->extends; + } + + return new ClassInfo( + $name, + $flags, + $class instanceof Class_ ? "class" : ($class instanceof Interface_ ? "interface" : "trait"), + $alias, + $isDeprecated, + $isStrictProperties, + $extends, + $implements, + $properties, + $methods + ); +} + function handlePreprocessorConditions(array &$conds, Stmt $stmt): ?string { foreach ($stmt->getComments() as $comment) { $text = trim($comment->getText()); @@ -1281,6 +1763,7 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac if ($stmt instanceof Stmt\ClassLike) { $className = $stmt->namespacedName; + $propertyInfos = []; $methodInfos = []; foreach ($stmt->stmts as $classStmt) { $cond = handlePreprocessorConditions($conds, $classStmt); @@ -1288,7 +1771,7 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac continue; } - if (!$classStmt instanceof Stmt\ClassMethod) { + if (!$classStmt instanceof Stmt\ClassMethod && !$classStmt instanceof Stmt\Property) { throw new Exception("Not implemented {$classStmt->getType()}"); } @@ -1303,20 +1786,32 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac } if (!($flags & Class_::VISIBILITY_MODIFIER_MASK)) { - throw new Exception("Method visibility modifier is required"); + throw new Exception("Visibility modifier is required"); } - $methodInfos[] = parseFunctionLike( - $prettyPrinter, - new MethodName($className, $classStmt->name->toString()), - $classFlags, - $flags, - $classStmt, - $cond - ); + if ($classStmt instanceof Stmt\Property) { + foreach ($classStmt->props as $property) { + $propertyInfos[] = parseProperty( + $className, + $flags, + $property, + $classStmt->type, + $classStmt->getDocComment() + ); + } + } else if ($classStmt instanceof Stmt\ClassMethod) { + $methodInfos[] = parseFunctionLike( + $prettyPrinter, + new MethodName($className, $classStmt->name->toString()), + $classFlags, + $flags, + $classStmt, + $cond + ); + } } - $fileInfo->classInfos[] = new ClassInfo($className, $methodInfos); + $fileInfo->classInfos[] = parseClass($className, $stmt, $propertyInfos, $methodInfos); continue; } @@ -1348,10 +1843,16 @@ protected function pName_FullyQualified(Name\FullyQualified $node) { $fileInfo->declarationPrefix = $tag->value ? $tag->value . " " : ""; } else if ($tag->name === 'generate-legacy-arginfo') { $fileInfo->generateLegacyArginfo = true; + } else if ($tag->name === 'generate-class-entries') { + $fileInfo->generateClassEntries = true; } } } + if ($fileInfo->generateClassEntries && !$fileInfo->generateFunctionEntries) { + throw new Exception("Function entry generation must be enabled when generating class entries"); + } + handleStatements($fileInfo, $stmts, $prettyPrinter); return $fileInfo; } @@ -1533,6 +2034,20 @@ function (FuncInfo $funcInfo) use($fileInfo, &$generatedFunctionDeclarations) { } } + if ($fileInfo->generateClassEntries) { + $code .= generateClassEntryCode($fileInfo); + } + + return $code; +} + +function generateClassEntryCode(FileInfo $fileInfo): string { + $code = "\n"; + + foreach ($fileInfo->classInfos as $class) { + $code .= $class->getRegistration(); + } + return $code; } diff --git a/ext/curl/curl_file.stub.php b/ext/curl/curl_file.stub.php index 28a218c69836f..7b0c83aa2f9aa 100644 --- a/ext/curl/curl_file.stub.php +++ b/ext/curl/curl_file.stub.php @@ -1,9 +1,19 @@ create_object = IntlIterator_object_create; IntlIterator_ce_ptr->get_iterator = IntlIterator_get_iterator; - zend_class_implements(IntlIterator_ce_ptr, 1, - zend_ce_iterator); memcpy(&IntlIterator_handlers, &std_object_handlers, sizeof IntlIterator_handlers); diff --git a/ext/intl/resourcebundle/resourcebundle.stub.php b/ext/intl/resourcebundle/resourcebundle.stub.php index fccd65e3df4f6..3585bf76e832f 100644 --- a/ext/intl/resourcebundle/resourcebundle.stub.php +++ b/ext/intl/resourcebundle/resourcebundle.stub.php @@ -1,6 +1,9 @@ create_object = ResourceBundle_object_create; + ResourceBundle_ce_ptr->get_iterator = resourcebundle_get_iterator; ResourceBundle_object_handlers = std_object_handlers; ResourceBundle_object_handlers.offset = XtOffsetOf(ResourceBundle_object, zend); @@ -380,7 +375,5 @@ void resourcebundle_register_class( void ) ResourceBundle_object_handlers.free_obj = ResourceBundle_object_free; ResourceBundle_object_handlers.read_dimension = resourcebundle_array_get; ResourceBundle_object_handlers.count_elements = resourcebundle_array_count; - - zend_class_implements(ResourceBundle_ce_ptr, 2, zend_ce_aggregate, zend_ce_countable); } /* }}} */ diff --git a/ext/intl/transliterator/transliterator.stub.php b/ext/intl/transliterator/transliterator.stub.php index c14a4cf0c060f..d9e29bd073797 100644 --- a/ext/intl/transliterator/transliterator.stub.php +++ b/ext/intl/transliterator/transliterator.stub.php @@ -1,9 +1,15 @@ create_object = Transliterator_object_create; + memcpy( &Transliterator_handlers, &std_object_handlers, sizeof Transliterator_handlers ); Transliterator_handlers.offset = XtOffsetOf(Transliterator_object, zo); Transliterator_handlers.free_obj = Transliterator_objects_free; Transliterator_handlers.clone_obj = Transliterator_clone_obj; @@ -273,17 +269,6 @@ void transliterator_register_Transliterator_class( void ) Transliterator_handlers.read_property = Transliterator_read_property; Transliterator_handlers.write_property = Transliterator_write_property; - /* Declare 'Transliterator' class properties */ - if( !Transliterator_ce_ptr ) - { - zend_error( E_ERROR, - "Transliterator: attempt to create properties " - "on a non-registered class." ); - return; - } - zend_declare_property_null( Transliterator_ce_ptr, - "id", sizeof( "id" ) - 1, ZEND_ACC_PUBLIC ); - /* constants are declared in transliterator_register_constants, called from MINIT */ } diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c index b3ce853ef1fd9..088af307132a9 100644 --- a/ext/libxml/libxml.c +++ b/ext/libxml/libxml.c @@ -738,8 +738,6 @@ PHP_LIBXML_API void php_libxml_switch_context(zval *context, zval *oldcontext) static PHP_MINIT_FUNCTION(libxml) { - zend_class_entry ce; - php_libxml_initialize(); REGISTER_LONG_CONSTANT("LIBXML_VERSION", LIBXML_VERSION, CONST_CS | CONST_PERSISTENT); @@ -787,35 +785,7 @@ static PHP_MINIT_FUNCTION(libxml) REGISTER_LONG_CONSTANT("LIBXML_ERR_ERROR", XML_ERR_ERROR, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("LIBXML_ERR_FATAL", XML_ERR_FATAL, CONST_CS | CONST_PERSISTENT); - INIT_CLASS_ENTRY(ce, "LibXMLError", NULL); - libxmlerror_class_entry = zend_register_internal_class(&ce); - - zval default_val; - zend_string *name; - ZVAL_UNDEF(&default_val); - - name = zend_string_init("level", sizeof("level")-1, 1); - zend_declare_typed_property( - libxmlerror_class_entry, name, &default_val, ZEND_ACC_PUBLIC, NULL, - (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release(name); - zend_declare_typed_property( - libxmlerror_class_entry, ZSTR_KNOWN(ZEND_STR_CODE), &default_val, ZEND_ACC_PUBLIC, NULL, - (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - name = zend_string_init("column", sizeof("column")-1, 1); - zend_declare_typed_property( - libxmlerror_class_entry, name, &default_val, ZEND_ACC_PUBLIC, NULL, - (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release(name); - zend_declare_typed_property( - libxmlerror_class_entry, ZSTR_KNOWN(ZEND_STR_MESSAGE), &default_val, ZEND_ACC_PUBLIC, NULL, - (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); - zend_declare_typed_property( - libxmlerror_class_entry, ZSTR_KNOWN(ZEND_STR_FILE), &default_val, ZEND_ACC_PUBLIC, NULL, - (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); - zend_declare_typed_property( - libxmlerror_class_entry, ZSTR_KNOWN(ZEND_STR_LINE), &default_val, ZEND_ACC_PUBLIC, NULL, - (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + libxmlerror_class_entry = register_class_LibXMLError(); if (sapi_module.name) { static const char * const supported_sapis[] = { diff --git a/ext/libxml/libxml.stub.php b/ext/libxml/libxml.stub.php index 12685bd8ceea6..fd6d130b44128 100644 --- a/ext/libxml/libxml.stub.php +++ b/ext/libxml/libxml.stub.php @@ -1,6 +1,23 @@ get_iterator = pdo_stmt_iter_get; pdo_dbstmt_ce->create_object = pdo_dbstmt_new; pdo_dbstmt_ce->serialize = zend_class_serialize_deny; pdo_dbstmt_ce->unserialize = zend_class_unserialize_deny; - zend_class_implements(pdo_dbstmt_ce, 1, zend_ce_aggregate); - zend_declare_property_null(pdo_dbstmt_ce, "queryString", sizeof("queryString")-1, ZEND_ACC_PUBLIC); memcpy(&pdo_dbstmt_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); pdo_dbstmt_object_handlers.offset = XtOffsetOf(pdo_stmt_t, std); @@ -2525,9 +2520,7 @@ void pdo_stmt_init(void) pdo_dbstmt_object_handlers.compare = dbstmt_compare; pdo_dbstmt_object_handlers.clone_obj = NULL; - INIT_CLASS_ENTRY(ce, "PDORow", class_PDORow_methods); - pdo_row_ce = zend_register_internal_class(&ce); - pdo_row_ce->ce_flags |= ZEND_ACC_FINAL; /* when removing this a lot of handlers need to be redone */ + pdo_row_ce = register_class_PDORow(); pdo_row_ce->create_object = pdo_row_new; pdo_row_ce->serialize = zend_class_serialize_deny; pdo_row_ce->unserialize = zend_class_unserialize_deny; diff --git a/ext/pdo/pdo_stmt.stub.php b/ext/pdo/pdo_stmt.stub.php index ab3ab6a42fe95..dbc8aa86352c1 100644 --- a/ext/pdo/pdo_stmt.stub.php +++ b/ext/pdo/pdo_stmt.stub.php @@ -1,9 +1,15 @@ ce_flags |= ZEND_ACC_FINAL; + + return class_entry; +} + diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index 32899e576c67a..dc74967ededbc 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -2682,14 +2682,9 @@ ZEND_GET_MODULE(simplexml) /* {{{ PHP_MINIT_FUNCTION(simplexml) */ PHP_MINIT_FUNCTION(simplexml) { - zend_class_entry ce; - - INIT_CLASS_ENTRY(ce, "SimpleXMLElement", class_SimpleXMLElement_methods); - sxe_class_entry = zend_register_internal_class(&ce); + sxe_class_entry = register_class_SimpleXMLElement(zend_ce_stringable, zend_ce_countable, spl_ce_RecursiveIterator); sxe_class_entry->create_object = sxe_object_new; sxe_class_entry->get_iterator = php_sxe_get_iterator; - zend_class_implements(sxe_class_entry, 3, - zend_ce_countable, zend_ce_stringable, spl_ce_RecursiveIterator); memcpy(&sxe_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); sxe_object_handlers.offset = XtOffsetOf(php_sxe_object, zo); @@ -2719,8 +2714,7 @@ PHP_MINIT_FUNCTION(simplexml) /* TODO: Why do we have two variables for this? */ ce_SimpleXMLElement = sxe_class_entry; - INIT_CLASS_ENTRY(ce, "SimpleXMLIterator", NULL); - ce_SimpleXMLIterator = zend_register_internal_class_ex(&ce, ce_SimpleXMLElement); + ce_SimpleXMLIterator = register_class_SimpleXMLIterator(ce_SimpleXMLElement); php_libxml_register_export(sxe_class_entry, simplexml_export_node); diff --git a/ext/simplexml/simplexml.stub.php b/ext/simplexml/simplexml.stub.php index 7d56de88e9fec..da562db7e4c94 100644 --- a/ext/simplexml/simplexml.stub.php +++ b/ext/simplexml/simplexml.stub.php @@ -1,6 +1,9 @@ create_object = xml_parser_create_object; - xml_parser_ce->ce_flags |= ZEND_ACC_FINAL | ZEND_ACC_NO_DYNAMIC_PROPERTIES; xml_parser_ce->serialize = zend_class_serialize_deny; xml_parser_ce->unserialize = zend_class_unserialize_deny; diff --git a/ext/xml/xml.stub.php b/ext/xml/xml.stub.php index 6dc10d58b5b0e..8167c68e86db2 100644 --- a/ext/xml/xml.stub.php +++ b/ext/xml/xml.stub.php @@ -1,6 +1,9 @@ ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} + diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index c44fdb481f354..d6140b0ff907e 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -346,40 +346,13 @@ static void custom_zend_execute_ex(zend_execute_data *execute_data) PHP_MINIT_FUNCTION(zend_test) { - zend_class_entry class_entry; - - INIT_CLASS_ENTRY(class_entry, "_ZendTestInterface", NULL); - zend_test_interface = zend_register_internal_interface(&class_entry); + zend_test_interface = register_class__ZendTestInterface(); zend_declare_class_constant_long(zend_test_interface, ZEND_STRL("DUMMY"), 0); - INIT_CLASS_ENTRY(class_entry, "_ZendTestClass", class__ZendTestClass_methods); - zend_test_class = zend_register_internal_class(&class_entry); - zend_class_implements(zend_test_class, 1, zend_test_interface); + + zend_test_class = register_class__ZendTestClass(zend_test_interface, zend_standard_class_def); zend_test_class->create_object = zend_test_class_new; zend_test_class->get_static_method = zend_test_class_static_method_get; - zend_declare_property_null(zend_test_class, "_StaticProp", sizeof("_StaticProp") - 1, ZEND_ACC_STATIC); - - { - zend_string *name = zend_string_init("intProp", sizeof("intProp") - 1, 1); - zval val; - ZVAL_LONG(&val, 123); - zend_declare_typed_property( - zend_test_class, name, &val, ZEND_ACC_PUBLIC, NULL, - (zend_type) ZEND_TYPE_INIT_CODE(IS_LONG, 0, 0)); - zend_string_release(name); - } - - { - zend_string *name = zend_string_init("classProp", sizeof("classProp") - 1, 1); - zend_string *class_name = zend_string_init("stdClass", sizeof("stdClass") - 1, 1); - zval val; - ZVAL_NULL(&val); - zend_declare_typed_property( - zend_test_class, name, &val, ZEND_ACC_PUBLIC, NULL, - (zend_type) ZEND_TYPE_INIT_CLASS(class_name, 1, 0)); - zend_string_release(name); - } - { zend_string *name = zend_string_init("classUnionProp", sizeof("classUnionProp") - 1, 1); zend_string *class_name1 = zend_string_init("stdClass", sizeof("stdClass") - 1, 1); @@ -395,35 +368,16 @@ PHP_MINIT_FUNCTION(zend_test) zend_string_release(name); } - { - zend_string *name = zend_string_init("staticIntProp", sizeof("staticIntProp") - 1, 1); - zval val; - ZVAL_LONG(&val, 123); - zend_declare_typed_property( - zend_test_class, name, &val, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC, NULL, - (zend_type) ZEND_TYPE_INIT_CODE(IS_LONG, 0, 0)); - zend_string_release(name); - } - - INIT_CLASS_ENTRY(class_entry, "_ZendTestChildClass", NULL); - zend_test_child_class = zend_register_internal_class_ex(&class_entry, zend_test_class); + zend_test_child_class = register_class__ZendTestChildClass(zend_test_class); memcpy(&zend_test_class_handlers, &std_object_handlers, sizeof(zend_object_handlers)); zend_test_class_handlers.get_method = zend_test_class_method_get; - INIT_CLASS_ENTRY(class_entry, "_ZendTestTrait", class__ZendTestTrait_methods); - zend_test_trait = zend_register_internal_class(&class_entry); - zend_test_trait->ce_flags |= ZEND_ACC_TRAIT; - zend_declare_property_null(zend_test_trait, "testProp", sizeof("testProp")-1, ZEND_ACC_PUBLIC); - - zend_register_class_alias("_ZendTestClassAlias", zend_test_class); + zend_test_trait = register_class__ZendTestTrait(); REGISTER_LONG_CONSTANT("ZEND_TEST_DEPRECATED", 42, CONST_PERSISTENT | CONST_DEPRECATED); - INIT_CLASS_ENTRY(class_entry, "ZendTestAttribute", NULL); - zend_test_attribute = zend_register_internal_class(&class_entry); - zend_test_attribute->ce_flags |= ZEND_ACC_FINAL; - + zend_test_attribute = register_class_ZendTestAttribute(); { zend_internal_attribute *attr = zend_internal_attribute_register(zend_test_attribute, ZEND_ATTRIBUTE_TARGET_ALL); attr->validator = zend_attribute_validate_zendtestattribute; diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index 91ff78e113e0a..ce688655a70c6 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -1,10 +1,26 @@ ce_flags |= ZEND_ACC_TRAIT; + + zend_declare_property_null(class_entry, "testProp", sizeof("testProp") - 1, ZEND_ACC_PUBLIC); + + return class_entry; +} + +zend_class_entry *register_class_ZendTestAttribute() +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "ZendTestAttribute", class_ZendTestAttribute_methods); + class_entry = zend_register_internal_class_ex(&ce, NULL); + class_entry->ce_flags |= ZEND_ACC_FINAL; + + return class_entry; +} + +zend_class_entry *register_class_ZendTestNS_Foo() +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "ZendTestNS", "Foo", class_ZendTestNS_Foo_methods); + class_entry = zend_register_internal_class_ex(&ce, NULL); + + return class_entry; +} + +zend_class_entry *register_class_ZendTestNS2_Foo() +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "ZendTestNS2", "Foo", class_ZendTestNS2_Foo_methods); + class_entry = zend_register_internal_class_ex(&ce, NULL); + + return class_entry; +} + diff --git a/ext/zip/php_zip.stub.php b/ext/zip/php_zip.stub.php index 5ae4731ae25d5..ff7b9d99fbe9f 100644 --- a/ext/zip/php_zip.stub.php +++ b/ext/zip/php_zip.stub.php @@ -66,6 +66,9 @@ function zip_entry_compressionmethod($zip_entry): string|false {} class ZipArchive { + /** @var string|null */ + public $name; + /** @return bool|int */ public function open(string $filename, int $flags = 0) {} diff --git a/ext/zip/php_zip_arginfo.h b/ext/zip/php_zip_arginfo.h index ba72e52aa8b6b..104fac05a0b56 100644 --- a/ext/zip/php_zip_arginfo.h +++ b/ext/zip/php_zip_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 095084d2a2df557398191af5dd6c8bea6bb7c338 */ + * Stub hash: a5b8a10dbaeddf5d0d1ac751ff64a5d7ff235562 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_zip_open, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) From 56ac2b325a6d35bf768a62c4c9b5e413ea5d10e5 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 19 Jan 2021 11:48:22 +0100 Subject: [PATCH 2/9] Fix xml --- ext/xml/xml_arginfo.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/xml/xml_arginfo.h b/ext/xml/xml_arginfo.h index b3a4aee500576..0de97a4ba3003 100644 --- a/ext/xml/xml_arginfo.h +++ b/ext/xml/xml_arginfo.h @@ -138,11 +138,11 @@ static const zend_function_entry class_XMLParser_methods[] = { ZEND_FE_END }; -zend_class_entry *register_class_XmlParser() +zend_class_entry *register_class_XMLParser() { zend_class_entry ce, *class_entry; - INIT_CLASS_ENTRY(ce, "XMLParser", class_XmlParser_methods); + INIT_CLASS_ENTRY(ce, "XMLParser", class_XMLParser_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES; From ca7d0e01a054ea3a56bd68ded1ac9735c2bb077a Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 19 Jan 2021 11:56:25 +0100 Subject: [PATCH 3/9] Rebase fixup RepresentableType has been replaced by ArginfoType. This is only a partial fix, in that we still need to handle class union types. --- build/gen_stub.php | 19 +++++++------------ ext/zend_test/test.stub.php | 2 +- ext/zend_test/test_arginfo.h | 2 +- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index 9d8d68c94c3a6..ffa7c5972cfe1 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -1033,21 +1033,16 @@ function (Expr $expr) use (&$defaultValueConstant) { } if ($this->type) { - $typeFlags = $this->type->tryToRepresentableType(); - if ($typeFlags === null) { - echo "Skipping code generation for property $this->name, because it has an unimplemented type\n"; - return ""; - } - - if ($typeFlags->classType) { + $arginfoType = $this->type->toArginfoType(); + if ($arginfoType->hasClassType()) { $simpleType = $this->type->tryToSimpleType(); if ($simpleType) { - $typeCode = "(zend_type) ZEND_TYPE_INIT_CE(class_entry_" . str_replace("\\", "_", $typeFlags->classType->name) . ", " . ((int) $this->type->isNullable()) . ", 0)"; + $typeCode = "(zend_type) ZEND_TYPE_INIT_CE(class_entry_" . str_replace("\\", "_", $arginfoType->classTypes[0]->name) . ", " . ((int) $this->type->isNullable()) . ", 0)"; } else { throw new Exception("Property $this->name has an unsupported union type"); } } else { - $typeCode = "(zend_type) ZEND_TYPE_INIT_MASK(" . $typeFlags->toTypeMask() . ")"; + $typeCode = "(zend_type) ZEND_TYPE_INIT_MASK(" . $arginfoType->toTypeMask() . ")"; } $code .= $this->initializeValue($defaultValueType, $defaultValue); @@ -1261,9 +1256,9 @@ public function getRegistration(): string continue; } - $representableType = $type->tryToRepresentableType(); - if ($representableType && $representableType->classType) { - $params[] = "zend_class_entry *class_entry_" . str_replace("\\", "_", $representableType->classType->name); + $arginfoType = $type->toArginfoType(); + if (count($arginfoType->classTypes) == 1) { + $params[] = "zend_class_entry *class_entry_" . str_replace("\\", "_", $arginfoType->classTypes[0]->name); } } $params = array_unique($params); diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index ce688655a70c6..e72094028d125 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -19,7 +19,7 @@ class _ZendTestClass implements _ZendTestInterface { public int $intProp = 123; public ?stdClass $classProp = null; - public stdClass|Iterator|null $classUnionProp = null; + //public stdClass|Iterator|null $classUnionProp = null; public static function is_object(): int {} diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index c00893c621d56..c27766cadd4fa 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 520097c67aab4b8f2f6c641be4816fb4e06e7e99 */ + * Stub hash: 950679cde15789a9060d4798dc35dc5a590fd8b2 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() From bcd8514f4b4dbce98b89d77bd71b71e0a125354f Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 19 Jan 2021 12:07:55 +0100 Subject: [PATCH 4/9] fix xml again --- ext/xml/xml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/xml/xml.c b/ext/xml/xml.c index eeda7e5cef885..3b692a865133e 100644 --- a/ext/xml/xml.c +++ b/ext/xml/xml.c @@ -253,7 +253,7 @@ static void php_xml_free_wrapper(void *ptr) PHP_MINIT_FUNCTION(xml) { - xml_parser_ce = register_class_XmlParser(); + xml_parser_ce = register_class_XMLParser(); xml_parser_ce->create_object = xml_parser_create_object; xml_parser_ce->serialize = zend_class_serialize_deny; xml_parser_ce->unserialize = zend_class_unserialize_deny; From 6ec49f486dd784b95c3173b0c85120c1dfe88f14 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 19 Jan 2021 12:17:29 +0100 Subject: [PATCH 5/9] Register Exception/Error via stubs --- Zend/zend_exceptions.c | 52 +++++++++++++----------------------------- 1 file changed, 16 insertions(+), 36 deletions(-) diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 15f4ad42c4856..10864d4f175ba 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -53,14 +53,22 @@ static zend_object_handlers default_exception_handlers; /* {{{ zend_implement_throwable */ static int zend_implement_throwable(zend_class_entry *interface, zend_class_entry *class_type) { - if (instanceof_function(class_type, zend_ce_exception) || instanceof_function(class_type, zend_ce_error)) { + /* During the registration of Exception/Error themselves, this may be called before + * zend_ce_exception and zend_ce_error have been initialized, so handle these explicitly. */ + if (zend_ce_exception && instanceof_function(class_type, zend_ce_exception)) { return SUCCESS; } - zend_error_noreturn(E_ERROR, "Class %s cannot implement interface %s, extend %s or %s instead", + if (zend_ce_error && instanceof_function(class_type, zend_ce_error)) { + return SUCCESS; + } + if (zend_string_equals_literal(class_type->name, "Exception") + || zend_string_equals_literal(class_type->name, "Error")) { + return SUCCESS; + } + zend_error_noreturn(E_ERROR, + "Class %s cannot implement interface %s, extend Exception or Error instead", ZSTR_VAL(class_type->name), - ZSTR_VAL(interface->name), - ZSTR_VAL(zend_ce_exception->name), - ZSTR_VAL(zend_ce_error->name)); + ZSTR_VAL(interface->name)); return FAILURE; } /* }}} */ @@ -740,52 +748,24 @@ ZEND_METHOD(Exception, __toString) } /* }}} */ -static void declare_exception_properties(zend_class_entry *ce) -{ - zval val; - - zend_declare_property_string(ce, "message", sizeof("message")-1, "", ZEND_ACC_PROTECTED); - zend_declare_property_string(ce, "string", sizeof("string")-1, "", ZEND_ACC_PRIVATE); - zend_declare_property_long(ce, "code", sizeof("code")-1, 0, ZEND_ACC_PROTECTED); - zend_declare_property_null(ce, "file", sizeof("file")-1, ZEND_ACC_PROTECTED); - zend_declare_property_null(ce, "line", sizeof("line")-1, ZEND_ACC_PROTECTED); - - ZVAL_EMPTY_ARRAY(&val); - zend_declare_typed_property( - ce, ZSTR_KNOWN(ZEND_STR_TRACE), &val, ZEND_ACC_PRIVATE, NULL, - (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); - - ZVAL_NULL(&val); - zend_declare_typed_property( - ce, ZSTR_KNOWN(ZEND_STR_PREVIOUS), &val, ZEND_ACC_PRIVATE, NULL, - (zend_type) ZEND_TYPE_INIT_CE(zend_ce_throwable, /* allow_null */ 1, 0)); -} - void zend_register_default_exception(void) /* {{{ */ { - zend_class_entry ce; - zend_ce_throwable = register_class_Throwable(zend_ce_stringable); zend_ce_throwable->interface_gets_implemented = zend_implement_throwable; memcpy(&default_exception_handlers, &std_object_handlers, sizeof(zend_object_handlers)); default_exception_handlers.clone_obj = NULL; - INIT_CLASS_ENTRY(ce, "Exception", class_Exception_methods); - zend_ce_exception = zend_register_internal_class_ex(&ce, NULL); + zend_ce_exception = register_class_Exception(zend_ce_throwable); zend_ce_exception->create_object = zend_default_exception_new; - zend_class_implements(zend_ce_exception, 1, zend_ce_throwable); - declare_exception_properties(zend_ce_exception); zend_ce_error_exception = register_class_ErrorException(zend_ce_exception); zend_ce_error_exception->create_object = zend_error_exception_new; + /* Declared manually because it uses constant E_ERROR. */ zend_declare_property_long(zend_ce_error_exception, "severity", sizeof("severity")-1, E_ERROR, ZEND_ACC_PROTECTED); - INIT_CLASS_ENTRY(ce, "Error", class_Error_methods); - zend_ce_error = zend_register_internal_class_ex(&ce, NULL); + zend_ce_error = register_class_Error(zend_ce_throwable); zend_ce_error->create_object = zend_default_exception_new; - zend_class_implements(zend_ce_error, 1, zend_ce_throwable); - declare_exception_properties(zend_ce_error); zend_ce_compile_error = register_class_CompileError(zend_ce_error); zend_ce_compile_error->create_object = zend_default_exception_new; From 873acc0337c6dd9dc54f79a66c33f3f689954841 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 19 Jan 2021 12:38:41 +0100 Subject: [PATCH 6/9] register curlfile --- ext/curl/curl_file.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ext/curl/curl_file.c b/ext/curl/curl_file.c index aad162604a1f4..a81239a60aba2 100644 --- a/ext/curl/curl_file.c +++ b/ext/curl/curl_file.c @@ -122,12 +122,7 @@ ZEND_METHOD(CURLFile, setPostFilename) void curlfile_register_class(void) { - zend_class_entry ce; - INIT_CLASS_ENTRY( ce, "CURLFile", class_CURLFile_methods ); - curl_CURLFile_class = zend_register_internal_class(&ce); + curl_CURLFile_class = register_class_CURLFile(); curl_CURLFile_class->serialize = zend_class_serialize_deny; curl_CURLFile_class->unserialize = zend_class_unserialize_deny; - zend_declare_property_string(curl_CURLFile_class, "name", sizeof("name")-1, "", ZEND_ACC_PUBLIC); - zend_declare_property_string(curl_CURLFile_class, "mime", sizeof("mime")-1, "", ZEND_ACC_PUBLIC); - zend_declare_property_string(curl_CURLFile_class, "postname", sizeof("postname")-1, "", ZEND_ACC_PUBLIC); } From 86a85c50a75ead666da9867e1f713be477fb6d5b Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 19 Jan 2021 14:33:56 +0100 Subject: [PATCH 7/9] Fix Throwable implementation, again --- Zend/zend_exceptions.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 10864d4f175ba..0026860ef8ca6 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -53,18 +53,17 @@ static zend_object_handlers default_exception_handlers; /* {{{ zend_implement_throwable */ static int zend_implement_throwable(zend_class_entry *interface, zend_class_entry *class_type) { - /* During the registration of Exception/Error themselves, this may be called before - * zend_ce_exception and zend_ce_error have been initialized, so handle these explicitly. */ - if (zend_ce_exception && instanceof_function(class_type, zend_ce_exception)) { - return SUCCESS; - } - if (zend_ce_error && instanceof_function(class_type, zend_ce_error)) { - return SUCCESS; - } - if (zend_string_equals_literal(class_type->name, "Exception") - || zend_string_equals_literal(class_type->name, "Error")) { + /* zend_ce_exception and zend_ce_error may not be initialized yet when this is caleld (e.g when + * implementing Throwable for Exception itself). Perform a manual inheritance check. */ + zend_class_entry *root = class_type; + while (root->parent) { + root = root->parent; + } + if (zend_string_equals_literal(root->name, "Exception") + || zend_string_equals_literal(root->name, "Error")) { return SUCCESS; } + zend_error_noreturn(E_ERROR, "Class %s cannot implement interface %s, extend Exception or Error instead", ZSTR_VAL(class_type->name), From 0d03441b7a6f3efbfd3e565aa94bd481150b321e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Mon, 25 Jan 2021 23:25:21 +0100 Subject: [PATCH 8/9] Address code review --- Zend/zend_exceptions.stub.php | 4 - Zend/zend_exceptions_arginfo.h | 96 ++++++--- build/gen_stub.php | 189 ++++++------------ ext/curl/curl_file_arginfo.h | 22 +- .../transliterator/transliterator_arginfo.h | 6 +- ext/libxml/libxml.stub.php | 4 - ext/libxml/libxml_arginfo.h | 18 +- ext/pdo/pdo_stmt_arginfo.h | 6 +- ext/zend_test/test.c | 2 +- ext/zend_test/test_arginfo.h | 17 +- 10 files changed, 192 insertions(+), 172 deletions(-) diff --git a/Zend/zend_exceptions.stub.php b/Zend/zend_exceptions.stub.php index 28cf456ab260f..89dff788c09c6 100644 --- a/Zend/zend_exceptions.stub.php +++ b/Zend/zend_exceptions.stub.php @@ -35,9 +35,7 @@ class Exception implements Throwable protected $file = null; /** @var int|null */ protected $line = null; - /** @known */ private array $trace = []; - /** @known */ private ?Throwable $previous = null; final private function __clone(): void {} @@ -94,9 +92,7 @@ class Error implements Throwable protected $file = null; /** @var int|null */ protected $line = null; - /** @known */ private array $trace = []; - /** @known */ private ?Throwable $previous = null; /** @implementation-alias Exception::__clone */ diff --git a/Zend/zend_exceptions_arginfo.h b/Zend/zend_exceptions_arginfo.h index bbc0e351c00da..748927fd92964 100644 --- a/Zend/zend_exceptions_arginfo.h +++ b/Zend/zend_exceptions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: fc90f59a8c670e7874f4a7564333c5b22c0eea5e */ + * Stub hash: 053248482a00efc35be505186f8430708bd280e9 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Throwable_getMessage, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() @@ -205,23 +205,48 @@ zend_class_entry *register_class_Exception(zend_class_entry *class_entry_Throwab class_entry = zend_register_internal_class_ex(&ce, NULL); zend_class_implements(class_entry, 1, class_entry_Throwable); - zend_declare_property_string(class_entry, "message", sizeof("message") - 1, "", ZEND_ACC_PROTECTED); - - zend_declare_property_string(class_entry, "string", sizeof("string") - 1, "", ZEND_ACC_PRIVATE); - - zend_declare_property_long(class_entry, "code", sizeof("code") - 1, 0, ZEND_ACC_PROTECTED); - - zend_declare_property_null(class_entry, "file", sizeof("file") - 1, ZEND_ACC_PROTECTED); - - zend_declare_property_null(class_entry, "line", sizeof("line") - 1, ZEND_ACC_PROTECTED); + zval property_message_default_value; + ZVAL_EMPTY_STRING(&property_message_default_value); + zend_string *property_message_name = zend_string_init("message", sizeof("message") - 1, 1); + zend_declare_property_ex(class_entry, property_message_name, &property_message_default_value, ZEND_ACC_PROTECTED, NULL); + zend_string_release(property_message_name); + + zval property_string_default_value; + ZVAL_EMPTY_STRING(&property_string_default_value); + zend_string *property_string_name = zend_string_init("string", sizeof("string") - 1, 1); + zend_declare_property_ex(class_entry, property_string_name, &property_string_default_value, ZEND_ACC_PRIVATE, NULL); + zend_string_release(property_string_name); + + zval property_code_default_value; + ZVAL_LONG(&property_code_default_value, 0); + zend_string *property_code_name = zend_string_init("code", sizeof("code") - 1, 1); + zend_declare_property_ex(class_entry, property_code_name, &property_code_default_value, ZEND_ACC_PROTECTED, NULL); + zend_string_release(property_code_name); + + zval property_file_default_value; + ZVAL_NULL(&property_file_default_value); + zend_string *property_file_name = zend_string_init("file", sizeof("file") - 1, 1); + zend_declare_property_ex(class_entry, property_file_name, &property_file_default_value, ZEND_ACC_PROTECTED, NULL); + zend_string_release(property_file_name); + + zval property_line_default_value; + ZVAL_NULL(&property_line_default_value); + zend_string *property_line_name = zend_string_init("line", sizeof("line") - 1, 1); + zend_declare_property_ex(class_entry, property_line_name, &property_line_default_value, ZEND_ACC_PROTECTED, NULL); + zend_string_release(property_line_name); zval property_trace_default_value; ZVAL_EMPTY_ARRAY(&property_trace_default_value); - zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_TRACE), &property_trace_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); + zend_string *property_trace_name = zend_string_init("trace", sizeof("trace") - 1, 1); + zend_declare_typed_property(class_entry, property_trace_name, &property_trace_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); + zend_string_release(property_trace_name); + zend_string *property_previous_class_Throwable = zend_string_init("Throwable", sizeof("Throwable"), 1); zval property_previous_default_value; ZVAL_NULL(&property_previous_default_value); - zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_PREVIOUS), &property_previous_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_CE(class_entry_Throwable, 1, 0)); + zend_string *property_previous_name = zend_string_init("previous", sizeof("previous") - 1, 1); + zend_declare_typed_property(class_entry, property_previous_name, &property_previous_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_previous_class_Throwable, 1, 0)); + zend_string_release(property_previous_name); return class_entry; } @@ -244,23 +269,48 @@ zend_class_entry *register_class_Error(zend_class_entry *class_entry_Throwable) class_entry = zend_register_internal_class_ex(&ce, NULL); zend_class_implements(class_entry, 1, class_entry_Throwable); - zend_declare_property_string(class_entry, "message", sizeof("message") - 1, "", ZEND_ACC_PROTECTED); - - zend_declare_property_string(class_entry, "string", sizeof("string") - 1, "", ZEND_ACC_PRIVATE); - - zend_declare_property_long(class_entry, "code", sizeof("code") - 1, 0, ZEND_ACC_PROTECTED); - - zend_declare_property_null(class_entry, "file", sizeof("file") - 1, ZEND_ACC_PROTECTED); - - zend_declare_property_null(class_entry, "line", sizeof("line") - 1, ZEND_ACC_PROTECTED); + zval property_message_default_value; + ZVAL_EMPTY_STRING(&property_message_default_value); + zend_string *property_message_name = zend_string_init("message", sizeof("message") - 1, 1); + zend_declare_property_ex(class_entry, property_message_name, &property_message_default_value, ZEND_ACC_PROTECTED, NULL); + zend_string_release(property_message_name); + + zval property_string_default_value; + ZVAL_EMPTY_STRING(&property_string_default_value); + zend_string *property_string_name = zend_string_init("string", sizeof("string") - 1, 1); + zend_declare_property_ex(class_entry, property_string_name, &property_string_default_value, ZEND_ACC_PRIVATE, NULL); + zend_string_release(property_string_name); + + zval property_code_default_value; + ZVAL_LONG(&property_code_default_value, 0); + zend_string *property_code_name = zend_string_init("code", sizeof("code") - 1, 1); + zend_declare_property_ex(class_entry, property_code_name, &property_code_default_value, ZEND_ACC_PROTECTED, NULL); + zend_string_release(property_code_name); + + zval property_file_default_value; + ZVAL_NULL(&property_file_default_value); + zend_string *property_file_name = zend_string_init("file", sizeof("file") - 1, 1); + zend_declare_property_ex(class_entry, property_file_name, &property_file_default_value, ZEND_ACC_PROTECTED, NULL); + zend_string_release(property_file_name); + + zval property_line_default_value; + ZVAL_NULL(&property_line_default_value); + zend_string *property_line_name = zend_string_init("line", sizeof("line") - 1, 1); + zend_declare_property_ex(class_entry, property_line_name, &property_line_default_value, ZEND_ACC_PROTECTED, NULL); + zend_string_release(property_line_name); zval property_trace_default_value; ZVAL_EMPTY_ARRAY(&property_trace_default_value); - zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_TRACE), &property_trace_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); + zend_string *property_trace_name = zend_string_init("trace", sizeof("trace") - 1, 1); + zend_declare_typed_property(class_entry, property_trace_name, &property_trace_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); + zend_string_release(property_trace_name); + zend_string *property_previous_class_Throwable = zend_string_init("Throwable", sizeof("Throwable"), 1); zval property_previous_default_value; ZVAL_NULL(&property_previous_default_value); - zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_PREVIOUS), &property_previous_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_CE(class_entry_Throwable, 1, 0)); + zend_string *property_previous_name = zend_string_init("previous", sizeof("previous") - 1, 1); + zend_declare_typed_property(class_entry, property_previous_name, &property_previous_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_previous_class_Throwable, 1, 0)); + zend_string_release(property_previous_name); return class_entry; } diff --git a/build/gen_stub.php b/build/gen_stub.php index ffa7c5972cfe1..3fac13787c87f 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -300,7 +300,7 @@ public function tryToSimpleType(): ?SimpleType { return null; } - public function toArginfoType(): ?ArginfoType { + public function toArginfoType(): ArginfoType { $classTypes = []; $builtinTypes = []; foreach ($this->types as $type) { @@ -465,12 +465,12 @@ public function getDefaultValueAsMethodSynopsisString(): ?string { } class PropertyName { - /** @var string */ + /** @var Name */ public $class; /** @var string */ public $property; - public function __construct(string $class, string $property) + public function __construct(Name $class, string $property) { $this->class = $class; $this->property = $property; @@ -478,7 +478,7 @@ public function __construct(string $class, string $property) public function __toString() { - return $this->class . "::$" . $this->property; + return $this->class->toString() . "::$" . $this->property; } } @@ -864,32 +864,6 @@ private function getFlagsAsArginfoString(): string return $flags; } -} - -class PropertyInfo -{ - /** @var PropertyName */ - public $name; - /** @var int */ - public $flags; - /** @var bool */ - public $isKnownName; - /** @var bool */ - public $isDeprecated; - /** @var Type|null */ - public $type; - /** @var Expr|null */ - public $defaultValue; - - public function __construct(PropertyName $name, int $flags, bool $isKnownName, bool $isDeprecated, ?Type $type, ?Expr $defaultValue) - { - $this->name = $name; - $this->flags = $flags; - $this->isKnownName = $isKnownName; - $this->isDeprecated = $isDeprecated; - $this->type = $type; - $this->defaultValue = $defaultValue; - } /** * @param FuncInfo[] $funcMap @@ -999,6 +973,42 @@ public function getMethodSynopsisElement(array $funcMap, array $aliasMap, DOMDoc return $methodSynopsis; } + private function appendMethodSynopsisTypeToElement(DOMDocument $doc, DOMElement $elementToAppend, Type $type) { + if (count($type->types) > 1) { + $typeElement = $doc->createElement('type'); + $typeElement->setAttribute("class", "union"); + + foreach ($type->types as $type) { + $unionTypeElement = $doc->createElement('type', $type->name); + $typeElement->appendChild($unionTypeElement); + } + } else { + $typeElement = $doc->createElement('type', $type->types[0]->name); + } + + $elementToAppend->appendChild($typeElement); + } +} + +class PropertyInfo +{ + /** @var PropertyName */ + public $name; + /** @var int */ + public $flags; + /** @var Type|null */ + public $type; + /** @var Expr|null */ + public $defaultValue; + + public function __construct(PropertyName $name, int $flags, ?Type $type, ?Expr $defaultValue) + { + $this->name = $name; + $this->flags = $flags; + $this->type = $type; + $this->defaultValue = $defaultValue; + } + public function discardInfoForOldPhpVersions(): void { $this->type = null; } @@ -1032,68 +1042,37 @@ function (Expr $expr) use (&$defaultValueConstant) { return ""; } + $typeCode = ""; if ($this->type) { $arginfoType = $this->type->toArginfoType(); if ($arginfoType->hasClassType()) { $simpleType = $this->type->tryToSimpleType(); + + $className = $arginfoType->classTypes[0]->name; + $code .= " zend_string *property_{$propertyName}_class_{$className} = zend_string_init(\"$className\", sizeof(\"$className\"), 1);\n"; if ($simpleType) { - $typeCode = "(zend_type) ZEND_TYPE_INIT_CE(class_entry_" . str_replace("\\", "_", $arginfoType->classTypes[0]->name) . ", " . ((int) $this->type->isNullable()) . ", 0)"; + $typeCode = "(zend_type) ZEND_TYPE_INIT_CLASS(property_{$propertyName}_class_{$className}, " . ((int) $this->type->isNullable()) . ", 0)"; + } elseif (count($arginfoType->classTypes) === 1) { + $typeCode = "(zend_type) ZEND_TYPE_INIT_CLASS(property_{$propertyName}_class_{$className}, 0, " . $arginfoType->toTypeMask() . ")"; } else { throw new Exception("Property $this->name has an unsupported union type"); } } else { $typeCode = "(zend_type) ZEND_TYPE_INIT_MASK(" . $arginfoType->toTypeMask() . ")"; } + } - $code .= $this->initializeValue($defaultValueType, $defaultValue); + $code .= $this->initializeValue($defaultValueType, $defaultValue, $this->type !== null); - if ($this->isKnownName) { - $nameCode = "ZSTR_KNOWN(ZEND_STR_" . strtoupper($propertyName) . ")"; - } else { - $code .= "\tzend_string *property_{$propertyName}_name = zend_string_init(\"$propertyName\", sizeof(\"$propertyName\") - 1, 1);\n"; - $nameCode = "property_{$propertyName}_name"; - } + $code .= "\tzend_string *property_{$propertyName}_name = zend_string_init(\"$propertyName\", sizeof(\"$propertyName\") - 1, 1);\n"; + $nameCode = "property_{$propertyName}_name"; + if ($this->type !== null) { $code .= "\tzend_declare_typed_property(class_entry, $nameCode, &property_{$propertyName}_default_value, " . $this->getFlagsAsString() . ", NULL, $typeCode);\n"; - if (!$this->isKnownName) { - $code .= "\tzend_string_release(property_{$propertyName}_name);\n"; - } } else { - if ($this->isKnownName) { - Throw new Exception("Non-typed property $this->name cannot be annotated as @known"); - } - - switch ($defaultValueType) { - case "undefined": // intentional fallthrough - case "NULL": - $code .= "\tzend_declare_property_null(class_entry, \"$propertyName\", sizeof(\"$propertyName\") - 1, " . $this->getFlagsAsString() . ");\n"; - break; - - case "boolean": - $code .= "\tzend_declare_property_bool(class_entry, \"$propertyName\", sizeof(\"$propertyName\") - 1, " . ((int) $defaultValue) . ", " . $this->getFlagsAsString() . ");\n"; - break; - - case "integer": - $code .= "\tzend_declare_property_long(class_entry, \"$propertyName\", sizeof(\"$propertyName\") - 1, " . $defaultValue . ", " . $this->getFlagsAsString() . ");\n"; - break; - - case "double": - $code .= "\tzend_declare_property_double(class_entry, \"$propertyName\", sizeof(\"$propertyName\") - 1, " . $defaultValue . ", " . $this->getFlagsAsString() . ");\n"; - break; - - case "string": - $code .= "\tzend_declare_property_string(class_entry, \"$propertyName\", sizeof(\"$propertyName\") - 1, \"" . $defaultValue . "\", " . $this->getFlagsAsString() . ");\n"; - break; - - case "array": - $code .= $this->initializeValue($defaultValueType, $defaultValue); - $code .= "\tzend_declare_property_ex(class_entry, \"$propertyName\", sizeof(\"$propertyName\") - 1, property_{$propertyName}_default_value, " . $this->getFlagsAsString() . ");\n"; - break; - - default: - throw new Exception("Property $this->name has an invalid default value"); - } + $code .= "\tzend_declare_property_ex(class_entry, $nameCode, &property_{$propertyName}_default_value, " . $this->getFlagsAsString() . ", NULL);\n"; } + $code .= "\tzend_string_release(property_{$propertyName}_name);\n"; return $code; } @@ -1101,7 +1080,7 @@ function (Expr $expr) use (&$defaultValueConstant) { /** * @param mixed $value */ - private function initializeValue(string $type, $value): string + private function initializeValue(string $type, $value, bool $isTyped): string { $name = $this->name->property; $zvalName = "property_{$name}_default_value"; @@ -1110,7 +1089,11 @@ private function initializeValue(string $type, $value): string switch ($type) { case "undefined": - $code .= "\tZVAL_UNDEF(&$zvalName);\n"; + if ($isTyped) { + $code .= "\tZVAL_UNDEF(&$zvalName);\n"; + } else { + $code .= "\tZVAL_NULL(&$zvalName);\n"; + } break; case "NULL": @@ -1165,28 +1148,8 @@ private function getFlagsAsString(): string $flags .= "|ZEND_ACC_STATIC"; } - if ($this->isDeprecated) { - $flags .= "|ZEND_ACC_DEPRECATED"; - } - return $flags; } - - private function appendMethodSynopsisTypeToElement(DOMDocument $doc, DOMElement $elementToAppend, Type $type) { - if (count($type->types) > 1) { - $typeElement = $doc->createElement('type'); - $typeElement->setAttribute("class", "union"); - - foreach ($type->types as $type) { - $unionTypeElement = $doc->createElement('type', $type->name); - $typeElement->appendChild($unionTypeElement); - } - } else { - $typeElement = $doc->createElement('type', $type->types[0]->name); - } - - $elementToAppend->appendChild($typeElement); - } } class ClassInfo { @@ -1250,18 +1213,6 @@ public function getRegistration(): string foreach ($this->implements as $implements) { $params[] = "zend_class_entry *class_entry_" . implode("_", $implements->parts); } - foreach ($this->propertyInfos as $property) { - $type = $property->type; - if ($type === null) { - continue; - } - - $arginfoType = $type->toArginfoType(); - if (count($arginfoType->classTypes) == 1) { - $params[] = "zend_class_entry *class_entry_" . str_replace("\\", "_", $arginfoType->classTypes[0]->name); - } - } - $params = array_unique($params); $escapedName = implode("_", $this->name->parts); @@ -1270,8 +1221,8 @@ public function getRegistration(): string $code .= "{\n"; $code .= "\tzend_class_entry ce, *class_entry;\n\n"; if (count($this->name->parts) > 1) { - $className = array_pop($this->name->parts); - $namespace = $this->name->toCodeString(); + $className = $this->name->getLast(); + $namespace = $this->name->slice(0, -1); $code .= "\tINIT_NS_CLASS_ENTRY(ce, \"$namespace\", \"$className\", class_{$escapedName}_methods);\n"; } else { @@ -1279,7 +1230,7 @@ public function getRegistration(): string } if ($this->type === "class" || $this->type === "trait") { - $code .= "\tclass_entry = zend_register_internal_class_ex(&ce, " . (isset($this->extends[0]) ? "class_entry_" . str_replace("\\", "_", $this->extends[0]) : "NULL") . ");\n"; + $code .= "\tclass_entry = zend_register_internal_class_ex(&ce, " . (isset($this->extends[0]) ? "class_entry_" . str_replace("\\", "_", $this->extends[0]->toString()) : "NULL") . ");\n"; } else { $code .= "\tclass_entry = zend_register_internal_interface(&ce);\n"; } @@ -1354,8 +1305,6 @@ class FileInfo { public $generateLegacyArginfo = false; /** @var bool */ public $generateClassEntries = false; - /** @var bool */ - public $generateLegacyClassEntries = false; /** * @return iterable @@ -1593,18 +1542,12 @@ function parseProperty( ?Node $type, ?DocComment $comment ): PropertyInfo { - $isDeprecated = false; - $isKnownName = false; $docType = false; if ($comment) { $tags = parseDocComment($comment); foreach ($tags as $tag) { - if ($tag->name === 'deprecated') { - $isDeprecated = true; - } else if ($tag->name === 'known') { - $isKnownName = true; - } else if ($tag->name === 'var') { + if ($tag->name === 'var') { $docType = true; } } @@ -1627,10 +1570,8 @@ function parseProperty( } return new PropertyInfo( - new PropertyName($class->__toString(), $property->name->__toString()), + new PropertyName($class, $property->name->__toString()), $flags, - $isKnownName, - $isDeprecated, $propertyType, $property->default ); diff --git a/ext/curl/curl_file_arginfo.h b/ext/curl/curl_file_arginfo.h index b4e45907045de..47be45ac95b2b 100644 --- a/ext/curl/curl_file_arginfo.h +++ b/ext/curl/curl_file_arginfo.h @@ -48,11 +48,23 @@ zend_class_entry *register_class_CURLFile() INIT_CLASS_ENTRY(ce, "CURLFile", class_CURLFile_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); - zend_declare_property_string(class_entry, "name", sizeof("name") - 1, "", ZEND_ACC_PUBLIC); - - zend_declare_property_string(class_entry, "mime", sizeof("mime") - 1, "", ZEND_ACC_PUBLIC); - - zend_declare_property_string(class_entry, "postname", sizeof("postname") - 1, "", ZEND_ACC_PUBLIC); + zval property_name_default_value; + ZVAL_EMPTY_STRING(&property_name_default_value); + zend_string *property_name_name = zend_string_init("name", sizeof("name") - 1, 1); + zend_declare_property_ex(class_entry, property_name_name, &property_name_default_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(property_name_name); + + zval property_mime_default_value; + ZVAL_EMPTY_STRING(&property_mime_default_value); + zend_string *property_mime_name = zend_string_init("mime", sizeof("mime") - 1, 1); + zend_declare_property_ex(class_entry, property_mime_name, &property_mime_default_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(property_mime_name); + + zval property_postname_default_value; + ZVAL_EMPTY_STRING(&property_postname_default_value); + zend_string *property_postname_name = zend_string_init("postname", sizeof("postname") - 1, 1); + zend_declare_property_ex(class_entry, property_postname_name, &property_postname_default_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(property_postname_name); return class_entry; } diff --git a/ext/intl/transliterator/transliterator_arginfo.h b/ext/intl/transliterator/transliterator_arginfo.h index a024ee78567d9..a2f0660c9799f 100644 --- a/ext/intl/transliterator/transliterator_arginfo.h +++ b/ext/intl/transliterator/transliterator_arginfo.h @@ -58,7 +58,11 @@ zend_class_entry *register_class_Transliterator() INIT_CLASS_ENTRY(ce, "Transliterator", class_Transliterator_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); - zend_declare_property_null(class_entry, "id", sizeof("id") - 1, ZEND_ACC_PUBLIC); + zval property_id_default_value; + ZVAL_NULL(&property_id_default_value); + zend_string *property_id_name = zend_string_init("id", sizeof("id") - 1, 1); + zend_declare_property_ex(class_entry, property_id_name, &property_id_default_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(property_id_name); return class_entry; } diff --git a/ext/libxml/libxml.stub.php b/ext/libxml/libxml.stub.php index fd6d130b44128..b20d681b96358 100644 --- a/ext/libxml/libxml.stub.php +++ b/ext/libxml/libxml.stub.php @@ -8,14 +8,10 @@ class LibXMLError { public int $level; - /** @known */ public int $code; public int $column; - /** @known */ public string $message; - /** @known */ public string $file; - /** @known */ public int $line; } diff --git a/ext/libxml/libxml_arginfo.h b/ext/libxml/libxml_arginfo.h index ed0dcb5eefc12..a10639b6190d6 100644 --- a/ext/libxml/libxml_arginfo.h +++ b/ext/libxml/libxml_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: ee0d55cbc9691d182bd796ec135ccb28f9be5303 */ + * Stub hash: 2de903a36e16ddd4ff7ca0ff5be0c2be4697bd7e */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_libxml_set_streams_context, 0, 1, IS_VOID, 0) ZEND_ARG_INFO(0, context) @@ -67,7 +67,9 @@ zend_class_entry *register_class_LibXMLError() zval property_code_default_value; ZVAL_UNDEF(&property_code_default_value); - zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_CODE), &property_code_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string *property_code_name = zend_string_init("code", sizeof("code") - 1, 1); + zend_declare_typed_property(class_entry, property_code_name, &property_code_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(property_code_name); zval property_column_default_value; ZVAL_UNDEF(&property_column_default_value); @@ -77,15 +79,21 @@ zend_class_entry *register_class_LibXMLError() zval property_message_default_value; ZVAL_UNDEF(&property_message_default_value); - zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_MESSAGE), &property_message_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_string *property_message_name = zend_string_init("message", sizeof("message") - 1, 1); + zend_declare_typed_property(class_entry, property_message_name, &property_message_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_string_release(property_message_name); zval property_file_default_value; ZVAL_UNDEF(&property_file_default_value); - zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_FILE), &property_file_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_string *property_file_name = zend_string_init("file", sizeof("file") - 1, 1); + zend_declare_typed_property(class_entry, property_file_name, &property_file_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_string_release(property_file_name); zval property_line_default_value; ZVAL_UNDEF(&property_line_default_value); - zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_LINE), &property_line_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string *property_line_name = zend_string_init("line", sizeof("line") - 1, 1); + zend_declare_typed_property(class_entry, property_line_name, &property_line_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(property_line_name); return class_entry; } diff --git a/ext/pdo/pdo_stmt_arginfo.h b/ext/pdo/pdo_stmt_arginfo.h index fcc24ac20ab76..ebfb0c7156c47 100644 --- a/ext/pdo/pdo_stmt_arginfo.h +++ b/ext/pdo/pdo_stmt_arginfo.h @@ -143,7 +143,11 @@ zend_class_entry *register_class_PDOStatement(zend_class_entry *class_entry_Iter class_entry = zend_register_internal_class_ex(&ce, NULL); zend_class_implements(class_entry, 1, class_entry_IteratorAggregate); - zend_declare_property_null(class_entry, "queryString", sizeof("queryString") - 1, ZEND_ACC_PUBLIC); + zval property_queryString_default_value; + ZVAL_NULL(&property_queryString_default_value); + zend_string *property_queryString_name = zend_string_init("queryString", sizeof("queryString") - 1, 1); + zend_declare_property_ex(class_entry, property_queryString_name, &property_queryString_default_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(property_queryString_name); return class_entry; } diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index d6140b0ff907e..1b9ba4ce5956e 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -349,7 +349,7 @@ PHP_MINIT_FUNCTION(zend_test) zend_test_interface = register_class__ZendTestInterface(); zend_declare_class_constant_long(zend_test_interface, ZEND_STRL("DUMMY"), 0); - zend_test_class = register_class__ZendTestClass(zend_test_interface, zend_standard_class_def); + zend_test_class = register_class__ZendTestClass(zend_test_interface); zend_test_class->create_object = zend_test_class_new; zend_test_class->get_static_method = zend_test_class_static_method_get; diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index c27766cadd4fa..ec8d6e7795914 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -157,7 +157,7 @@ zend_class_entry *register_class__ZendTestInterface() return class_entry; } -zend_class_entry *register_class__ZendTestClass(zend_class_entry *class_entry__ZendTestInterface, zend_class_entry *class_entry_stdClass) +zend_class_entry *register_class__ZendTestClass(zend_class_entry *class_entry__ZendTestInterface) { zend_class_entry ce, *class_entry; @@ -166,7 +166,11 @@ zend_class_entry *register_class__ZendTestClass(zend_class_entry *class_entry__Z zend_class_implements(class_entry, 1, class_entry__ZendTestInterface); zend_register_class_alias("_ZendTestClassAlias", class_entry); - zend_declare_property_null(class_entry, "_StaticProp", sizeof("_StaticProp") - 1, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC); + zval property__StaticProp_default_value; + ZVAL_NULL(&property__StaticProp_default_value); + zend_string *property__StaticProp_name = zend_string_init("_StaticProp", sizeof("_StaticProp") - 1, 1); + zend_declare_property_ex(class_entry, property__StaticProp_name, &property__StaticProp_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC, NULL); + zend_string_release(property__StaticProp_name); zval property_staticIntProp_default_value; ZVAL_LONG(&property_staticIntProp_default_value, 123); @@ -180,10 +184,11 @@ zend_class_entry *register_class__ZendTestClass(zend_class_entry *class_entry__Z zend_declare_typed_property(class_entry, property_intProp_name, &property_intProp_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(property_intProp_name); + zend_string *property_classProp_class_stdClass = zend_string_init("stdClass", sizeof("stdClass"), 1); zval property_classProp_default_value; ZVAL_NULL(&property_classProp_default_value); zend_string *property_classProp_name = zend_string_init("classProp", sizeof("classProp") - 1, 1); - zend_declare_typed_property(class_entry, property_classProp_name, &property_classProp_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CE(class_entry_stdClass, 1, 0)); + zend_declare_typed_property(class_entry, property_classProp_name, &property_classProp_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_classProp_class_stdClass, 1, 0)); zend_string_release(property_classProp_name); return class_entry; @@ -207,7 +212,11 @@ zend_class_entry *register_class__ZendTestTrait() class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_TRAIT; - zend_declare_property_null(class_entry, "testProp", sizeof("testProp") - 1, ZEND_ACC_PUBLIC); + zval property_testProp_default_value; + ZVAL_NULL(&property_testProp_default_value); + zend_string *property_testProp_name = zend_string_init("testProp", sizeof("testProp") - 1, 1); + zend_declare_property_ex(class_entry, property_testProp_name, &property_testProp_default_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(property_testProp_name); return class_entry; } From 240b4b761525e8176ce17b60f60b362fac52e5df Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 26 Jan 2021 10:30:16 +0100 Subject: [PATCH 9/9] Fix zend_string length --- Zend/zend_exceptions_arginfo.h | 4 ++-- build/gen_stub.php | 2 +- ext/zend_test/test_arginfo.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Zend/zend_exceptions_arginfo.h b/Zend/zend_exceptions_arginfo.h index 748927fd92964..04e3ec753b4c7 100644 --- a/Zend/zend_exceptions_arginfo.h +++ b/Zend/zend_exceptions_arginfo.h @@ -241,7 +241,7 @@ zend_class_entry *register_class_Exception(zend_class_entry *class_entry_Throwab zend_declare_typed_property(class_entry, property_trace_name, &property_trace_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); zend_string_release(property_trace_name); - zend_string *property_previous_class_Throwable = zend_string_init("Throwable", sizeof("Throwable"), 1); + zend_string *property_previous_class_Throwable = zend_string_init("Throwable", sizeof("Throwable")-1, 1); zval property_previous_default_value; ZVAL_NULL(&property_previous_default_value); zend_string *property_previous_name = zend_string_init("previous", sizeof("previous") - 1, 1); @@ -305,7 +305,7 @@ zend_class_entry *register_class_Error(zend_class_entry *class_entry_Throwable) zend_declare_typed_property(class_entry, property_trace_name, &property_trace_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); zend_string_release(property_trace_name); - zend_string *property_previous_class_Throwable = zend_string_init("Throwable", sizeof("Throwable"), 1); + zend_string *property_previous_class_Throwable = zend_string_init("Throwable", sizeof("Throwable")-1, 1); zval property_previous_default_value; ZVAL_NULL(&property_previous_default_value); zend_string *property_previous_name = zend_string_init("previous", sizeof("previous") - 1, 1); diff --git a/build/gen_stub.php b/build/gen_stub.php index 3fac13787c87f..8653b6f3c5662 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -1049,7 +1049,7 @@ function (Expr $expr) use (&$defaultValueConstant) { $simpleType = $this->type->tryToSimpleType(); $className = $arginfoType->classTypes[0]->name; - $code .= " zend_string *property_{$propertyName}_class_{$className} = zend_string_init(\"$className\", sizeof(\"$className\"), 1);\n"; + $code .= " zend_string *property_{$propertyName}_class_{$className} = zend_string_init(\"$className\", sizeof(\"$className\")-1, 1);\n"; if ($simpleType) { $typeCode = "(zend_type) ZEND_TYPE_INIT_CLASS(property_{$propertyName}_class_{$className}, " . ((int) $this->type->isNullable()) . ", 0)"; } elseif (count($arginfoType->classTypes) === 1) { diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index ec8d6e7795914..8b0754dd247a1 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -184,7 +184,7 @@ zend_class_entry *register_class__ZendTestClass(zend_class_entry *class_entry__Z zend_declare_typed_property(class_entry, property_intProp_name, &property_intProp_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(property_intProp_name); - zend_string *property_classProp_class_stdClass = zend_string_init("stdClass", sizeof("stdClass"), 1); + zend_string *property_classProp_class_stdClass = zend_string_init("stdClass", sizeof("stdClass")-1, 1); zval property_classProp_default_value; ZVAL_NULL(&property_classProp_default_value); zend_string *property_classProp_name = zend_string_init("classProp", sizeof("classProp") - 1, 1);