summaryrefslogtreecommitdiff
path: root/Zend/zend_API.c
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2019-01-07 12:28:51 +0100
committerNikita Popov <nikita.ppv@gmail.com>2019-01-11 15:49:06 +0100
commite219ec144ef6682b71e135fd18654ee1bb4676b4 (patch)
treee4a3ae2b619cdc9fe50ee8e1fa5adb99d804dddf /Zend/zend_API.c
parentfe8fdfa3bd588d80ce60f6b3848058239e0a760f (diff)
downloadphp-git-e219ec144ef6682b71e135fd18654ee1bb4676b4.tar.gz
Implement typed properties
RFC: https://wiki.php.net/rfc/typed_properties_v2 This is a squash of PR #3734, which is a squash of PR #3313. Co-authored-by: Bob Weinand <bobwei9@hotmail.com> Co-authored-by: Joe Watkins <krakjoe@php.net> Co-authored-by: Dmitry Stogov <dmitry@zend.com>
Diffstat (limited to 'Zend/zend_API.c')
-rw-r--r--Zend/zend_API.c79
1 files changed, 66 insertions, 13 deletions
diff --git a/Zend/zend_API.c b/Zend/zend_API.c
index 02b89be61b..3154f4808f 100644
--- a/Zend/zend_API.c
+++ b/Zend/zend_API.c
@@ -1173,7 +1173,21 @@ ZEND_API int zend_update_class_constants(zend_class_entry *class_type) /* {{{ */
val = (zval*)((char*)class_type->default_properties_table + prop_info->offset - OBJ_PROP_TO_OFFSET(0));
}
if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
- if (UNEXPECTED(zval_update_constant_ex(val, ce) != SUCCESS)) {
+ if (prop_info->type) {
+ zval tmp;
+
+ ZVAL_COPY(&tmp, val);
+ if (UNEXPECTED(zval_update_constant_ex(&tmp, ce) != SUCCESS)) {
+ return FAILURE;
+ }
+ /* property initializers must always be evaluated with strict types */;
+ if (UNEXPECTED(!zend_verify_property_type(prop_info, &tmp, /* strict */ 1))) {
+ zval_ptr_dtor(&tmp);
+ return FAILURE;
+ }
+ zval_ptr_dtor(val);
+ ZVAL_COPY_VALUE(val, &tmp);
+ } else if (UNEXPECTED(zval_update_constant_ex(val, ce) != SUCCESS)) {
return FAILURE;
}
}
@@ -1234,7 +1248,18 @@ ZEND_API void object_properties_init_ex(zend_object *object, HashTable *properti
property_info &&
(property_info->flags & ZEND_ACC_STATIC) == 0) {
zval *slot = OBJ_PROP(object, property_info->offset);
- ZVAL_COPY_VALUE(slot, prop);
+
+ if (UNEXPECTED(property_info->type)) {
+ zval tmp;
+
+ ZVAL_COPY_VALUE(&tmp, prop);
+ if (UNEXPECTED(!zend_verify_property_type(property_info, &tmp, 0))) {
+ continue;
+ }
+ ZVAL_COPY_VALUE(slot, &tmp);
+ } else {
+ ZVAL_COPY_VALUE(slot, prop);
+ }
ZVAL_INDIRECT(prop, slot);
}
} ZEND_HASH_FOREACH_END();
@@ -2632,6 +2657,7 @@ ZEND_API zend_class_entry *zend_register_internal_class_ex(zend_class_entry *cla
if (parent_ce) {
zend_do_inheritance(register_class, parent_ce);
+ zend_build_properties_info_table(register_class);
}
return register_class;
}
@@ -3556,10 +3582,14 @@ static inline zend_string *zval_make_interned_string(zval *zv) /* {{{ */
return Z_STR_P(zv);
}
-ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment) /* {{{ */
+ZEND_API int zend_declare_typed_property(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment, zend_type type) /* {{{ */
{
zend_property_info *property_info, *property_info_ptr;
+ if (ZEND_TYPE_IS_SET(type)) {
+ ce->ce_flags |= ZEND_ACC_HAS_TYPE_HINTS;
+ }
+
if (ce->type == ZEND_INTERNAL_CLASS) {
property_info = pemalloc(sizeof(zend_property_info), 1);
} else {
@@ -3602,10 +3632,20 @@ ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, z
property_info->offset = property_info_ptr->offset;
zval_ptr_dtor(&ce->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)]);
zend_hash_del(&ce->properties_info, name);
+
+ ZEND_ASSERT(ce->type == ZEND_INTERNAL_CLASS);
+ ZEND_ASSERT(ce->properties_info_table != NULL);
+ ce->properties_info_table[OBJ_PROP_TO_NUM(property_info->offset)] = property_info;
} else {
property_info->offset = OBJ_PROP_TO_OFFSET(ce->default_properties_count);
ce->default_properties_count++;
ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(zval) * ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
+
+ /* For user classes this is handled during linking */
+ if (ce->type == ZEND_INTERNAL_CLASS) {
+ ce->properties_info_table = perealloc(ce->properties_info_table, sizeof(zend_property_info *) * ce->default_properties_count, 1);
+ ce->properties_info_table[ce->default_properties_count - 1] = property_info;
+ }
}
ZVAL_COPY_VALUE(&ce->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)], property);
}
@@ -3637,12 +3677,20 @@ ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, z
property_info->flags = access_type;
property_info->doc_comment = doc_comment;
property_info->ce = ce;
+ property_info->type = type;
+
zend_hash_update_ptr(&ce->properties_info, name, property_info);
return SUCCESS;
}
/* }}} */
+ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment) /* {{{ */
+{
+ return zend_declare_typed_property(ce, name, property, access_type, doc_comment, 0);
+}
+/* }}} */
+
ZEND_API int zend_declare_property(zend_class_entry *ce, const char *name, size_t name_length, zval *property, int access_type) /* {{{ */
{
zend_string *key = zend_string_init(name, name_length, ce->type & ZEND_INTERNAL_CLASS);
@@ -3926,25 +3974,30 @@ ZEND_API void zend_update_property_stringl(zend_class_entry *scope, zval *object
ZEND_API int zend_update_static_property_ex(zend_class_entry *scope, zend_string *name, zval *value) /* {{{ */
{
- zval *property;
+ zval *property, tmp;
+ zend_property_info *prop_info;
zend_class_entry *old_scope = EG(fake_scope);
EG(fake_scope) = scope;
- property = zend_std_get_static_property(scope, name, 0);
+ property = zend_std_get_static_property_with_info(scope, name, BP_VAR_W, &prop_info);
EG(fake_scope) = old_scope;
if (!property) {
return FAILURE;
}
- if (property != value) {
- zval garbage;
- ZVAL_DEREF(property);
- ZVAL_DEREF(value);
- ZVAL_COPY_VALUE(&garbage, property);
- ZVAL_COPY(property, value);
- zval_ptr_dtor(&garbage);
+ ZEND_ASSERT(!Z_ISREF_P(value));
+ Z_TRY_ADDREF_P(value);
+ if (prop_info->type) {
+ ZVAL_COPY_VALUE(&tmp, value);
+ if (!zend_verify_property_type(prop_info, &tmp, /* strict */ 0)) {
+ Z_TRY_DELREF_P(value);
+ return FAILURE;
+ }
+ value = &tmp;
}
+
+ zend_assign_to_variable(property, value, IS_TMP_VAR, /* strict */ 0);
return SUCCESS;
}
/* }}} */
@@ -4047,7 +4100,7 @@ ZEND_API zval *zend_read_static_property_ex(zend_class_entry *scope, zend_string
zend_class_entry *old_scope = EG(fake_scope);
EG(fake_scope) = scope;
- property = zend_std_get_static_property(scope, name, silent);
+ property = zend_std_get_static_property(scope, name, silent ? BP_VAR_IS : BP_VAR_R);
EG(fake_scope) = old_scope;
return property;