Skip to content

Commit 53a4038

Browse files
committed
Implement additional type reservations
* The class names false, true and null are now reserved. * The code dealing with reserved class names is now decoupled from scalar type hint handling. It also includes self, parent, and static, which are class names which were already reserved previously. * Reuse existing messages for reserved class names. Fallout: class_alias() can no longer alias self, parent and static. However this never really worked in the first place, as the test which was testing this shows.
1 parent 607b7d6 commit 53a4038

16 files changed

+72
-80
lines changed

Zend/tests/class_alias_003.phpt

Lines changed: 0 additions & 22 deletions
This file was deleted.

Zend/tests/typehints/scalar_relative_typehint_disallowed.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ foo(10);
1111

1212
?>
1313
--EXPECTF--
14-
Fatal error: "bar\int" cannot be used as a type declaration in %s on line %d
14+
Fatal error: Cannot use 'bar\int' as class name as it is reserved in %s on line %d

Zend/tests/typehints/scalar_reserved2.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ Scalar type hint names cannot be used as class, trait or interface names (2)
55

66
class int {}
77
--EXPECTF--
8-
Fatal error: "int" cannot be used as a class name in %s on line %d
8+
Fatal error: Cannot use 'int' as class name as it is reserved in %s on line %d

Zend/tests/typehints/scalar_reserved2_class_alias.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ Scalar type hint names cannot be used as class, trait or interface names (2) - c
66
class foobar {}
77
class_alias("foobar", "int");
88
--EXPECTF--
9-
Fatal error: "int" cannot be used as a class name in %s on line %d
9+
Fatal error: Cannot use 'int' as class name as it is reserved in %s on line %d

Zend/tests/typehints/scalar_reserved2_use.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ Scalar type hint names cannot be used as class, trait or interface names (2) - u
55

66
use foobar as int;
77
--EXPECTF--
8-
Fatal error: "int" cannot be used as a class name in %s on line %d
8+
Fatal error: Cannot use foobar as int because 'int' is a special class name in %s on line %d

Zend/tests/typehints/scalar_reserved3.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ Scalar type hint names cannot be used as class, trait or interface names (3)
55

66
class float {}
77
--EXPECTF--
8-
Fatal error: "float" cannot be used as a class name in %s on line %d
8+
Fatal error: Cannot use 'float' as class name as it is reserved in %s on line %d

Zend/tests/typehints/scalar_reserved3_class_alias.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ Scalar type hint names cannot be used as class, trait or interface names (3) - c
66
class foobar {}
77
class_alias("foobar", "float");
88
--EXPECTF--
9-
Fatal error: "float" cannot be used as a class name in %s on line %d
9+
Fatal error: Cannot use 'float' as class name as it is reserved in %s on line %d

Zend/tests/typehints/scalar_reserved3_use.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ Scalar type hint names cannot be used as class, trait or interface names (3) - u
55

66
use foobar as float;
77
--EXPECTF--
8-
Fatal error: "float" cannot be used as a class name in %s on line %d
8+
Fatal error: Cannot use foobar as float because 'float' is a special class name in %s on line %d

Zend/tests/typehints/scalar_reserved4.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ Scalar type hint names cannot be used as class, trait or interface names (4)
55

66
class string {}
77
--EXPECTF--
8-
Fatal error: "string" cannot be used as a class name in %s on line %d
8+
Fatal error: Cannot use 'string' as class name as it is reserved in %s on line %d

Zend/tests/typehints/scalar_reserved4_class_alias.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ Scalar type hint names cannot be used as class, trait or interface names (4) - c
66
class foobar {}
77
class_alias("foobar", "string");
88
--EXPECTF--
9-
Fatal error: "string" cannot be used as a class name in %s on line %d
9+
Fatal error: Cannot use 'string' as class name as it is reserved in %s on line %d

Zend/tests/typehints/scalar_reserved4_use.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ Scalar type hint names cannot be used as class, trait or interface names (4) - u
55

66
use foobar as string;
77
--EXPECTF--
8-
Fatal error: "string" cannot be used as a class name in %s on line %d
8+
Fatal error: Cannot use foobar as string because 'string' is a special class name in %s on line %d

Zend/tests/typehints/scalar_reserved6.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ Scalar type hint names cannot be used as class, trait or interface names (6)
55

66
class bool {}
77
--EXPECTF--
8-
Fatal error: "bool" cannot be used as a class name in %s on line %d
8+
Fatal error: Cannot use 'bool' as class name as it is reserved in %s on line %d

Zend/tests/typehints/scalar_reserved6_class_alias.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ Scalar type hint names cannot be used as class, trait or interface names (6) - c
66
class foobar {}
77
class_alias("foobar", "bool");
88
--EXPECTF--
9-
Fatal error: "bool" cannot be used as a class name in %s on line %d
9+
Fatal error: Cannot use 'bool' as class name as it is reserved in %s on line %d

Zend/tests/typehints/scalar_reserved6_use.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ Scalar type hint names cannot be used as class, trait or interface names (6) - u
55

66
use foobar as bool;
77
--EXPECTF--
8-
Fatal error: "bool" cannot be used as a class name in %s on line %d
8+
Fatal error: Cannot use foobar as bool because 'bool' is a special class name in %s on line %d

Zend/tests/typehints/scalar_reserved7.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ namespace foo;
66

77
class int {}
88
--EXPECTF--
9-
Fatal error: "int" cannot be used as a class name in %s on line %d
9+
Fatal error: Cannot use 'int' as class name as it is reserved in %s on line %d

Zend/zend_compile.c

Lines changed: 58 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,53 @@ static zend_bool zend_get_unqualified_name(const zend_string *name, const char *
129129
}
130130
/* }}} */
131131

132+
struct reserved_class_name {
133+
const char *name;
134+
size_t len;
135+
};
136+
static const struct reserved_class_name reserved_class_names[] = {
137+
{ZEND_STRL("bool")},
138+
{ZEND_STRL("false")},
139+
{ZEND_STRL("float")},
140+
{ZEND_STRL("int")},
141+
{ZEND_STRL("null")},
142+
{ZEND_STRL("parent")},
143+
{ZEND_STRL("self")},
144+
{ZEND_STRL("static")},
145+
{ZEND_STRL("string")},
146+
{ZEND_STRL("true")},
147+
{NULL, 0}
148+
};
149+
150+
static zend_bool zend_is_reserved_class_name(const zend_string *name) /* {{{ */
151+
{
152+
const struct reserved_class_name *reserved = reserved_class_names;
153+
154+
const char *uqname = name->val;
155+
size_t uqname_len = name->len;
156+
zend_get_unqualified_name(name, &uqname, &uqname_len);
157+
158+
for (; reserved->name; ++reserved) {
159+
if (uqname_len == reserved->len
160+
&& zend_binary_strcasecmp(uqname, uqname_len, reserved->name, reserved->len) == 0
161+
) {
162+
return 1;
163+
}
164+
}
165+
166+
return 0;
167+
}
168+
/* }}} */
169+
170+
ZEND_API void zend_assert_valid_class_name(const zend_string *name) /* {{{ */
171+
{
172+
if (zend_is_reserved_class_name(name)) {
173+
zend_error_noreturn(E_COMPILE_ERROR,
174+
"Cannot use '%s' as class name as it is reserved", name->val);
175+
}
176+
}
177+
/* }}} */
178+
132179
typedef struct _scalar_typehint_info {
133180
const char* name;
134181
const size_t name_len;
@@ -143,39 +190,19 @@ static const scalar_typehint_info scalar_typehints[] = {
143190
{NULL, 0, IS_UNDEF}
144191
};
145192

146-
static zend_always_inline const scalar_typehint_info* zend_find_scalar_typehint(const zend_string *const_name) /* {{{ */
193+
static zend_always_inline const scalar_typehint_info* zend_find_scalar_typehint(const zend_string *name) /* {{{ */
147194
{
148195
const scalar_typehint_info *info = &scalar_typehints[0];
149-
const char *uqname;
150-
size_t uqname_len;
151-
152-
if (!zend_get_unqualified_name(const_name, &uqname, &uqname_len)) {
153-
uqname = const_name->val;
154-
uqname_len = const_name->len;
155-
}
156196

157-
while (info->name) {
158-
if (uqname_len == info->name_len && zend_binary_strcasecmp(uqname, uqname_len, info->name, info->name_len) == 0) {
159-
break;
197+
for (; info->name; ++info) {
198+
if (name->len == info->name_len
199+
&& zend_binary_strcasecmp(name->val, name->len, info->name, info->name_len) == 0
200+
) {
201+
return info;
160202
}
161-
info++;
162-
}
163-
164-
if (info->name) {
165-
return info;
166-
} else {
167-
return NULL;
168203
}
169-
}
170-
/* }}} */
171-
172-
ZEND_API void zend_assert_valid_class_name(const zend_string *const_name) /* {{{ */
173-
{
174-
const scalar_typehint_info *info = zend_find_scalar_typehint(const_name);
175204

176-
if (info) {
177-
zend_error_noreturn(E_COMPILE_ERROR, "\"%s\" cannot be used as a class name", info->name);
178-
}
205+
return NULL;
179206
}
180207
/* }}} */
181208

@@ -184,9 +211,6 @@ static zend_always_inline zend_uchar zend_lookup_scalar_typehint_by_name(const z
184211
const scalar_typehint_info *info = zend_find_scalar_typehint(const_name);
185212

186213
if (info) {
187-
if (const_name->len != info->name_len) {
188-
zend_error_noreturn(E_COMPILE_ERROR, "\"%s\" cannot be used as a type declaration", const_name->val);
189-
}
190214
return info->type;
191215
} else {
192216
return 0;
@@ -4099,6 +4123,7 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, zend_bool is_
40994123
} else {
41004124
if (zend_is_const_default_class_ref(return_type_ast)) {
41014125
class_name = zend_resolve_class_name_ast(return_type_ast);
4126+
zend_assert_valid_class_name(class_name);
41024127
} else {
41034128
zend_string_addref(class_name);
41044129
if (!is_method) {
@@ -4225,9 +4250,9 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, zend_bool is_
42254250
if (type != 0) {
42264251
arg_info->type_hint = type;
42274252
} else {
4228-
42294253
if (zend_is_const_default_class_ref(type_ast)) {
42304254
class_name = zend_resolve_class_name_ast(type_ast);
4255+
zend_assert_valid_class_name(class_name);
42314256
} else {
42324257
zend_string_addref(class_name);
42334258
}
@@ -4846,19 +4871,14 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */
48464871
return;
48474872
}
48484873

4849-
if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type(name)) {
4850-
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use '%s' as class name as it is reserved",
4851-
name->val);
4852-
}
4874+
zend_assert_valid_class_name(name);
48534875

48544876
lcname = zend_string_tolower(name);
48554877

48564878
if (CG(current_import)) {
48574879
import_name = zend_hash_find_ptr(CG(current_import), lcname);
48584880
}
48594881

4860-
zend_assert_valid_class_name(name);
4861-
48624882
if (CG(current_namespace)) {
48634883
name = zend_prefix_with_ns(name);
48644884

@@ -5094,19 +5114,13 @@ void zend_compile_use(zend_ast *ast) /* {{{ */
50945114
}
50955115
}
50965116

5097-
if (type == T_CLASS) {
5098-
zend_assert_valid_class_name(new_name);
5099-
}
5100-
51015117
if (case_sensitive) {
51025118
lookup_name = zend_string_copy(new_name);
51035119
} else {
51045120
lookup_name = zend_string_tolower(new_name);
51055121
}
51065122

5107-
if (type == T_CLASS && (zend_string_equals_literal(lookup_name, "self")
5108-
|| zend_string_equals_literal(lookup_name, "parent"))
5109-
) {
5123+
if (type == T_CLASS && zend_is_reserved_class_name(new_name)) {
51105124
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use %s as %s because '%s' "
51115125
"is a special class name", old_name->val, new_name->val, new_name->val);
51125126
}

0 commit comments

Comments
 (0)