mirror of
https://github.com/php/php-src.git
synced 2024-09-21 18:07:23 +00:00
Only allow "nearly linked" classes for parent/interface
The requirements for parent/interface are difference than for the variance checks in type declarations. The latter can work on fully unlinked classes, but the former need inheritance to be essentially finished, only variance checks may still be outstanding. Adding a new flag for this because we have lots of space, but we could also represent these "inheritance states" more compactly in the future.
This commit is contained in:
parent
b7c353c8d0
commit
270e5e3c5b
@ -10,4 +10,4 @@ var_dump($a instanceOf A);
|
||||
echo "ok\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Interface RecurisiveFooFar cannot implement itself in %s on line %d
|
||||
Fatal error: Interface 'RecurisiveFooFar' not found in %s on line %d
|
||||
|
15
Zend/tests/type_declarations/variance/unlinked_parent_1.phpt
Normal file
15
Zend/tests/type_declarations/variance/unlinked_parent_1.phpt
Normal file
@ -0,0 +1,15 @@
|
||||
--TEST--
|
||||
Using an unlinked parent class
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
spl_autoload_register(function($class) {
|
||||
class X extends B {}
|
||||
});
|
||||
|
||||
class B extends A {
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Class 'B' not found in %s on line %d
|
15
Zend/tests/type_declarations/variance/unlinked_parent_2.phpt
Normal file
15
Zend/tests/type_declarations/variance/unlinked_parent_2.phpt
Normal file
@ -0,0 +1,15 @@
|
||||
--TEST--
|
||||
Using an unlinked parent interface
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
spl_autoload_register(function($class) {
|
||||
class X implements B {}
|
||||
});
|
||||
|
||||
interface B extends A {
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Interface 'B' not found in %s on line %d
|
@ -229,7 +229,7 @@ typedef struct _zend_oparray_context {
|
||||
/* op_array or class is preloaded | | | */
|
||||
#define ZEND_ACC_PRELOADED (1 << 10) /* X | X | | */
|
||||
/* | | | */
|
||||
/* Class Flags (unused: 22...) | | | */
|
||||
/* Class Flags (unused: 23...) | | | */
|
||||
/* =========== | | | */
|
||||
/* | | | */
|
||||
/* Special class types | | | */
|
||||
@ -278,6 +278,9 @@ typedef struct _zend_oparray_context {
|
||||
/* Class has unresolved variance obligations. | | | */
|
||||
#define ZEND_ACC_UNRESOLVED_VARIANCE (1 << 21) /* X | | | */
|
||||
/* | | | */
|
||||
/* Class is linked apart from variance obligations. | | | */
|
||||
#define ZEND_ACC_NEARLY_LINKED (1 << 22) /* X | | | */
|
||||
/* | | | */
|
||||
/* Function Flags (unused: 23, 26) | | | */
|
||||
/* ============== | | | */
|
||||
/* | | | */
|
||||
@ -864,6 +867,7 @@ void zend_assert_valid_class_name(const zend_string *const_name);
|
||||
#define ZEND_FETCH_CLASS_SILENT 0x0100
|
||||
#define ZEND_FETCH_CLASS_EXCEPTION 0x0200
|
||||
#define ZEND_FETCH_CLASS_ALLOW_UNLINKED 0x0400
|
||||
#define ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED 0x0800
|
||||
|
||||
#define ZEND_PARAM_REF (1<<0)
|
||||
#define ZEND_PARAM_VARIADIC (1<<1)
|
||||
|
@ -917,8 +917,12 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *
|
||||
zend_string_release_ex(lc_name, 0);
|
||||
}
|
||||
ce = (zend_class_entry*)Z_PTR_P(zv);
|
||||
if (UNEXPECTED(!(ce->ce_flags & ZEND_ACC_LINKED)) &&
|
||||
!(flags & ZEND_FETCH_CLASS_ALLOW_UNLINKED)) {
|
||||
if (UNEXPECTED(!(ce->ce_flags & ZEND_ACC_LINKED))) {
|
||||
if ((flags & ZEND_FETCH_CLASS_ALLOW_UNLINKED) ||
|
||||
((flags & ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED) &&
|
||||
(ce->ce_flags & ZEND_ACC_NEARLY_LINKED))) {
|
||||
return ce;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
return ce;
|
||||
|
@ -1005,9 +1005,8 @@ static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry
|
||||
if (!(ce->ce_flags & ZEND_ACC_INTERFACE) && iface->interface_gets_implemented && iface->interface_gets_implemented(iface, ce) == FAILURE) {
|
||||
zend_error_noreturn(E_CORE_ERROR, "Class %s could not implement interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
|
||||
}
|
||||
if (UNEXPECTED(ce == iface)) {
|
||||
zend_error_noreturn(E_ERROR, "Interface %s cannot implement itself", ZSTR_VAL(ce->name));
|
||||
}
|
||||
/* This should be prevented by the class lookup logic. */
|
||||
ZEND_ASSERT(ce != iface);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@ -1457,7 +1456,7 @@ static void zend_do_implement_interfaces(zend_class_entry *ce) /* {{{ */
|
||||
for (i = 0; i < ce->num_interfaces; i++) {
|
||||
iface = zend_fetch_class_by_name(
|
||||
ce->interface_names[i].name, ce->interface_names[i].lc_name,
|
||||
ZEND_FETCH_CLASS_INTERFACE|ZEND_FETCH_CLASS_ALLOW_UNLINKED);
|
||||
ZEND_FETCH_CLASS_INTERFACE|ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED);
|
||||
if (!(iface->ce_flags & ZEND_ACC_LINKED)) {
|
||||
add_dependency_obligation(ce, iface);
|
||||
}
|
||||
@ -2404,7 +2403,7 @@ ZEND_API void zend_do_link_class(zend_class_entry *ce, zend_string *lc_parent_na
|
||||
{
|
||||
if (ce->parent_name) {
|
||||
zend_class_entry *parent = zend_fetch_class_by_name(
|
||||
ce->parent_name, lc_parent_name, ZEND_FETCH_CLASS_ALLOW_UNLINKED);
|
||||
ce->parent_name, lc_parent_name, ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED);
|
||||
if (!(parent->ce_flags & ZEND_ACC_LINKED)) {
|
||||
add_dependency_obligation(ce, parent);
|
||||
}
|
||||
@ -2427,6 +2426,7 @@ ZEND_API void zend_do_link_class(zend_class_entry *ce, zend_string *lc_parent_na
|
||||
return;
|
||||
}
|
||||
|
||||
ce->ce_flags |= ZEND_ACC_NEARLY_LINKED;
|
||||
load_delayed_classes();
|
||||
if (ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
|
||||
resolve_delayed_variance_obligations(ce);
|
||||
|
Loading…
Reference in New Issue
Block a user