mirror of
https://github.com/php/php-src.git
synced 2024-11-23 18:04:36 +08:00
Add reproducer for possible issue with object return type inheritance (#6961)
Fix early inheritance Co-authored-by: Joe Watkins <krakjoe@php.net>
This commit is contained in:
parent
f71bfe4544
commit
fcd18757b2
16
Zend/tests/internal_class_variance.phpt
Normal file
16
Zend/tests/internal_class_variance.phpt
Normal file
@ -0,0 +1,16 @@
|
||||
--TEST--
|
||||
Internal class variance
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
--FILE--
|
||||
<?php
|
||||
$test = new _ZendTestChildClass;
|
||||
|
||||
try {
|
||||
$test->returnsThrowable();
|
||||
} catch (\Error) {
|
||||
echo "OK";
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
OK
|
@ -200,22 +200,45 @@ static bool class_visible(zend_class_entry *ce) {
|
||||
}
|
||||
}
|
||||
|
||||
static zend_always_inline void register_unresolved_class(zend_string *name) {
|
||||
/* We'll autoload this class and process delayed variance obligations later. */
|
||||
if (!CG(delayed_autoloads)) {
|
||||
ALLOC_HASHTABLE(CG(delayed_autoloads));
|
||||
zend_hash_init(CG(delayed_autoloads), 0, NULL, NULL, 0);
|
||||
}
|
||||
zend_hash_add_empty_element(CG(delayed_autoloads), name);
|
||||
}
|
||||
|
||||
static zend_class_entry *lookup_class(
|
||||
zend_class_entry *scope, zend_string *name, bool register_unresolved) {
|
||||
uint32_t flags = ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD;
|
||||
zend_class_entry *ce = zend_lookup_class_ex(name, NULL, flags);
|
||||
zend_class_entry *ce;
|
||||
|
||||
if (UNEXPECTED(!EG(active))) {
|
||||
zend_string *lc_name = zend_string_tolower(name);
|
||||
|
||||
ce = zend_hash_find_ptr(CG(class_table), lc_name);
|
||||
|
||||
zend_string_release(lc_name);
|
||||
|
||||
if (register_unresolved && !ce) {
|
||||
zend_error_noreturn(
|
||||
E_COMPILE_ERROR, "%s must be registered before %s",
|
||||
ZSTR_VAL(name), ZSTR_VAL(scope->name));
|
||||
}
|
||||
|
||||
return ce;
|
||||
}
|
||||
|
||||
ce = zend_lookup_class_ex(
|
||||
name, NULL, ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
|
||||
|
||||
if (!CG(in_compilation)) {
|
||||
if (ce) {
|
||||
return ce;
|
||||
}
|
||||
|
||||
if (register_unresolved) {
|
||||
/* We'll autoload this class and process delayed variance obligations later. */
|
||||
if (!CG(delayed_autoloads)) {
|
||||
ALLOC_HASHTABLE(CG(delayed_autoloads));
|
||||
zend_hash_init(CG(delayed_autoloads), 0, NULL, NULL, 0);
|
||||
}
|
||||
zend_hash_add_empty_element(CG(delayed_autoloads), name);
|
||||
register_unresolved_class(name);
|
||||
}
|
||||
} else {
|
||||
if (ce && class_visible(ce)) {
|
||||
|
@ -257,22 +257,25 @@ static zend_object *zend_test_class_new(zend_class_entry *class_type) /* {{{ */
|
||||
/* }}} */
|
||||
|
||||
static zend_function *zend_test_class_method_get(zend_object **object, zend_string *name, const zval *key) /* {{{ */ {
|
||||
zend_internal_function *fptr;
|
||||
if (zend_string_equals_literal_ci(name, "test")) {
|
||||
zend_internal_function *fptr;
|
||||
|
||||
if (EXPECTED(EG(trampoline).common.function_name == NULL)) {
|
||||
fptr = (zend_internal_function *) &EG(trampoline);
|
||||
} else {
|
||||
fptr = emalloc(sizeof(zend_internal_function));
|
||||
}
|
||||
memset(fptr, 0, sizeof(zend_internal_function));
|
||||
fptr->type = ZEND_INTERNAL_FUNCTION;
|
||||
fptr->num_args = 1;
|
||||
fptr->scope = (*object)->ce;
|
||||
fptr->fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
|
||||
fptr->function_name = zend_string_copy(name);
|
||||
fptr->handler = ZEND_FN(zend_test_func);
|
||||
if (EXPECTED(EG(trampoline).common.function_name == NULL)) {
|
||||
fptr = (zend_internal_function *) &EG(trampoline);
|
||||
} else {
|
||||
fptr = emalloc(sizeof(zend_internal_function));
|
||||
}
|
||||
memset(fptr, 0, sizeof(zend_internal_function));
|
||||
fptr->type = ZEND_INTERNAL_FUNCTION;
|
||||
fptr->num_args = 1;
|
||||
fptr->scope = (*object)->ce;
|
||||
fptr->fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
|
||||
fptr->function_name = zend_string_copy(name);
|
||||
fptr->handler = ZEND_FN(zend_test_func);
|
||||
|
||||
return (zend_function*)fptr;
|
||||
return (zend_function*)fptr;
|
||||
}
|
||||
return zend_std_get_method(object, name, key);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@ -322,6 +325,16 @@ static ZEND_METHOD(_ZendTestClass, returnsStatic) {
|
||||
object_init_ex(return_value, zend_get_called_scope(execute_data));
|
||||
}
|
||||
|
||||
static ZEND_METHOD(_ZendTestClass, returnsThrowable) {
|
||||
ZEND_PARSE_PARAMETERS_NONE();
|
||||
zend_throw_error(NULL, "Dummy");
|
||||
}
|
||||
|
||||
static ZEND_METHOD(_ZendTestChildClass, returnsThrowable) {
|
||||
ZEND_PARSE_PARAMETERS_NONE();
|
||||
zend_throw_error(NULL, "Dummy");
|
||||
}
|
||||
|
||||
static ZEND_METHOD(_ZendTestTrait, testMethod) {
|
||||
ZEND_PARSE_PARAMETERS_NONE();
|
||||
RETURN_TRUE;
|
||||
|
@ -24,10 +24,13 @@ class _ZendTestClass implements _ZendTestInterface {
|
||||
public function __toString(): string {}
|
||||
|
||||
public function returnsStatic(): static {}
|
||||
|
||||
public function returnsThrowable(): Throwable {}
|
||||
}
|
||||
|
||||
class _ZendTestChildClass extends _ZendTestClass
|
||||
{
|
||||
public function returnsThrowable(): Exception {}
|
||||
}
|
||||
|
||||
trait _ZendTestTrait {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: cf8958513064fb7257203b3304c8dc67c8e008b9 */
|
||||
* Stub hash: 70374ed7b55604eb98e85148d7ff19e79258ce92 */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
@ -63,6 +63,12 @@ ZEND_END_ARG_INFO()
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class__ZendTestClass_returnsStatic, 0, 0, IS_STATIC, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class__ZendTestClass_returnsThrowable, 0, 0, Throwable, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class__ZendTestChildClass_returnsThrowable, 0, 0, Exception, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class__ZendTestTrait_testMethod arginfo_ZendTestNS2_ZendSubNS_namespaced_func
|
||||
|
||||
#define arginfo_class_ZendTestNS_Foo_method arginfo_zend_test_void_return
|
||||
@ -89,6 +95,8 @@ static ZEND_FUNCTION(namespaced_func);
|
||||
static ZEND_METHOD(_ZendTestClass, is_object);
|
||||
static ZEND_METHOD(_ZendTestClass, __toString);
|
||||
static ZEND_METHOD(_ZendTestClass, returnsStatic);
|
||||
static ZEND_METHOD(_ZendTestClass, returnsThrowable);
|
||||
static ZEND_METHOD(_ZendTestChildClass, returnsThrowable);
|
||||
static ZEND_METHOD(_ZendTestTrait, testMethod);
|
||||
static ZEND_METHOD(ZendTestNS_Foo, method);
|
||||
static ZEND_METHOD(ZendTestNS2_Foo, method);
|
||||
@ -123,11 +131,13 @@ static const zend_function_entry class__ZendTestClass_methods[] = {
|
||||
ZEND_ME(_ZendTestClass, is_object, arginfo_class__ZendTestClass_is_object, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
||||
ZEND_ME(_ZendTestClass, __toString, arginfo_class__ZendTestClass___toString, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
|
||||
ZEND_ME(_ZendTestClass, returnsStatic, arginfo_class__ZendTestClass_returnsStatic, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(_ZendTestClass, returnsThrowable, arginfo_class__ZendTestClass_returnsThrowable, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
|
||||
static const zend_function_entry class__ZendTestChildClass_methods[] = {
|
||||
ZEND_ME(_ZendTestChildClass, returnsThrowable, arginfo_class__ZendTestChildClass_returnsThrowable, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user