mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
Allow for arbitrary (class) attributes in stubs
This can be easily extended to other types of attributes. Closes #8839.
This commit is contained in:
parent
82bcc94bea
commit
9f29e2d7e9
10 changed files with 282 additions and 57 deletions
|
@ -317,28 +317,40 @@ static void free_internal_attribute(zval *v)
|
|||
pefree(Z_PTR_P(v), 1);
|
||||
}
|
||||
|
||||
ZEND_API zend_internal_attribute *zend_internal_attribute_register(zend_class_entry *ce, uint32_t flags)
|
||||
ZEND_API zend_internal_attribute *zend_mark_internal_attribute(zend_class_entry *ce)
|
||||
{
|
||||
zend_internal_attribute *internal_attr;
|
||||
zend_attribute *attr;
|
||||
|
||||
if (ce->type != ZEND_INTERNAL_CLASS) {
|
||||
zend_error_noreturn(E_ERROR, "Only internal classes can be registered as compiler attribute");
|
||||
}
|
||||
|
||||
ZEND_HASH_FOREACH_PTR(ce->attributes, attr) {
|
||||
if (zend_string_equals(attr->name, zend_ce_attribute->name)) {
|
||||
internal_attr = pemalloc(sizeof(zend_internal_attribute), 1);
|
||||
internal_attr->ce = ce;
|
||||
internal_attr->flags = flags;
|
||||
internal_attr->flags = Z_LVAL(attr->args[0].value);
|
||||
internal_attr->validator = NULL;
|
||||
|
||||
zend_string *lcname = zend_string_tolower_ex(ce->name, 1);
|
||||
|
||||
zend_hash_update_ptr(&internal_attributes, lcname, internal_attr);
|
||||
zend_attribute *attr = zend_add_class_attribute(ce, zend_ce_attribute->name, 1);
|
||||
ZVAL_LONG(&attr->args[0].value, flags);
|
||||
zend_string_release(lcname);
|
||||
|
||||
return internal_attr;
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
zend_error_noreturn(E_ERROR, "Classes must be first marked as attribute before being able to be registered as internal attribute class");
|
||||
}
|
||||
|
||||
ZEND_API zend_internal_attribute *zend_internal_attribute_register(zend_class_entry *ce, uint32_t flags)
|
||||
{
|
||||
zend_attribute *attr = zend_add_class_attribute(ce, zend_ce_attribute->name, 1);
|
||||
ZVAL_LONG(&attr->args[0].value, flags);
|
||||
|
||||
return zend_mark_internal_attribute(ce);
|
||||
}
|
||||
|
||||
ZEND_API zend_internal_attribute *zend_internal_attribute_get(zend_string *lcname)
|
||||
{
|
||||
|
@ -352,32 +364,23 @@ void zend_register_attribute_ce(void)
|
|||
zend_hash_init(&internal_attributes, 8, NULL, free_internal_attribute, 1);
|
||||
|
||||
zend_ce_attribute = register_class_Attribute();
|
||||
attr = zend_internal_attribute_register(zend_ce_attribute, ZEND_ATTRIBUTE_TARGET_CLASS);
|
||||
attr = zend_mark_internal_attribute(zend_ce_attribute);
|
||||
attr->validator = validate_attribute;
|
||||
|
||||
zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_CLASS"), ZEND_ATTRIBUTE_TARGET_CLASS);
|
||||
zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_FUNCTION"), ZEND_ATTRIBUTE_TARGET_FUNCTION);
|
||||
zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_METHOD"), ZEND_ATTRIBUTE_TARGET_METHOD);
|
||||
zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_PROPERTY"), ZEND_ATTRIBUTE_TARGET_PROPERTY);
|
||||
zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_CLASS_CONSTANT"), ZEND_ATTRIBUTE_TARGET_CLASS_CONST);
|
||||
zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_PARAMETER"), ZEND_ATTRIBUTE_TARGET_PARAMETER);
|
||||
zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_ALL"), ZEND_ATTRIBUTE_TARGET_ALL);
|
||||
zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("IS_REPEATABLE"), ZEND_ATTRIBUTE_IS_REPEATABLE);
|
||||
|
||||
zend_ce_return_type_will_change_attribute = register_class_ReturnTypeWillChange();
|
||||
zend_internal_attribute_register(zend_ce_return_type_will_change_attribute, ZEND_ATTRIBUTE_TARGET_METHOD);
|
||||
zend_mark_internal_attribute(zend_ce_return_type_will_change_attribute);
|
||||
|
||||
zend_ce_allow_dynamic_properties = register_class_AllowDynamicProperties();
|
||||
attr = zend_internal_attribute_register(zend_ce_allow_dynamic_properties, ZEND_ATTRIBUTE_TARGET_CLASS);
|
||||
attr = zend_mark_internal_attribute(zend_ce_allow_dynamic_properties);
|
||||
attr->validator = validate_allow_dynamic_properties;
|
||||
|
||||
zend_ce_sensitive_parameter = register_class_SensitiveParameter();
|
||||
attr = zend_internal_attribute_register(zend_ce_sensitive_parameter, ZEND_ATTRIBUTE_TARGET_PARAMETER);
|
||||
zend_mark_internal_attribute(zend_ce_sensitive_parameter);
|
||||
|
||||
memcpy(&attributes_object_handlers_sensitive_parameter_value, &std_object_handlers, sizeof(zend_object_handlers));
|
||||
attributes_object_handlers_sensitive_parameter_value.get_properties_for = attributes_sensitive_parameter_value_get_properties_for;
|
||||
|
||||
/* This is not an actual attribute, thus the zend_internal_attribute_register() call is missing. */
|
||||
/* This is not an actual attribute, thus the zend_mark_internal_attribute() call is missing. */
|
||||
zend_ce_sensitive_parameter_value = register_class_SensitiveParameterValue();
|
||||
zend_ce_sensitive_parameter_value->create_object = attributes_sensitive_parameter_value_new;
|
||||
}
|
||||
|
|
|
@ -77,6 +77,7 @@ ZEND_API zend_result zend_get_attribute_value(zval *ret, zend_attribute *attr, u
|
|||
ZEND_API zend_string *zend_get_attribute_target_names(uint32_t targets);
|
||||
ZEND_API bool zend_is_attribute_repeated(HashTable *attributes, zend_attribute *attr);
|
||||
|
||||
ZEND_API zend_internal_attribute *zend_mark_internal_attribute(zend_class_entry *ce);
|
||||
ZEND_API zend_internal_attribute *zend_internal_attribute_register(zend_class_entry *ce, uint32_t flags);
|
||||
ZEND_API zend_internal_attribute *zend_internal_attribute_get(zend_string *lcname);
|
||||
|
||||
|
|
|
@ -2,18 +2,62 @@
|
|||
|
||||
/** @generate-class-entries */
|
||||
|
||||
#[Attribute(Attribute::TARGET_CLASS)]
|
||||
final class Attribute
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
* @cname ZEND_ATTRIBUTE_TARGET_CLASS
|
||||
*/
|
||||
const TARGET_CLASS = UNKNOWN;
|
||||
/**
|
||||
* @var int
|
||||
* @cname ZEND_ATTRIBUTE_TARGET_FUNCTION
|
||||
*/
|
||||
const TARGET_FUNCTION = UNKNOWN;
|
||||
/**
|
||||
* @var int
|
||||
* @cname ZEND_ATTRIBUTE_TARGET_METHOD
|
||||
*/
|
||||
const TARGET_METHOD = UNKNOWN;
|
||||
/**
|
||||
* @var int
|
||||
* @cname ZEND_ATTRIBUTE_TARGET_PROPERTY
|
||||
*/
|
||||
const TARGET_PROPERTY = UNKNOWN;
|
||||
/**
|
||||
* @var int
|
||||
* @cname ZEND_ATTRIBUTE_TARGET_CLASS_CONST
|
||||
*/
|
||||
const TARGET_CLASS_CONSTANT = UNKNOWN;
|
||||
/**
|
||||
* @var int
|
||||
* @cname ZEND_ATTRIBUTE_TARGET_PARAMETER
|
||||
*/
|
||||
const TARGET_PARAMETER = UNKNOWN;
|
||||
/**
|
||||
* @var int
|
||||
* @cname ZEND_ATTRIBUTE_TARGET_ALL
|
||||
*/
|
||||
const TARGET_ALL = UNKNOWN;
|
||||
/**
|
||||
* @var int
|
||||
* @cname ZEND_ATTRIBUTE_IS_REPEATABLE
|
||||
*/
|
||||
const IS_REPEATABLE = UNKNOWN;
|
||||
|
||||
public int $flags;
|
||||
|
||||
public function __construct(int $flags = Attribute::TARGET_ALL) {}
|
||||
}
|
||||
|
||||
#[Attribute(Attribute::TARGET_METHOD)]
|
||||
final class ReturnTypeWillChange
|
||||
{
|
||||
public function __construct() {}
|
||||
}
|
||||
|
||||
#[Attribute(Attribute::TARGET_CLASS)]
|
||||
final class AllowDynamicProperties
|
||||
{
|
||||
public function __construct() {}
|
||||
|
@ -22,6 +66,7 @@ final class AllowDynamicProperties
|
|||
/**
|
||||
* @strict-properties
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_PARAMETER)]
|
||||
final class SensitiveParameter
|
||||
{
|
||||
public function __construct() {}
|
||||
|
|
78
Zend/zend_attributes_arginfo.h
generated
78
Zend/zend_attributes_arginfo.h
generated
|
@ -1,5 +1,5 @@
|
|||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 5d9a092c1f0da5f32d9a161cc5166ed794ffe8e9 */
|
||||
* Stub hash: a07e5020fd36cda191c1f3b4fca180157bd74cbc */
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Attribute___construct, 0, 0, 0)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "Attribute::TARGET_ALL")
|
||||
|
@ -71,12 +71,67 @@ static zend_class_entry *register_class_Attribute(void)
|
|||
class_entry = zend_register_internal_class_ex(&ce, NULL);
|
||||
class_entry->ce_flags |= ZEND_ACC_FINAL;
|
||||
|
||||
zval const_TARGET_CLASS_value;
|
||||
ZVAL_LONG(&const_TARGET_CLASS_value, ZEND_ATTRIBUTE_TARGET_CLASS);
|
||||
zend_string *const_TARGET_CLASS_name = zend_string_init_interned("TARGET_CLASS", sizeof("TARGET_CLASS") - 1, 1);
|
||||
zend_declare_class_constant_ex(class_entry, const_TARGET_CLASS_name, &const_TARGET_CLASS_value, ZEND_ACC_PUBLIC, NULL);
|
||||
zend_string_release(const_TARGET_CLASS_name);
|
||||
|
||||
zval const_TARGET_FUNCTION_value;
|
||||
ZVAL_LONG(&const_TARGET_FUNCTION_value, ZEND_ATTRIBUTE_TARGET_FUNCTION);
|
||||
zend_string *const_TARGET_FUNCTION_name = zend_string_init_interned("TARGET_FUNCTION", sizeof("TARGET_FUNCTION") - 1, 1);
|
||||
zend_declare_class_constant_ex(class_entry, const_TARGET_FUNCTION_name, &const_TARGET_FUNCTION_value, ZEND_ACC_PUBLIC, NULL);
|
||||
zend_string_release(const_TARGET_FUNCTION_name);
|
||||
|
||||
zval const_TARGET_METHOD_value;
|
||||
ZVAL_LONG(&const_TARGET_METHOD_value, ZEND_ATTRIBUTE_TARGET_METHOD);
|
||||
zend_string *const_TARGET_METHOD_name = zend_string_init_interned("TARGET_METHOD", sizeof("TARGET_METHOD") - 1, 1);
|
||||
zend_declare_class_constant_ex(class_entry, const_TARGET_METHOD_name, &const_TARGET_METHOD_value, ZEND_ACC_PUBLIC, NULL);
|
||||
zend_string_release(const_TARGET_METHOD_name);
|
||||
|
||||
zval const_TARGET_PROPERTY_value;
|
||||
ZVAL_LONG(&const_TARGET_PROPERTY_value, ZEND_ATTRIBUTE_TARGET_PROPERTY);
|
||||
zend_string *const_TARGET_PROPERTY_name = zend_string_init_interned("TARGET_PROPERTY", sizeof("TARGET_PROPERTY") - 1, 1);
|
||||
zend_declare_class_constant_ex(class_entry, const_TARGET_PROPERTY_name, &const_TARGET_PROPERTY_value, ZEND_ACC_PUBLIC, NULL);
|
||||
zend_string_release(const_TARGET_PROPERTY_name);
|
||||
|
||||
zval const_TARGET_CLASS_CONSTANT_value;
|
||||
ZVAL_LONG(&const_TARGET_CLASS_CONSTANT_value, ZEND_ATTRIBUTE_TARGET_CLASS_CONST);
|
||||
zend_string *const_TARGET_CLASS_CONSTANT_name = zend_string_init_interned("TARGET_CLASS_CONSTANT", sizeof("TARGET_CLASS_CONSTANT") - 1, 1);
|
||||
zend_declare_class_constant_ex(class_entry, const_TARGET_CLASS_CONSTANT_name, &const_TARGET_CLASS_CONSTANT_value, ZEND_ACC_PUBLIC, NULL);
|
||||
zend_string_release(const_TARGET_CLASS_CONSTANT_name);
|
||||
|
||||
zval const_TARGET_PARAMETER_value;
|
||||
ZVAL_LONG(&const_TARGET_PARAMETER_value, ZEND_ATTRIBUTE_TARGET_PARAMETER);
|
||||
zend_string *const_TARGET_PARAMETER_name = zend_string_init_interned("TARGET_PARAMETER", sizeof("TARGET_PARAMETER") - 1, 1);
|
||||
zend_declare_class_constant_ex(class_entry, const_TARGET_PARAMETER_name, &const_TARGET_PARAMETER_value, ZEND_ACC_PUBLIC, NULL);
|
||||
zend_string_release(const_TARGET_PARAMETER_name);
|
||||
|
||||
zval const_TARGET_ALL_value;
|
||||
ZVAL_LONG(&const_TARGET_ALL_value, ZEND_ATTRIBUTE_TARGET_ALL);
|
||||
zend_string *const_TARGET_ALL_name = zend_string_init_interned("TARGET_ALL", sizeof("TARGET_ALL") - 1, 1);
|
||||
zend_declare_class_constant_ex(class_entry, const_TARGET_ALL_name, &const_TARGET_ALL_value, ZEND_ACC_PUBLIC, NULL);
|
||||
zend_string_release(const_TARGET_ALL_name);
|
||||
|
||||
zval const_IS_REPEATABLE_value;
|
||||
ZVAL_LONG(&const_IS_REPEATABLE_value, ZEND_ATTRIBUTE_IS_REPEATABLE);
|
||||
zend_string *const_IS_REPEATABLE_name = zend_string_init_interned("IS_REPEATABLE", sizeof("IS_REPEATABLE") - 1, 1);
|
||||
zend_declare_class_constant_ex(class_entry, const_IS_REPEATABLE_name, &const_IS_REPEATABLE_value, ZEND_ACC_PUBLIC, NULL);
|
||||
zend_string_release(const_IS_REPEATABLE_name);
|
||||
|
||||
zval property_flags_default_value;
|
||||
ZVAL_UNDEF(&property_flags_default_value);
|
||||
zend_string *property_flags_name = zend_string_init("flags", sizeof("flags") - 1, 1);
|
||||
zend_declare_typed_property(class_entry, property_flags_name, &property_flags_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
|
||||
zend_string_release(property_flags_name);
|
||||
|
||||
zend_string *attribute_name_Attribute_class_Attribute = zend_string_init("Attribute", sizeof("Attribute") - 1, 1);
|
||||
zend_attribute *attribute_Attribute_class_Attribute = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_Attribute, 1);
|
||||
zend_string_release(attribute_name_Attribute_class_Attribute);
|
||||
zval attribute_Attribute_class_Attribute_arg0;
|
||||
ZVAL_LONG(&attribute_Attribute_class_Attribute_arg0, ZEND_ATTRIBUTE_TARGET_CLASS);
|
||||
ZVAL_COPY_VALUE(&attribute_Attribute_class_Attribute->args[0].value, &attribute_Attribute_class_Attribute_arg0);
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
|
||||
|
@ -88,6 +143,13 @@ static zend_class_entry *register_class_ReturnTypeWillChange(void)
|
|||
class_entry = zend_register_internal_class_ex(&ce, NULL);
|
||||
class_entry->ce_flags |= ZEND_ACC_FINAL;
|
||||
|
||||
zend_string *attribute_name_Attribute_class_ReturnTypeWillChange = zend_string_init("Attribute", sizeof("Attribute") - 1, 1);
|
||||
zend_attribute *attribute_Attribute_class_ReturnTypeWillChange = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_ReturnTypeWillChange, 1);
|
||||
zend_string_release(attribute_name_Attribute_class_ReturnTypeWillChange);
|
||||
zval attribute_Attribute_class_ReturnTypeWillChange_arg0;
|
||||
ZVAL_LONG(&attribute_Attribute_class_ReturnTypeWillChange_arg0, ZEND_ATTRIBUTE_TARGET_METHOD);
|
||||
ZVAL_COPY_VALUE(&attribute_Attribute_class_ReturnTypeWillChange->args[0].value, &attribute_Attribute_class_ReturnTypeWillChange_arg0);
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
|
||||
|
@ -99,6 +161,13 @@ static zend_class_entry *register_class_AllowDynamicProperties(void)
|
|||
class_entry = zend_register_internal_class_ex(&ce, NULL);
|
||||
class_entry->ce_flags |= ZEND_ACC_FINAL;
|
||||
|
||||
zend_string *attribute_name_Attribute_class_AllowDynamicProperties = zend_string_init("Attribute", sizeof("Attribute") - 1, 1);
|
||||
zend_attribute *attribute_Attribute_class_AllowDynamicProperties = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_AllowDynamicProperties, 1);
|
||||
zend_string_release(attribute_name_Attribute_class_AllowDynamicProperties);
|
||||
zval attribute_Attribute_class_AllowDynamicProperties_arg0;
|
||||
ZVAL_LONG(&attribute_Attribute_class_AllowDynamicProperties_arg0, ZEND_ATTRIBUTE_TARGET_CLASS);
|
||||
ZVAL_COPY_VALUE(&attribute_Attribute_class_AllowDynamicProperties->args[0].value, &attribute_Attribute_class_AllowDynamicProperties_arg0);
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
|
||||
|
@ -110,6 +179,13 @@ static zend_class_entry *register_class_SensitiveParameter(void)
|
|||
class_entry = zend_register_internal_class_ex(&ce, NULL);
|
||||
class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES;
|
||||
|
||||
zend_string *attribute_name_Attribute_class_SensitiveParameter = zend_string_init("Attribute", sizeof("Attribute") - 1, 1);
|
||||
zend_attribute *attribute_Attribute_class_SensitiveParameter = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_SensitiveParameter, 1);
|
||||
zend_string_release(attribute_name_Attribute_class_SensitiveParameter);
|
||||
zval attribute_Attribute_class_SensitiveParameter_arg0;
|
||||
ZVAL_LONG(&attribute_Attribute_class_SensitiveParameter_arg0, ZEND_ATTRIBUTE_TARGET_PARAMETER);
|
||||
ZVAL_COPY_VALUE(&attribute_Attribute_class_SensitiveParameter->args[0].value, &attribute_Attribute_class_SensitiveParameter_arg0);
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
|
||||
|
|
5
Zend/zend_builtin_functions_arginfo.h
generated
5
Zend/zend_builtin_functions_arginfo.h
generated
|
@ -354,7 +354,10 @@ static zend_class_entry *register_class_stdClass(void)
|
|||
INIT_CLASS_ENTRY(ce, "stdClass", class_stdClass_methods);
|
||||
class_entry = zend_register_internal_class_ex(&ce, NULL);
|
||||
class_entry->ce_flags |= ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES;
|
||||
zend_add_class_attribute(class_entry, zend_ce_allow_dynamic_properties->name, 0);
|
||||
|
||||
zend_string *attribute_name_AllowDynamicProperties_class_stdClass = zend_string_init("AllowDynamicProperties", sizeof("AllowDynamicProperties") - 1, 1);
|
||||
zend_add_class_attribute(class_entry, attribute_name_AllowDynamicProperties_class_stdClass, 0);
|
||||
zend_string_release(attribute_name_AllowDynamicProperties_class_stdClass);
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
|
|
|
@ -46,12 +46,13 @@ function processDirectory(string $dir, Context $context): array {
|
|||
return $fileInfos;
|
||||
}
|
||||
|
||||
function processStubFile(string $stubFile, Context $context): ?FileInfo {
|
||||
function processStubFile(string $stubFile, Context $context, bool $includeOnly = false): ?FileInfo {
|
||||
try {
|
||||
if (!file_exists($stubFile)) {
|
||||
throw new Exception("File $stubFile does not exist");
|
||||
}
|
||||
|
||||
if (!$includeOnly) {
|
||||
$stubFilenameWithoutExtension = str_replace(".stub.php", "", $stubFile);
|
||||
$arginfoFile = "{$stubFilenameWithoutExtension}_arginfo.h";
|
||||
$legacyFile = "{$stubFilenameWithoutExtension}_legacy_arginfo.h";
|
||||
|
@ -63,11 +64,36 @@ function processStubFile(string $stubFile, Context $context): ?FileInfo {
|
|||
/* Stub file did not change, do not regenerate. */
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$fileInfo = $context->parsedFiles[$stubFile] ?? null) {
|
||||
initPhpParser();
|
||||
$fileInfo = parseStubFile($stubCode);
|
||||
$fileInfo = parseStubFile($stubCode ?? file_get_contents($stubFile));
|
||||
$context->parsedFiles[$stubFile] = $fileInfo;
|
||||
|
||||
foreach ($fileInfo->dependencies as $dependency) {
|
||||
// TODO add header search path for extensions?
|
||||
$prefixes = [dirname($stubFile) . "/", dirname(__DIR__) . "/"];
|
||||
foreach ($prefixes as $prefix) {
|
||||
$depFile = $prefix . $dependency;
|
||||
if (file_exists($depFile)) {
|
||||
break;
|
||||
}
|
||||
$depFile = null;
|
||||
}
|
||||
if (!$depFile) {
|
||||
throw new Exception("File $stubFile includes a file $dependency which does not exist");
|
||||
}
|
||||
processStubFile($depFile, $context, true);
|
||||
}
|
||||
|
||||
$constInfos = $fileInfo->getAllConstInfos();
|
||||
$context->allConstInfos = array_merge($context->allConstInfos, $constInfos);
|
||||
}
|
||||
|
||||
if ($includeOnly) {
|
||||
return $fileInfo;
|
||||
}
|
||||
|
||||
$arginfoCode = generateArgInfoCode(
|
||||
basename($stubFilenameWithoutExtension),
|
||||
|
@ -131,6 +157,8 @@ class Context {
|
|||
public $forceRegeneration = false;
|
||||
/** @var iterable<ConstInfo> */
|
||||
public iterable $allConstInfos = [];
|
||||
/** @var FileInfo[] */
|
||||
public array $parsedFiles = [];
|
||||
}
|
||||
|
||||
class ArrayType extends SimpleType {
|
||||
|
@ -2257,6 +2285,38 @@ class EnumCaseInfo {
|
|||
}
|
||||
}
|
||||
|
||||
class AttributeInfo {
|
||||
/** @var string */
|
||||
public $class;
|
||||
/** @var \PhpParser\Node\Arg[] */
|
||||
public $args;
|
||||
|
||||
/** @param \PhpParser\Node\Arg[] $args */
|
||||
public function __construct(string $class, array $args) {
|
||||
$this->class = $class;
|
||||
$this->args = $args;
|
||||
}
|
||||
|
||||
/** @param iterable<ConstInfo> $allConstInfos */
|
||||
public function generateCode(string $invocation, string $nameSuffix, iterable $allConstInfos): string {
|
||||
$code = "\n";
|
||||
$escapedAttributeName = strtr($this->class, '\\', '_');
|
||||
$code .= "\tzend_string *attribute_name_{$escapedAttributeName}_$nameSuffix = zend_string_init(\"" . addcslashes($this->class, "\\") . "\", sizeof(\"" . addcslashes($this->class, "\\") . "\") - 1, 1);\n";
|
||||
$code .= "\t" . ($this->args ? "zend_attribute *attribute_{$escapedAttributeName}_$nameSuffix = " : "") . "$invocation, attribute_name_{$escapedAttributeName}_$nameSuffix, " . count($this->args) . ");\n";
|
||||
$code .= "\tzend_string_release(attribute_name_{$escapedAttributeName}_$nameSuffix);\n";
|
||||
foreach ($this->args as $i => $arg) {
|
||||
$value = EvaluatedValue::createFromExpression($arg->value, null, null, $allConstInfos);
|
||||
$zvalName = "attribute_{$escapedAttributeName}_{$nameSuffix}_arg$i";
|
||||
$code .= $value->initializeZval($zvalName, $allConstInfos);
|
||||
$code .= "\tZVAL_COPY_VALUE(&attribute_{$escapedAttributeName}_{$nameSuffix}->args[$i].value, &$zvalName);\n";
|
||||
if ($arg->name) {
|
||||
$code .= "\tattribute_{$escapedAttributeName}_{$nameSuffix}->args[$i].name = zend_string_init(\"{$arg->name->name}\", sizeof(\"{$arg->name->name}\") - 1, 1);\n";
|
||||
}
|
||||
}
|
||||
return $code;
|
||||
}
|
||||
}
|
||||
|
||||
class ClassInfo {
|
||||
/** @var Name */
|
||||
public $name;
|
||||
|
@ -2272,8 +2332,8 @@ class ClassInfo {
|
|||
public $isDeprecated;
|
||||
/** @var bool */
|
||||
public $isStrictProperties;
|
||||
/** @var bool */
|
||||
public $allowsDynamicProperties;
|
||||
/** @var AttributeInfo[] */
|
||||
public $attributes;
|
||||
/** @var bool */
|
||||
public $isNotSerializable;
|
||||
/** @var Name[] */
|
||||
|
@ -2292,6 +2352,7 @@ class ClassInfo {
|
|||
public $cond;
|
||||
|
||||
/**
|
||||
* @param AttributeInfo[] $attributes
|
||||
* @param Name[] $extends
|
||||
* @param Name[] $implements
|
||||
* @param ConstInfo[] $constInfos
|
||||
|
@ -2307,7 +2368,7 @@ class ClassInfo {
|
|||
?SimpleType $enumBackingType,
|
||||
bool $isDeprecated,
|
||||
bool $isStrictProperties,
|
||||
bool $allowsDynamicProperties,
|
||||
array $attributes,
|
||||
bool $isNotSerializable,
|
||||
array $extends,
|
||||
array $implements,
|
||||
|
@ -2324,7 +2385,7 @@ class ClassInfo {
|
|||
$this->enumBackingType = $enumBackingType;
|
||||
$this->isDeprecated = $isDeprecated;
|
||||
$this->isStrictProperties = $isStrictProperties;
|
||||
$this->allowsDynamicProperties = $allowsDynamicProperties;
|
||||
$this->attributes = $attributes;
|
||||
$this->isNotSerializable = $isNotSerializable;
|
||||
$this->extends = $extends;
|
||||
$this->implements = $implements;
|
||||
|
@ -2413,8 +2474,8 @@ class ClassInfo {
|
|||
$code .= $property->getDeclaration($allConstInfos);
|
||||
}
|
||||
|
||||
if ($this->allowsDynamicProperties) {
|
||||
$code .= "\tzend_add_class_attribute(class_entry, zend_ce_allow_dynamic_properties->name, 0);\n";
|
||||
foreach ($this->attributes as $attribute) {
|
||||
$code .= $attribute->generateCode("zend_add_class_attribute(class_entry", "class_$escapedName", $allConstInfos);
|
||||
}
|
||||
|
||||
if ($attributeInitializationCode = generateAttributeInitialization($this->funcInfos, $this->cond)) {
|
||||
|
@ -2460,9 +2521,11 @@ class ClassInfo {
|
|||
$flags[] = "ZEND_ACC_NO_DYNAMIC_PROPERTIES";
|
||||
}
|
||||
|
||||
if ($this->allowsDynamicProperties) {
|
||||
foreach ($this->attributes as $attr) {
|
||||
if ($attr->class === "AllowDynamicProperties") {
|
||||
$flags[] = "ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES";
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->isNotSerializable) {
|
||||
$flags[] = "ZEND_ACC_NOT_SERIALIZABLE";
|
||||
|
@ -2861,6 +2924,8 @@ class ClassInfo {
|
|||
}
|
||||
|
||||
class FileInfo {
|
||||
/** @var string[] */
|
||||
public $dependencies = [];
|
||||
/** @var ConstInfo[] */
|
||||
public $constInfos = [];
|
||||
/** @var FuncInfo[] */
|
||||
|
@ -3286,6 +3351,7 @@ function parseClass(
|
|||
$isStrictProperties = false;
|
||||
$isNotSerializable = false;
|
||||
$allowsDynamicProperties = false;
|
||||
$attributes = [];
|
||||
|
||||
if ($comment) {
|
||||
$tags = parseDocComment($comment);
|
||||
|
@ -3304,12 +3370,11 @@ function parseClass(
|
|||
|
||||
foreach ($class->attrGroups as $attrGroup) {
|
||||
foreach ($attrGroup->attrs as $attr) {
|
||||
switch ($attr->name->toCodeString()) {
|
||||
case '\\AllowDynamicProperties':
|
||||
$attributes[] = new AttributeInfo($attr->name->toString(), $attr->args);
|
||||
switch ($attr->name->toString()) {
|
||||
case 'AllowDynamicProperties':
|
||||
$allowsDynamicProperties = true;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Unhandled attribute {$attr->name->toCodeString()}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3348,7 +3413,7 @@ function parseClass(
|
|||
? SimpleType::fromNode($class->scalarType) : null,
|
||||
$isDeprecated,
|
||||
$isStrictProperties,
|
||||
$allowsDynamicProperties,
|
||||
$attributes,
|
||||
$isNotSerializable,
|
||||
$extends,
|
||||
$implements,
|
||||
|
@ -3511,6 +3576,14 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac
|
|||
continue;
|
||||
}
|
||||
|
||||
if ($stmt instanceof Stmt\Expression) {
|
||||
$expr = $stmt->expr;
|
||||
if ($expr instanceof Expr\Include_) {
|
||||
$fileInfo->dependencies[] = (string)EvaluatedValue::createFromExpression($expr->expr, null, null, [])->value;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception("Unexpected node {$stmt->getType()}");
|
||||
}
|
||||
}
|
||||
|
|
10
ext/oci8/oci8_arginfo.h
generated
10
ext/oci8/oci8_arginfo.h
generated
|
@ -816,7 +816,10 @@ static zend_class_entry *register_class_OCILob(void)
|
|||
INIT_CLASS_ENTRY(ce, "OCILob", class_OCILob_methods);
|
||||
class_entry = zend_register_internal_class_ex(&ce, NULL);
|
||||
class_entry->ce_flags |= ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES;
|
||||
zend_add_class_attribute(class_entry, zend_ce_allow_dynamic_properties->name, 0);
|
||||
|
||||
zend_string *attribute_name_AllowDynamicProperties_class_OCILob = zend_string_init("AllowDynamicProperties", sizeof("AllowDynamicProperties") - 1, 1);
|
||||
zend_add_class_attribute(class_entry, attribute_name_AllowDynamicProperties_class_OCILob, 0);
|
||||
zend_string_release(attribute_name_AllowDynamicProperties_class_OCILob);
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
|
@ -828,7 +831,10 @@ static zend_class_entry *register_class_OCICollection(void)
|
|||
INIT_CLASS_ENTRY(ce, "OCICollection", class_OCICollection_methods);
|
||||
class_entry = zend_register_internal_class_ex(&ce, NULL);
|
||||
class_entry->ce_flags |= ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES;
|
||||
zend_add_class_attribute(class_entry, zend_ce_allow_dynamic_properties->name, 0);
|
||||
|
||||
zend_string *attribute_name_AllowDynamicProperties_class_OCICollection = zend_string_init("AllowDynamicProperties", sizeof("AllowDynamicProperties") - 1, 1);
|
||||
zend_add_class_attribute(class_entry, attribute_name_AllowDynamicProperties_class_OCICollection, 0);
|
||||
zend_string_release(attribute_name_AllowDynamicProperties_class_OCICollection);
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
|
|
|
@ -634,12 +634,12 @@ PHP_MINIT_FUNCTION(zend_test)
|
|||
|
||||
zend_test_attribute = register_class_ZendTestAttribute();
|
||||
{
|
||||
zend_internal_attribute *attr = zend_internal_attribute_register(zend_test_attribute, ZEND_ATTRIBUTE_TARGET_ALL);
|
||||
zend_internal_attribute *attr = zend_mark_internal_attribute(zend_test_attribute);
|
||||
attr->validator = zend_attribute_validate_zendtestattribute;
|
||||
}
|
||||
|
||||
zend_test_parameter_attribute = register_class_ZendTestParameterAttribute();
|
||||
zend_internal_attribute_register(zend_test_parameter_attribute, ZEND_ATTRIBUTE_TARGET_PARAMETER);
|
||||
zend_mark_internal_attribute(zend_test_parameter_attribute);
|
||||
|
||||
{
|
||||
zend_attribute *attr;
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
namespace {
|
||||
|
||||
require "Zend/zend_attributes.stub.php";
|
||||
|
||||
interface _ZendTestInterface
|
||||
{
|
||||
}
|
||||
|
@ -41,10 +43,12 @@ namespace {
|
|||
public function testMethod(): bool {}
|
||||
}
|
||||
|
||||
#[Attribute(Attribute::TARGET_ALL)]
|
||||
final class ZendTestAttribute {
|
||||
|
||||
}
|
||||
|
||||
#[Attribute(Attribute::TARGET_PARAMETER)]
|
||||
final class ZendTestParameterAttribute {
|
||||
public string $parameter;
|
||||
|
||||
|
|
16
ext/zend_test/test_arginfo.h
generated
16
ext/zend_test/test_arginfo.h
generated
|
@ -1,5 +1,5 @@
|
|||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 1a23b7473e5b4525352445545c6b3ab374c4e949 */
|
||||
* Stub hash: 3ad8ef04d52f1a099d9fd3b6c2c02b90de2980be */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
@ -391,6 +391,13 @@ static zend_class_entry *register_class_ZendTestAttribute(void)
|
|||
class_entry = zend_register_internal_class_ex(&ce, NULL);
|
||||
class_entry->ce_flags |= ZEND_ACC_FINAL;
|
||||
|
||||
zend_string *attribute_name_Attribute_class_ZendTestAttribute = zend_string_init("Attribute", sizeof("Attribute") - 1, 1);
|
||||
zend_attribute *attribute_Attribute_class_ZendTestAttribute = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_ZendTestAttribute, 1);
|
||||
zend_string_release(attribute_name_Attribute_class_ZendTestAttribute);
|
||||
zval attribute_Attribute_class_ZendTestAttribute_arg0;
|
||||
ZVAL_LONG(&attribute_Attribute_class_ZendTestAttribute_arg0, ZEND_ATTRIBUTE_TARGET_ALL);
|
||||
ZVAL_COPY_VALUE(&attribute_Attribute_class_ZendTestAttribute->args[0].value, &attribute_Attribute_class_ZendTestAttribute_arg0);
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
|
||||
|
@ -408,6 +415,13 @@ static zend_class_entry *register_class_ZendTestParameterAttribute(void)
|
|||
zend_declare_typed_property(class_entry, property_parameter_name, &property_parameter_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
zend_string_release(property_parameter_name);
|
||||
|
||||
zend_string *attribute_name_Attribute_class_ZendTestParameterAttribute = zend_string_init("Attribute", sizeof("Attribute") - 1, 1);
|
||||
zend_attribute *attribute_Attribute_class_ZendTestParameterAttribute = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_ZendTestParameterAttribute, 1);
|
||||
zend_string_release(attribute_name_Attribute_class_ZendTestParameterAttribute);
|
||||
zval attribute_Attribute_class_ZendTestParameterAttribute_arg0;
|
||||
ZVAL_LONG(&attribute_Attribute_class_ZendTestParameterAttribute_arg0, ZEND_ATTRIBUTE_TARGET_PARAMETER);
|
||||
ZVAL_COPY_VALUE(&attribute_Attribute_class_ZendTestParameterAttribute->args[0].value, &attribute_Attribute_class_ZendTestParameterAttribute_arg0);
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue