Skip to content

Commit 66700f1

Browse files
authored
Merge pull request #14 from beberlei/attributes_no_compiler_attribute
Unify PhpCompilerAttribute + PhpAttribute; allow attributes on internal classes + fns
2 parents 325b636 + 1ea8fef commit 66700f1

15 files changed

+95
-54
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
Attributes: attributes on PhpAttribute return itself
3+
--FILE--
4+
<?php
5+
6+
$reflection = new \ReflectionClass(PhpAttribute::class);
7+
$attributes = $reflection->getAttributes();
8+
9+
foreach ($attributes as $attribute) {
10+
var_dump($attribute->getName());
11+
var_dump($attribute->getArguments());
12+
var_dump($attribute->newInstance());
13+
}
14+
--EXPECTF--
15+
string(12) "PhpAttribute"
16+
array(0) {
17+
}
18+
object(PhpAttribute)#3 (0) {
19+
}

Zend/tests/attributes/007_wrong_compiler_attributes.phpt

Lines changed: 0 additions & 14 deletions
This file was deleted.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
--TEST--
2+
Attributes: Compiler Attributes can check for target declarations
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('zend-test')) {
6+
echo "skip requires zend-test extension\n";
7+
}
8+
--FILE--
9+
<?php
10+
11+
<<ZendTestAttribute>>
12+
function foo() {
13+
}
14+
--EXPECTF--
15+
Fatal error: Only classes can be marked with <<ZendTestAttribute>> in %s

Zend/zend.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,14 +170,14 @@ struct _zend_class_entry {
170170
zend_class_name *trait_names;
171171
zend_trait_alias **trait_aliases;
172172
zend_trait_precedence **trait_precedences;
173+
HashTable *attributes;
173174

174175
union {
175176
struct {
176177
zend_string *filename;
177178
uint32_t line_start;
178179
uint32_t line_end;
179180
zend_string *doc_comment;
180-
HashTable *attributes;
181181
} user;
182182
struct {
183183
const struct _zend_function_entry *builtin_functions;

Zend/zend_API.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2583,6 +2583,7 @@ static zend_class_entry *do_register_internal_class(zend_class_entry *orig_class
25832583
zend_initialize_class_data(class_entry, 0);
25842584
class_entry->ce_flags = ce_flags | ZEND_ACC_CONSTANTS_UPDATED | ZEND_ACC_LINKED | ZEND_ACC_RESOLVED_PARENT | ZEND_ACC_RESOLVED_INTERFACES;
25852585
class_entry->info.internal.module = EG(current_module);
2586+
class_entry->attributes = NULL;
25862587

25872588
if (class_entry->info.internal.builtin_functions) {
25882589
zend_register_functions(class_entry, class_entry->info.internal.builtin_functions, &class_entry->function_table, EG(current_module)->type);

Zend/zend_attributes.c

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
#include "zend_attributes.h"
44

55
ZEND_API zend_class_entry *zend_ce_php_attribute;
6-
ZEND_API zend_class_entry *zend_ce_php_compiler_attribute;
76

87
static HashTable internal_validators;
98

@@ -14,11 +13,6 @@ void zend_attribute_validate_phpattribute(zend_attribute *attr, int target)
1413
}
1514
}
1615

17-
void zend_attribute_validate_phpcompilerattribute(zend_attribute *attr, int target)
18-
{
19-
zend_error(E_COMPILE_ERROR, "The PhpCompilerAttribute can only be used by internal classes, use PhpAttribute instead");
20-
}
21-
2216
ZEND_API zend_attributes_internal_validator zend_attribute_get_validator(zend_string *lcname)
2317
{
2418
return zend_hash_find_ptr(&internal_validators, lcname);
@@ -90,12 +84,38 @@ ZEND_API zend_attribute *zend_get_parameter_attribute_str(HashTable *attributes,
9084
return get_attribute_str(attributes, str, len, offset + 1);
9185
}
9286

87+
static void attribute_ptr_dtor(zval *v) /* {{{ */
88+
{
89+
zend_attribute_free((zend_attribute *) Z_PTR_P(v));
90+
}
91+
/* }}} */
92+
9393
ZEND_API void zend_compiler_attribute_register(zend_class_entry *ce, zend_attributes_internal_validator validator)
9494
{
95+
if (ce->type != ZEND_INTERNAL_CLASS) {
96+
zend_error_noreturn(E_ERROR, "Only internal classes can be registered as compiler attribute");
97+
}
98+
9599
zend_string *lcname = zend_string_tolower_ex(ce->name, 1);
100+
zval tmp;
96101

97102
zend_hash_update_ptr(&internal_validators, lcname, validator);
98103
zend_string_release(lcname);
104+
105+
if (ce->attributes == NULL) {
106+
ce->attributes = pemalloc(sizeof(HashTable), 1);
107+
zend_hash_init(ce->attributes, 8, NULL, attribute_ptr_dtor, 1);
108+
}
109+
110+
zend_attribute *attr = pemalloc(ZEND_ATTRIBUTE_SIZE(0), 1);
111+
112+
attr->name = zend_string_copy(zend_ce_php_attribute->name);
113+
attr->lcname = zend_string_tolower_ex(attr->name, 1);
114+
attr->offset = 0;
115+
attr->argc = 0;
116+
117+
ZVAL_PTR(&tmp, attr);
118+
zend_hash_next_index_insert(ce->attributes, &tmp);
99119
}
100120

101121
void zend_register_attribute_ce(void)
@@ -109,10 +129,4 @@ void zend_register_attribute_ce(void)
109129
zend_ce_php_attribute->ce_flags |= ZEND_ACC_FINAL;
110130

111131
zend_compiler_attribute_register(zend_ce_php_attribute, zend_attribute_validate_phpattribute);
112-
113-
INIT_CLASS_ENTRY(ce, "PhpCompilerAttribute", NULL);
114-
zend_ce_php_compiler_attribute = zend_register_internal_class(&ce);
115-
zend_ce_php_compiler_attribute->ce_flags |= ZEND_ACC_FINAL;
116-
117-
zend_compiler_attribute_register(zend_ce_php_compiler_attribute, zend_attribute_validate_phpcompilerattribute);
118132
}

Zend/zend_attributes.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
BEGIN_EXTERN_C()
1515

1616
extern ZEND_API zend_class_entry *zend_ce_php_attribute;
17-
extern ZEND_API zend_class_entry *zend_ce_php_compiler_attribute;
1817

1918
typedef struct _zend_attribute {
2019
zend_string *name;

Zend/zend_compile.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1813,7 +1813,7 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify
18131813
} else {
18141814
ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table);
18151815
ce->info.user.doc_comment = NULL;
1816-
ce->info.user.attributes = NULL;
1816+
ce->attributes = NULL;
18171817
}
18181818

18191819
ce->default_properties_count = 0;
@@ -6800,8 +6800,8 @@ void zend_compile_class_decl(znode *result, zend_ast *ast, zend_bool toplevel) /
68006800
ce->info.user.doc_comment = zend_string_copy(decl->doc_comment);
68016801
}
68026802
if (decl->attributes) {
6803-
ce->info.user.attributes = create_attribute_array();
6804-
zend_compile_attributes(ce->info.user.attributes, decl->attributes, 0, ZEND_ATTRIBUTE_TARGET_CLASS);
6803+
ce->attributes = create_attribute_array();
6804+
zend_compile_attributes(ce->attributes, decl->attributes, 0, ZEND_ATTRIBUTE_TARGET_CLASS);
68056805
}
68066806

68076807
if (UNEXPECTED((decl->flags & ZEND_ACC_ANON_CLASS))) {

Zend/zend_compile.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,7 @@ struct _zend_op_array {
406406
uint32_t num_args;
407407
uint32_t required_num_args;
408408
zend_arg_info *arg_info;
409+
HashTable *attributes;
409410
/* END of common elements */
410411

411412
int cache_size; /* number of run_time_cache_slots * sizeof(void*) */
@@ -430,7 +431,6 @@ struct _zend_op_array {
430431
uint32_t line_start;
431432
uint32_t line_end;
432433
zend_string *doc_comment;
433-
HashTable *attributes;
434434

435435
int last_literal;
436436
zval *literals;
@@ -456,6 +456,7 @@ typedef struct _zend_internal_function {
456456
uint32_t num_args;
457457
uint32_t required_num_args;
458458
zend_internal_arg_info *arg_info;
459+
HashTable *attributes;
459460
/* END of common elements */
460461

461462
zif_handler handler;
@@ -479,6 +480,7 @@ union _zend_function {
479480
uint32_t num_args;
480481
uint32_t required_num_args;
481482
zend_arg_info *arg_info; /* index -1 represents the return value info, if any */
483+
HashTable *attributes;
482484
} common;
483485

484486
zend_op_array op_array;

Zend/zend_opcode.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,8 +357,8 @@ ZEND_API void destroy_zend_class(zval *zv)
357357
if (ce->info.user.doc_comment) {
358358
zend_string_release_ex(ce->info.user.doc_comment, 0);
359359
}
360-
if (ce->info.user.attributes) {
361-
zend_array_release(ce->info.user.attributes);
360+
if (ce->attributes) {
361+
zend_array_release(ce->attributes);
362362
}
363363

364364
if (ce->num_traits > 0) {

ext/opcache/zend_file_cache.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,7 @@ static void zend_file_cache_serialize_class(zval *zv,
726726
zend_file_cache_serialize_hash(&ce->constants_table, script, info, buf, zend_file_cache_serialize_class_constant);
727727
SERIALIZE_STR(ce->info.user.filename);
728728
SERIALIZE_STR(ce->info.user.doc_comment);
729-
SERIALIZE_ATTRIBUTES(ce->info.user.attributes);
729+
SERIALIZE_ATTRIBUTES(ce->attributes);
730730
zend_file_cache_serialize_hash(&ce->properties_info, script, info, buf, zend_file_cache_serialize_prop_info);
731731

732732
if (ce->properties_info_table) {
@@ -1465,7 +1465,7 @@ static void zend_file_cache_unserialize_class(zval *zv,
14651465
script, buf, zend_file_cache_unserialize_class_constant, NULL);
14661466
UNSERIALIZE_STR(ce->info.user.filename);
14671467
UNSERIALIZE_STR(ce->info.user.doc_comment);
1468-
UNSERIALIZE_ATTRIBUTES(ce->info.user.attributes);
1468+
UNSERIALIZE_ATTRIBUTES(ce->attributes);
14691469
zend_file_cache_unserialize_hash(&ce->properties_info,
14701470
script, buf, zend_file_cache_unserialize_prop_info, NULL);
14711471

ext/opcache/zend_persist.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -866,8 +866,8 @@ static void zend_persist_class_entry(zval *zv)
866866
ce->info.user.doc_comment = NULL;
867867
}
868868
}
869-
if (ce->info.user.attributes) {
870-
ce->info.user.attributes = zend_persist_attributes(ce->info.user.attributes);
869+
if (ce->attributes) {
870+
ce->attributes = zend_persist_attributes(ce->attributes);
871871
}
872872
zend_hash_persist(&ce->properties_info);
873873
ZEND_HASH_FOREACH_BUCKET(&ce->properties_info, p) {

ext/opcache/zend_persist_calc.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -457,8 +457,8 @@ static void zend_persist_class_entry_calc(zval *zv)
457457
if (ZCG(accel_directives).save_comments && ce->info.user.doc_comment) {
458458
ADD_STRING(ce->info.user.doc_comment);
459459
}
460-
if (ce->info.user.attributes) {
461-
zend_persist_attributes_calc(ce->info.user.attributes);
460+
if (ce->attributes) {
461+
zend_persist_attributes_calc(ce->attributes);
462462
}
463463

464464
zend_hash_persist_calc(&ce->properties_info);

ext/reflection/php_reflection.c

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,6 +1092,8 @@ static void reflection_attribute_factory(zval *object, zend_attribute *data, zen
10921092
static int read_attributes(zval *ret, HashTable *attributes, zend_class_entry *scope,
10931093
uint32_t offset, zend_string *name, zend_class_entry *base) /* {{{ */
10941094
{
1095+
ZEND_ASSERT(attributes != NULL);
1096+
10951097
zend_attribute *attr;
10961098
zval tmp;
10971099

@@ -4176,17 +4178,9 @@ ZEND_METHOD(ReflectionClass, getAttributes)
41764178
reflection_object *intern;
41774179
zend_class_entry *ce;
41784180

4179-
HashTable *attributes = NULL;
4180-
zend_class_entry *scope = NULL;
4181-
41824181
GET_REFLECTION_OBJECT_PTR(ce);
41834182

4184-
if (ce->type == ZEND_USER_CLASS && ce->info.user.attributes) {
4185-
attributes = ce->info.user.attributes;
4186-
scope = ce;
4187-
}
4188-
4189-
reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU, attributes, 0, scope);
4183+
reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU, ce->attributes, 0, ce);
41904184
}
41914185
/* }}} */
41924186

@@ -6582,12 +6576,9 @@ ZEND_METHOD(ReflectionAttribute, newInstance)
65826576
RETURN_THROWS();
65836577
}
65846578

6585-
if (ce->type == ZEND_USER_CLASS && !zend_get_attribute_str(ce->info.user.attributes, ZEND_STRL("phpattribute"))) {
6579+
if (!zend_get_attribute_str(ce->attributes, ZEND_STRL("phpattribute"))) {
65866580
zend_throw_error(NULL, "Attempting to use class '%s' as attribute that does not have <<PhpAttribute>>.", ZSTR_VAL(attr->data->name));
65876581
RETURN_THROWS();
6588-
} else if (ce->type == ZEND_INTERNAL_CLASS && !zend_attribute_get_validator(attr->data->lcname)) {
6589-
zend_throw_error(NULL, "Attempting to use internal class '%s' as attribute that does not have <<PhpCompilerAttribute>>.", ZSTR_VAL(attr->data->name));
6590-
RETURN_THROWS();
65916582
}
65926583

65936584
if (SUCCESS != object_init_ex(&obj, ce)) {
@@ -6623,7 +6614,6 @@ ZEND_METHOD(ReflectionAttribute, newInstance)
66236614
RETURN_ZVAL(&obj, 1, 1);
66246615
}
66256616
/* }}} */
6626-
66276617
static const zend_function_entry reflection_ext_functions[] = { /* {{{ */
66286618
PHP_FE_END
66296619
}; /* }}} */

ext/zend_test/test.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,13 @@
2323
#include "ext/standard/info.h"
2424
#include "php_test.h"
2525
#include "test_arginfo.h"
26+
#include "zend_attributes.h"
2627

2728
static zend_class_entry *zend_test_interface;
2829
static zend_class_entry *zend_test_class;
2930
static zend_class_entry *zend_test_child_class;
3031
static zend_class_entry *zend_test_trait;
32+
static zend_class_entry *zend_test_attribute;
3133
static zend_object_handlers zend_test_class_handlers;
3234

3335
ZEND_FUNCTION(zend_test_func)
@@ -181,6 +183,13 @@ static zend_function *zend_test_class_static_method_get(zend_class_entry *ce, ze
181183
}
182184
/* }}} */
183185

186+
void zend_attribute_validate_zendtestattribute(zend_attribute *attr, int target)
187+
{
188+
if (target != ZEND_ATTRIBUTE_TARGET_CLASS) {
189+
zend_error(E_COMPILE_ERROR, "Only classes can be marked with <<ZendTestAttribute>>");
190+
}
191+
}
192+
184193
ZEND_METHOD(_ZendTestClass, __toString) /* {{{ */ {
185194
RETURN_EMPTY_STRING();
186195
}
@@ -272,6 +281,12 @@ PHP_MINIT_FUNCTION(zend_test)
272281
zend_register_class_alias("_ZendTestClassAlias", zend_test_class);
273282

274283
REGISTER_LONG_CONSTANT("ZEND_TEST_DEPRECATED", 42, CONST_PERSISTENT | CONST_DEPRECATED);
284+
285+
INIT_CLASS_ENTRY(class_entry, "ZendTestAttribute", NULL);
286+
zend_test_attribute = zend_register_internal_class(&class_entry);
287+
zend_test_attribute->ce_flags |= ZEND_ACC_FINAL;
288+
289+
zend_compiler_attribute_register(zend_test_attribute, zend_attribute_validate_zendtestattribute);
275290
return SUCCESS;
276291
}
277292

0 commit comments

Comments
 (0)