Skip to content

Commit 4842ede

Browse files
committed
Improve magic __get and property type inconsistency error message
Fixes GH-9388 Closes GH-9436
1 parent e17a7ac commit 4842ede

7 files changed

+44
-6
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.3.0alpha1
44

5+
- Core:
6+
. Fixed bug GH-9388 (Improve unset property and __get type incompatibility
7+
error message). (ilutov)
8+
59
- Opcache:
610
. Added start, restart and force restart time to opcache's
711
phpinfo section. (Mikhail Galanin)

Zend/tests/type_declarations/typed_properties_030.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ unset($foo->bar); # ok
1919
var_dump($foo->bar); # not okay, __get is nasty
2020
?>
2121
--EXPECTF--
22-
Fatal error: Uncaught TypeError: Cannot assign string to property Foo::$bar of type int in %s:%d
22+
Fatal error: Uncaught TypeError: Value of type string returned from Foo::__get() must be compatible with unset property Foo::$bar of type int in %s:%d
2323
Stack trace:
2424
#0 {main}
2525
thrown in %s on line %d

Zend/tests/type_declarations/typed_properties_040.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ var_dump($foo->bar);
2020
--EXPECTF--
2121
string(3) "bar"
2222

23-
Fatal error: Uncaught TypeError: Cannot assign null to property Foo::$bar of type int in %s:%d
23+
Fatal error: Uncaught TypeError: Value of type null returned from Foo::__get() must be compatible with unset property Foo::$bar of type int in %s:%d
2424
Stack trace:
2525
#0 {main}
2626
thrown in %s on line %d

Zend/tests/type_declarations/typed_properties_074.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ object(Test)#1 (1) {
3232
["val"]=>
3333
uninitialized(int)
3434
}
35-
Cannot assign string to property Test::$val of type int
35+
Value of type string returned from Test::__get() must be compatible with unset property Test::$val of type int
3636
object(Test)#1 (1) {
3737
["prop"]=>
3838
&string(1) "x"

Zend/zend_execute.c

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,23 @@ ZEND_COLD zend_never_inline void zend_verify_property_type_error(zend_property_i
830830
zend_string_release(type_str);
831831
}
832832

833+
ZEND_COLD zend_never_inline void zend_magic_get_property_type_inconsistency_error(zend_property_info *info, zval *property)
834+
{
835+
/* we _may_ land here in case reading already errored and runtime cache thus has not been updated (i.e. it contains a valid but unrelated info) */
836+
if (EG(exception)) {
837+
return;
838+
}
839+
840+
zend_string *type_str = zend_type_to_string(info->type);
841+
zend_type_error("Value of type %s returned from %s::__get() must be compatible with unset property %s::$%s of type %s",
842+
zend_zval_type_name(property),
843+
ZSTR_VAL(info->ce->name),
844+
ZSTR_VAL(info->ce->name),
845+
zend_get_unmangled_property_name(info->name),
846+
ZSTR_VAL(type_str));
847+
zend_string_release(type_str);
848+
}
849+
833850
ZEND_COLD void zend_match_unhandled_error(zval *value)
834851
{
835852
smart_str msg = {0};
@@ -3560,7 +3577,7 @@ ZEND_API zval* zend_assign_to_typed_ref(zval *variable_ptr, zval *orig_value, ze
35603577
return variable_ptr;
35613578
}
35623579

3563-
ZEND_API bool ZEND_FASTCALL zend_verify_prop_assignable_by_ref(zend_property_info *prop_info, zval *orig_val, bool strict) {
3580+
ZEND_API bool ZEND_FASTCALL zend_verify_prop_assignable_by_ref_ex(zend_property_info *prop_info, zval *orig_val, bool strict, zend_verify_prop_assignable_by_ref_context context) {
35643581
zval *val = orig_val;
35653582
if (Z_ISREF_P(val) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(val))) {
35663583
int result;
@@ -3591,10 +3608,20 @@ ZEND_API bool ZEND_FASTCALL zend_verify_prop_assignable_by_ref(zend_property_inf
35913608
}
35923609
}
35933610

3594-
zend_verify_property_type_error(prop_info, val);
3611+
if (EXPECTED(context == ZEND_VERIFY_PROP_ASSIGNABLE_BY_REF_CONTEXT_ASSIGNMENT)) {
3612+
zend_verify_property_type_error(prop_info, val);
3613+
} else {
3614+
ZEND_ASSERT(context == ZEND_VERIFY_PROP_ASSIGNABLE_BY_REF_CONTEXT_MAGIC_GET);
3615+
zend_magic_get_property_type_inconsistency_error(prop_info, val);
3616+
}
3617+
35953618
return 0;
35963619
}
35973620

3621+
ZEND_API bool ZEND_FASTCALL zend_verify_prop_assignable_by_ref(zend_property_info *prop_info, zval *orig_val, bool strict) {
3622+
return zend_verify_prop_assignable_by_ref_ex(prop_info, orig_val, strict, ZEND_VERIFY_PROP_ASSIGNABLE_BY_REF_CONTEXT_ASSIGNMENT);
3623+
}
3624+
35983625
ZEND_API void ZEND_FASTCALL zend_ref_add_type_source(zend_property_info_source_list *source_list, zend_property_info *prop)
35993626
{
36003627
zend_property_info_list *list;

Zend/zend_execute.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ ZEND_COLD void ZEND_FASTCALL zend_param_must_be_ref(const zend_function *func, u
6565
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_use_resource_as_offset(const zval *dim);
6666

6767
ZEND_API bool ZEND_FASTCALL zend_verify_ref_assignable_zval(zend_reference *ref, zval *zv, bool strict);
68+
69+
typedef enum {
70+
ZEND_VERIFY_PROP_ASSIGNABLE_BY_REF_CONTEXT_ASSIGNMENT,
71+
ZEND_VERIFY_PROP_ASSIGNABLE_BY_REF_CONTEXT_MAGIC_GET,
72+
} zend_verify_prop_assignable_by_ref_context;
73+
ZEND_API bool ZEND_FASTCALL zend_verify_prop_assignable_by_ref_ex(zend_property_info *prop_info, zval *orig_val, bool strict, zend_verify_prop_assignable_by_ref_context context);
6874
ZEND_API bool ZEND_FASTCALL zend_verify_prop_assignable_by_ref(zend_property_info *prop_info, zval *orig_val, bool strict);
6975

7076
ZEND_API ZEND_COLD void zend_throw_ref_type_error_zval(zend_property_info *prop, zval *zv);
@@ -449,6 +455,7 @@ ZEND_API int ZEND_FASTCALL zend_handle_undef_args(zend_execute_data *call);
449455

450456
ZEND_API bool zend_verify_property_type(zend_property_info *info, zval *property, bool strict);
451457
ZEND_COLD void zend_verify_property_type_error(zend_property_info *info, zval *property);
458+
ZEND_COLD void zend_magic_get_property_type_inconsistency_error(zend_property_info *info, zval *property);
452459

453460
#define ZEND_REF_ADD_TYPE_SOURCE(ref, source) \
454461
zend_ref_add_type_source(&ZEND_REF_TYPE_SOURCES(ref), source)

Zend/zend_object_handlers.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,7 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int
726726
}
727727

728728
if (UNEXPECTED(prop_info)) {
729-
zend_verify_prop_assignable_by_ref(prop_info, retval, (zobj->ce->__get->common.fn_flags & ZEND_ACC_STRICT_TYPES) != 0);
729+
zend_verify_prop_assignable_by_ref_ex(prop_info, retval, (zobj->ce->__get->common.fn_flags & ZEND_ACC_STRICT_TYPES) != 0, ZEND_VERIFY_PROP_ASSIGNABLE_BY_REF_CONTEXT_MAGIC_GET);
730730
}
731731

732732
OBJ_RELEASE(zobj);

0 commit comments

Comments
 (0)