mirror of
https://github.com/php/php-src.git
synced 2025-08-15 13:38:49 +02:00
gen_stub: Add support for attributes on constants in stubs (#18735)
Update to PHP-Parser 5.5.0 and add support for attributes on constants in stubs. For now, I have only migrated over E_STRICT, once the support is in place I'll do a larger migration of the existing deprecated constants. In the process, fix the logic in `copy_zend_constant()` for copying attributes when a constant is copied; just increase the reference count for the attributes table rather than trying to duplicate the contents.
This commit is contained in:
parent
99d56248f8
commit
8f3cdf6236
11 changed files with 143 additions and 16 deletions
|
@ -10,5 +10,5 @@ var_dump(E_STRICT);
|
|||
--EXPECTF--
|
||||
int(30719)
|
||||
|
||||
Deprecated: Constant E_STRICT is deprecated in %s on line %d
|
||||
Deprecated: Constant E_STRICT is deprecated since 8.4, the error level was removed in %s on line %d
|
||||
int(2048)
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#define ZEND_ATTRIBUTES_H
|
||||
|
||||
#include "zend_compile.h"
|
||||
#include "zend_constants.h"
|
||||
|
||||
#define ZEND_ATTRIBUTE_TARGET_CLASS (1<<0)
|
||||
#define ZEND_ATTRIBUTE_TARGET_FUNCTION (1<<1)
|
||||
|
@ -126,6 +127,12 @@ static zend_always_inline zend_attribute *zend_add_class_constant_attribute(zend
|
|||
return zend_add_attribute(&c->attributes, name, argc, flags, 0, 0);
|
||||
}
|
||||
|
||||
static zend_always_inline zend_attribute *zend_add_global_constant_attribute(zend_constant *c, zend_string *name, uint32_t argc)
|
||||
{
|
||||
uint32_t flags = ZEND_CONSTANT_MODULE_NUMBER(c) == PHP_USER_CONSTANT ? 0 : ZEND_ATTRIBUTE_PERSISTENT;
|
||||
return zend_add_attribute(&c->attributes, name, argc, flags, 0, 0);
|
||||
}
|
||||
|
||||
void zend_register_attribute_ce(void);
|
||||
void zend_attributes_shutdown(void);
|
||||
|
||||
|
|
|
@ -85,7 +85,8 @@ static void copy_zend_constant(zval *zv)
|
|||
c->filename = zend_string_copy(c->filename);
|
||||
}
|
||||
if (c->attributes != NULL) {
|
||||
c->attributes = zend_array_dup(c->attributes);
|
||||
// Use the same attributes table
|
||||
GC_ADDREF(c->attributes);
|
||||
}
|
||||
if (Z_TYPE(c->value) == IS_STRING) {
|
||||
Z_STR(c->value) = zend_string_dup(Z_STR(c->value), 1);
|
||||
|
|
|
@ -71,9 +71,9 @@ const E_USER_NOTICE = UNKNOWN;
|
|||
/**
|
||||
* @var int
|
||||
* @cvalue E_STRICT
|
||||
* @deprecated
|
||||
* @todo Remove in PHP 9.0
|
||||
*/
|
||||
#[\Deprecated(since: '8.4', message: 'the error level was removed')]
|
||||
const E_STRICT = UNKNOWN;
|
||||
|
||||
/**
|
||||
|
|
16
Zend/zend_constants_arginfo.h
generated
16
Zend/zend_constants_arginfo.h
generated
|
@ -1,5 +1,5 @@
|
|||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 65be08c1bdace83ad1fa1175fc824262e07eac2a */
|
||||
* Stub hash: 5e224893a5fb72b3f93249235c2a1634233ce505 */
|
||||
|
||||
static void register_zend_constants_symbols(int module_number)
|
||||
{
|
||||
|
@ -26,4 +26,18 @@ static void register_zend_constants_symbols(int module_number)
|
|||
REGISTER_BOOL_CONSTANT("TRUE", true, CONST_PERSISTENT);
|
||||
REGISTER_BOOL_CONSTANT("FALSE", false, CONST_PERSISTENT);
|
||||
REGISTER_NULL_CONSTANT("NULL", CONST_PERSISTENT);
|
||||
|
||||
zend_constant *const_E_STRICT = zend_hash_str_find_ptr(EG(zend_constants), "E_STRICT", sizeof("E_STRICT") - 1);
|
||||
|
||||
zend_attribute *attribute_Deprecated_const_E_STRICT_0 = zend_add_global_constant_attribute(const_E_STRICT, ZSTR_KNOWN(ZEND_STR_DEPRECATED_CAPITALIZED), 2);
|
||||
zval attribute_Deprecated_const_E_STRICT_0_arg0;
|
||||
zend_string *attribute_Deprecated_const_E_STRICT_0_arg0_str = zend_string_init("8.4", strlen("8.4"), 1);
|
||||
ZVAL_STR(&attribute_Deprecated_const_E_STRICT_0_arg0, attribute_Deprecated_const_E_STRICT_0_arg0_str);
|
||||
ZVAL_COPY_VALUE(&attribute_Deprecated_const_E_STRICT_0->args[0].value, &attribute_Deprecated_const_E_STRICT_0_arg0);
|
||||
attribute_Deprecated_const_E_STRICT_0->args[0].name = ZSTR_KNOWN(ZEND_STR_SINCE);
|
||||
zval attribute_Deprecated_const_E_STRICT_0_arg1;
|
||||
zend_string *attribute_Deprecated_const_E_STRICT_0_arg1_str = zend_string_init("the error level was removed", strlen("the error level was removed"), 1);
|
||||
ZVAL_STR(&attribute_Deprecated_const_E_STRICT_0_arg1, attribute_Deprecated_const_E_STRICT_0_arg1_str);
|
||||
ZVAL_COPY_VALUE(&attribute_Deprecated_const_E_STRICT_0->args[1].value, &attribute_Deprecated_const_E_STRICT_0_arg1);
|
||||
attribute_Deprecated_const_E_STRICT_0->args[1].name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
|
||||
}
|
||||
|
|
|
@ -2622,6 +2622,13 @@ class ConstInfo extends VariableLike
|
|||
?ExposedDocComment $exposedDocComment,
|
||||
bool $isFileCacheAllowed
|
||||
) {
|
||||
foreach ($attributes as $attr) {
|
||||
if ($attr->class === "Deprecated") {
|
||||
$isDeprecated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->name = $name;
|
||||
$this->value = $value;
|
||||
$this->valueString = $valueString;
|
||||
|
@ -2915,17 +2922,11 @@ class ConstInfo extends VariableLike
|
|||
{
|
||||
$flags = parent::getFlagsByPhpVersion();
|
||||
|
||||
// $this->isDeprecated also accounts for any #[\Deprecated] attributes
|
||||
if ($this->isDeprecated) {
|
||||
$flags = $this->addFlagForVersionsAbove($flags, "ZEND_ACC_DEPRECATED", PHP_80_VERSION_ID);
|
||||
}
|
||||
|
||||
foreach ($this->attributes as $attr) {
|
||||
if ($attr->class === "Deprecated") {
|
||||
$flags = $this->addFlagForVersionsAbove($flags, "ZEND_ACC_DEPRECATED", PHP_80_VERSION_ID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->flags & Modifiers::FINAL) {
|
||||
$flags = $this->addFlagForVersionsAbove($flags, "ZEND_ACC_FINAL", PHP_81_VERSION_ID);
|
||||
}
|
||||
|
@ -4340,7 +4341,7 @@ class FileInfo {
|
|||
$cond,
|
||||
$this->isUndocumentable,
|
||||
$this->getMinimumPhpVersionIdCompatibility(),
|
||||
[]
|
||||
AttributeInfo::createFromGroups($stmt->attrGroups)
|
||||
);
|
||||
}
|
||||
continue;
|
||||
|
@ -5177,7 +5178,9 @@ function generateArgInfoCode(
|
|||
$php80MinimumCompatibility = $fileInfo->getMinimumPhpVersionIdCompatibility() === null || $fileInfo->getMinimumPhpVersionIdCompatibility() >= PHP_80_VERSION_ID;
|
||||
|
||||
if ($fileInfo->generateClassEntries) {
|
||||
if ($attributeInitializationCode = generateFunctionAttributeInitialization($fileInfo->funcInfos, $allConstInfos, $fileInfo->getMinimumPhpVersionIdCompatibility(), null)) {
|
||||
$attributeInitializationCode = generateFunctionAttributeInitialization($fileInfo->funcInfos, $allConstInfos, $fileInfo->getMinimumPhpVersionIdCompatibility(), null);
|
||||
$attributeInitializationCode .= generateGlobalConstantAttributeInitialization($fileInfo->constInfos, $allConstInfos, $fileInfo->getMinimumPhpVersionIdCompatibility(), null);
|
||||
if ($attributeInitializationCode) {
|
||||
if (!$php80MinimumCompatibility) {
|
||||
$attributeInitializationCode = "\n#if (PHP_VERSION_ID >= " . PHP_80_VERSION_ID . ")" . $attributeInitializationCode . "#endif\n";
|
||||
}
|
||||
|
@ -5289,6 +5292,51 @@ function generateFunctionAttributeInitialization(iterable $funcInfos, array $all
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param iterable<ConstInfo> $constInfos
|
||||
* @param array<string, ConstInfo> $allConstInfos
|
||||
*/
|
||||
function generateGlobalConstantAttributeInitialization(
|
||||
iterable $constInfos,
|
||||
array $allConstInfos,
|
||||
?int $phpVersionIdMinimumCompatibility,
|
||||
?string $parentCond = null
|
||||
): string {
|
||||
$isConditional = false;
|
||||
if ($phpVersionIdMinimumCompatibility !== null && $phpVersionIdMinimumCompatibility < PHP_85_VERSION_ID) {
|
||||
$isConditional = true;
|
||||
$phpVersionIdMinimumCompatibility = PHP_85_VERSION_ID;
|
||||
}
|
||||
$code = generateCodeWithConditions(
|
||||
$constInfos,
|
||||
"",
|
||||
static function (ConstInfo $constInfo) use ($allConstInfos, $phpVersionIdMinimumCompatibility) {
|
||||
if ($constInfo->attributes === []) {
|
||||
return null;
|
||||
}
|
||||
$constName = str_replace('\\', '\\\\', $constInfo->name->__toString());
|
||||
$constVarName = 'const_' . $constName;
|
||||
|
||||
$code .= "\tzend_constant *$constVarName = zend_hash_str_find_ptr(EG(zend_constants), \"" . $constName . "\", sizeof(\"" . $constName . "\") - 1);\n";
|
||||
foreach ($constInfo->attributes as $key => $attribute) {
|
||||
$code .= $attribute->generateCode(
|
||||
"zend_add_global_constant_attribute($constVarName",
|
||||
$constVarName . "_$key",
|
||||
$allConstInfos,
|
||||
$phpVersionIdMinimumCompatibility
|
||||
);
|
||||
}
|
||||
|
||||
return $code;
|
||||
},
|
||||
$parentCond
|
||||
);
|
||||
if ($code && $isConditional) {
|
||||
return "\n#if (PHP_VERSION_ID >= " . PHP_85_VERSION_ID . ")\n" . $code . "#endif\n";
|
||||
}
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param iterable<ConstInfo> $constInfos
|
||||
* @param array<string, ConstInfo> $allConstInfos
|
||||
|
@ -6030,7 +6078,7 @@ function initPhpParser() {
|
|||
}
|
||||
|
||||
$isInitialized = true;
|
||||
$version = "5.3.1";
|
||||
$version = "5.5.0";
|
||||
$phpParserDir = __DIR__ . "/PHP-Parser-$version";
|
||||
if (!is_dir($phpParserDir)) {
|
||||
installPhpParser($version, $phpParserDir);
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
--TEST--
|
||||
ReflectionConstant::getAttributes() with attribute (internal constant)
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$reflectionConstant = new ReflectionConstant('E_STRICT');
|
||||
var_dump($reflectionConstant->getAttributes());
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
array(1) {
|
||||
[0]=>
|
||||
object(ReflectionAttribute)#%d (1) {
|
||||
["name"]=>
|
||||
string(10) "Deprecated"
|
||||
}
|
||||
}
|
|
@ -17,6 +17,12 @@ namespace {
|
|||
/** @var string */
|
||||
const ZEND_CONSTANT_A = "global";
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
#[\Deprecated(message: "use something else", since: "version 1.5")]
|
||||
const ZEND_TEST_ATTRIBUTED_CONSTANT = 42;
|
||||
|
||||
interface _ZendTestInterface
|
||||
{
|
||||
/** @var int */
|
||||
|
|
19
ext/zend_test/test_arginfo.h
generated
19
ext/zend_test/test_arginfo.h
generated
|
@ -1,5 +1,5 @@
|
|||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 1fd4c80ed74efcc50698748b2afc89391ed69c72 */
|
||||
* Stub hash: 37ac76dddea2da24d3275cccc748b8fea4c8d09c */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
@ -579,6 +579,7 @@ static void register_test_symbols(int module_number)
|
|||
{
|
||||
REGISTER_LONG_CONSTANT("ZEND_TEST_DEPRECATED", 42, CONST_PERSISTENT | CONST_DEPRECATED);
|
||||
REGISTER_STRING_CONSTANT("ZEND_CONSTANT_A", "global", CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("ZEND_TEST_ATTRIBUTED_CONSTANT", 42, CONST_PERSISTENT | CONST_DEPRECATED);
|
||||
REGISTER_STRING_CONSTANT("ZendTestNS2\\ZEND_CONSTANT_A", "namespaced", CONST_PERSISTENT);
|
||||
REGISTER_STRING_CONSTANT("ZendTestNS2\\ZendSubNS\\ZEND_CONSTANT_A", "namespaced", CONST_PERSISTENT);
|
||||
|
||||
|
@ -635,6 +636,22 @@ static void register_test_symbols(int module_number)
|
|||
ZVAL_STR(&attribute_ZendTestAttributeWithArguments_func_zend_test_attribute_with_named_argument_0_arg0, attribute_ZendTestAttributeWithArguments_func_zend_test_attribute_with_named_argument_0_arg0_str);
|
||||
ZVAL_COPY_VALUE(&attribute_ZendTestAttributeWithArguments_func_zend_test_attribute_with_named_argument_0->args[0].value, &attribute_ZendTestAttributeWithArguments_func_zend_test_attribute_with_named_argument_0_arg0);
|
||||
attribute_ZendTestAttributeWithArguments_func_zend_test_attribute_with_named_argument_0->args[0].name = zend_string_init_interned("arg", sizeof("arg") - 1, 1);
|
||||
|
||||
#if (PHP_VERSION_ID >= 80500)
|
||||
zend_constant *const_ZEND_TEST_ATTRIBUTED_CONSTANT = zend_hash_str_find_ptr(EG(zend_constants), "ZEND_TEST_ATTRIBUTED_CONSTANT", sizeof("ZEND_TEST_ATTRIBUTED_CONSTANT") - 1);
|
||||
|
||||
zend_attribute *attribute_Deprecated_const_ZEND_TEST_ATTRIBUTED_CONSTANT_0 = zend_add_global_constant_attribute(const_ZEND_TEST_ATTRIBUTED_CONSTANT, ZSTR_KNOWN(ZEND_STR_DEPRECATED_CAPITALIZED), 2);
|
||||
zval attribute_Deprecated_const_ZEND_TEST_ATTRIBUTED_CONSTANT_0_arg0;
|
||||
zend_string *attribute_Deprecated_const_ZEND_TEST_ATTRIBUTED_CONSTANT_0_arg0_str = zend_string_init("use something else", strlen("use something else"), 1);
|
||||
ZVAL_STR(&attribute_Deprecated_const_ZEND_TEST_ATTRIBUTED_CONSTANT_0_arg0, attribute_Deprecated_const_ZEND_TEST_ATTRIBUTED_CONSTANT_0_arg0_str);
|
||||
ZVAL_COPY_VALUE(&attribute_Deprecated_const_ZEND_TEST_ATTRIBUTED_CONSTANT_0->args[0].value, &attribute_Deprecated_const_ZEND_TEST_ATTRIBUTED_CONSTANT_0_arg0);
|
||||
attribute_Deprecated_const_ZEND_TEST_ATTRIBUTED_CONSTANT_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
|
||||
zval attribute_Deprecated_const_ZEND_TEST_ATTRIBUTED_CONSTANT_0_arg1;
|
||||
zend_string *attribute_Deprecated_const_ZEND_TEST_ATTRIBUTED_CONSTANT_0_arg1_str = zend_string_init("version 1.5", strlen("version 1.5"), 1);
|
||||
ZVAL_STR(&attribute_Deprecated_const_ZEND_TEST_ATTRIBUTED_CONSTANT_0_arg1, attribute_Deprecated_const_ZEND_TEST_ATTRIBUTED_CONSTANT_0_arg1_str);
|
||||
ZVAL_COPY_VALUE(&attribute_Deprecated_const_ZEND_TEST_ATTRIBUTED_CONSTANT_0->args[1].value, &attribute_Deprecated_const_ZEND_TEST_ATTRIBUTED_CONSTANT_0_arg1);
|
||||
attribute_Deprecated_const_ZEND_TEST_ATTRIBUTED_CONSTANT_0->args[1].name = ZSTR_KNOWN(ZEND_STR_SINCE);
|
||||
#endif
|
||||
}
|
||||
|
||||
static zend_class_entry *register_class__ZendTestInterface(void)
|
||||
|
|
|
@ -17,6 +17,12 @@ $reflection = new ReflectionClassConstant('_ZendTestClass', 'ZEND_TEST_DEPRECATE
|
|||
var_dump($reflection->getAttributes()[0]->newInstance());
|
||||
var_dump($reflection->isDeprecated());
|
||||
|
||||
ZEND_TEST_ATTRIBUTED_CONSTANT;
|
||||
|
||||
$reflection = new ReflectionConstant('ZEND_TEST_ATTRIBUTED_CONSTANT');
|
||||
var_dump($reflection->getAttributes()[0]->newInstance());
|
||||
var_dump($reflection->isDeprecated());
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Deprecated: Function zend_test_deprecated() is deprecated in %s on line %d
|
||||
|
@ -38,3 +44,12 @@ object(Deprecated)#%d (2) {
|
|||
NULL
|
||||
}
|
||||
bool(true)
|
||||
|
||||
Deprecated: Constant ZEND_TEST_ATTRIBUTED_CONSTANT is deprecated since version 1.5, use something else in %s on line %d
|
||||
object(Deprecated)#%d (2) {
|
||||
["message"]=>
|
||||
string(18) "use something else"
|
||||
["since"]=>
|
||||
string(11) "version 1.5"
|
||||
}
|
||||
bool(true)
|
||||
|
|
|
@ -13,11 +13,13 @@ var_dump(get_defined_constants(true)["user"]);
|
|||
|
||||
?>
|
||||
--EXPECT--
|
||||
array(4) {
|
||||
array(5) {
|
||||
["ZEND_TEST_DEPRECATED"]=>
|
||||
int(42)
|
||||
["ZEND_CONSTANT_A"]=>
|
||||
string(6) "global"
|
||||
["ZEND_TEST_ATTRIBUTED_CONSTANT"]=>
|
||||
int(42)
|
||||
["ZendTestNS2\ZEND_CONSTANT_A"]=>
|
||||
string(10) "namespaced"
|
||||
["ZendTestNS2\ZendSubNS\ZEND_CONSTANT_A"]=>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue