1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

RFC: Add #[Override] attribute (#9836)

* Add #[Override] attribute

* Move #[\Override] tests into Zend/tests/attributes/override/

* Check `check_only` before removing `ZEND_ACC_OVERRIDE`

* NEWS/UPGRADING for #[\Override]
This commit is contained in:
Tim Düsterhus
2023-06-29 20:23:53 +02:00
committed by GitHub
parent b406f7c67a
commit 49ef6e209d
33 changed files with 591 additions and 2 deletions

1
NEWS
View File

@@ -9,6 +9,7 @@ PHP NEWS
(ilutov) (ilutov)
. Fixed GH-11488 (Missing "Optional parameter before required" deprecation on . Fixed GH-11488 (Missing "Optional parameter before required" deprecation on
union null type). (ilutov) union null type). (ilutov)
. Implement the #[\Override] attribute RFC. (timwolla)
- DOM: - DOM:
. Fixed bug GH-11500 (Namespace reuse in createElementNS() generates wrong . Fixed bug GH-11500 (Namespace reuse in createElementNS() generates wrong

View File

@@ -83,6 +83,9 @@ PHP 8.3 UPGRADE NOTES
declarations. RFC: https://wiki.php.net/rfc/typed_class_constants declarations. RFC: https://wiki.php.net/rfc/typed_class_constants
. Closures created from magic methods can now accept named arguments. . Closures created from magic methods can now accept named arguments.
. The final modifier may now be used when using a method from a trait. . The final modifier may now be used when using a method from a trait.
. Added the #[\Override] attribute to check that a method exists
in a parent class or implemented interface.
RFC: https://wiki.php.net/rfc/marking_overriden_methods
- Posix - Posix
. posix_getrlimit() now takes an optional $res parameter to allow fetching a . posix_getrlimit() now takes an optional $res parameter to allow fetching a

View File

@@ -0,0 +1,47 @@
--TEST--
#[\Override]
--FILE--
<?php
interface I {
public function i();
}
interface II extends I {
#[\Override]
public function i();
}
class P {
public function p1() {}
public function p2() {}
public function p3() {}
public function p4() {}
}
class PP extends P {
#[\Override]
public function p1() {}
public function p2() {}
#[\Override]
public function p3() {}
}
class C extends PP implements I {
#[\Override]
public function i() {}
#[\Override]
public function p1() {}
#[\Override]
public function p2() {}
public function p3() {}
#[\Override]
public function p4() {}
public function c() {}
}
echo "Done";
?>
--EXPECT--
Done

View File

@@ -0,0 +1,19 @@
--TEST--
#[\Override]: Valid native interface.
--FILE--
<?php
class Foo implements IteratorAggregate
{
#[\Override]
public function getIterator(): Traversable
{
yield from [];
}
}
echo "Done";
?>
--EXPECT--
Done

View File

@@ -0,0 +1,16 @@
--TEST--
#[\Override]: No parent class.
--FILE--
<?php
class C
{
#[\Override]
public function c(): void {}
}
echo "Done";
?>
--EXPECTF--
Fatal error: C::c() has #[\Override] attribute, but no matching parent method exists in %s on line %d

View File

@@ -0,0 +1,21 @@
--TEST--
#[\Override]: No parent class, but child implements matching interface.
--FILE--
<?php
interface I {
public function i(): void;
}
class P {
#[\Override]
public function i(): void {}
}
class C extends P implements I {}
echo "Done";
?>
--EXPECTF--
Fatal error: P::i() has #[\Override] attribute, but no matching parent method exists in %s on line %d

View File

@@ -0,0 +1,21 @@
--TEST--
#[\Override]: No parent class, but child implements matching interface (2).
--FILE--
<?php
interface I {
public function i(): void;
}
class C extends P implements I {}
class P {
#[\Override]
public function i(): void {}
}
echo "Done";
?>
--EXPECTF--
Fatal error: P::i() has #[\Override] attribute, but no matching parent method exists in %s on line %d

View File

@@ -0,0 +1,26 @@
--TEST--
#[\Override]: No parent interface.
--FILE--
<?php
interface I {
#[\Override]
public function i(): void;
}
interface II extends I {}
class C implements II {
public function i(): void {}
}
class C2 implements I {
public function i(): void {}
}
echo "Done";
?>
--EXPECTF--
Fatal error: I::i() has #[\Override] attribute, but no matching parent method exists in %s on line %d

View File

@@ -0,0 +1,15 @@
--TEST--
#[\Override]: On trait.
--FILE--
<?php
trait T {
#[\Override]
public function t(): void {}
}
echo "Done";
?>
--EXPECT--
Done

View File

@@ -0,0 +1,19 @@
--TEST--
#[\Override]: On used trait without parent method.
--FILE--
<?php
trait T {
#[\Override]
public function t(): void {}
}
class Foo {
use T;
}
echo "Done";
?>
--EXPECTF--
Fatal error: Foo::t() has #[\Override] attribute, but no matching parent method exists in %s on line %d

View File

@@ -0,0 +1,23 @@
--TEST--
#[\Override]: On used trait with interface method.
--FILE--
<?php
trait T {
#[\Override]
public function i(): void {}
}
interface I {
public function i(): void;
}
class Foo implements I {
use T;
}
echo "Done";
?>
--EXPECT--
Done

View File

@@ -0,0 +1,19 @@
--TEST--
#[\Override]: Parent method is private.
--FILE--
<?php
class P {
private function p(): void {}
}
class C extends P {
#[\Override]
public function p(): void {}
}
echo "Done";
?>
--EXPECTF--
Fatal error: C::p() has #[\Override] attribute, but no matching parent method exists in %s on line %d

View File

@@ -0,0 +1,19 @@
--TEST--
#[\Override]: Parent method is private (2).
--FILE--
<?php
class P {
private function p(): void {}
}
class C extends P {
#[\Override]
private function p(): void {}
}
echo "Done";
?>
--EXPECTF--
Fatal error: C::p() has #[\Override] attribute, but no matching parent method exists in %s on line %d

View File

@@ -0,0 +1,19 @@
--TEST--
#[\Override]: Parent method is protected.
--FILE--
<?php
class P {
protected function p(): void {}
}
class C extends P {
#[\Override]
public function p(): void {}
}
echo "Done";
?>
--EXPECT--
Done

View File

@@ -0,0 +1,19 @@
--TEST--
#[\Override]: Parent method is protected (2).
--FILE--
<?php
class P {
protected function p(): void {}
}
class C extends P {
#[\Override]
protected function p(): void {}
}
echo "Done";
?>
--EXPECT--
Done

View File

@@ -0,0 +1,18 @@
--TEST--
#[\Override]: enum without interface.
--FILE--
<?php
enum E {
case One;
case Two;
#[\Override]
public function e(): void {}
}
echo "Done";
?>
--EXPECTF--
Fatal error: E::e() has #[\Override] attribute, but no matching parent method exists in %s on line %d

View File

@@ -0,0 +1,22 @@
--TEST--
#[\Override]: enum with matching interface.
--FILE--
<?php
interface I {
public function e(): void;
}
enum E implements I {
case One;
case Two;
#[\Override]
public function e(): void {}
}
echo "Done";
?>
--EXPECT--
Done

View File

@@ -0,0 +1,21 @@
--TEST--
#[\Override]: Declared abstract trait method.
--FILE--
<?php
trait T {
public abstract function t(): void;
}
class C {
use T;
#[\Override]
public function t(): void {}
}
echo "Done";
?>
--EXPECT--
Done

View File

@@ -0,0 +1,21 @@
--TEST--
#[\Override]: Redeclared trait method.
--FILE--
<?php
trait T {
public function t(): void {}
}
class C {
use T;
#[\Override]
public function t(): void {}
}
echo "Done";
?>
--EXPECTF--
Fatal error: C::t() has #[\Override] attribute, but no matching parent method exists in %s on line %d

View File

@@ -0,0 +1,32 @@
--TEST--
#[\Override]: Redeclared trait method with interface.
--FILE--
<?php
interface I {
public function i(): string;
}
trait T {
public function i(): string {
return 'T';
}
}
class C implements I {
use T;
#[\Override]
public function i(): string {
return 'C';
}
}
var_dump((new C())->i());
echo "Done";
?>
--EXPECT--
string(1) "C"
Done

View File

@@ -0,0 +1,19 @@
--TEST--
#[\Override]: Valid anonymous class.
--FILE--
<?php
interface I {
public function i(): void;
}
new class () implements I {
#[\Override]
public function i(): void {}
};
echo "Done";
?>
--EXPECT--
Done

View File

@@ -0,0 +1,21 @@
--TEST--
#[\Override]: Invalid anonymous class.
--FILE--
<?php
interface I {
public function i(): void;
}
new class () implements I {
public function i(): void {}
#[\Override]
public function c(): void {}
};
echo "Done";
?>
--EXPECTF--
Fatal error: I@anonymous::c() has #[\Override] attribute, but no matching parent method exists in %s on line %d

View File

@@ -0,0 +1,19 @@
--TEST--
#[\Override]: __construct
--FILE--
<?php
class P {
public function __construct() {}
}
class C extends P {
#[\Override]
public function __construct() {}
}
echo "Done";
?>
--EXPECTF--
Fatal error: C::__construct() has #[\Override] attribute, but no matching parent method exists in %s on line %d

View File

@@ -0,0 +1,16 @@
--TEST--
#[\Override]: Static method no parent class.
--FILE--
<?php
class C
{
#[\Override]
public static function c(): void {}
}
echo "Done";
?>
--EXPECTF--
Fatal error: C::c() has #[\Override] attribute, but no matching parent method exists in %s on line %d

View File

@@ -0,0 +1,19 @@
--TEST--
#[\Override]: Static method.
--FILE--
<?php
class P {
public static function p(): void {}
}
class C extends P {
#[\Override]
public static function p(): void {}
}
echo "Done";
?>
--EXPECT--
Done

View File

@@ -29,6 +29,7 @@ ZEND_API zend_class_entry *zend_ce_return_type_will_change_attribute;
ZEND_API zend_class_entry *zend_ce_allow_dynamic_properties; ZEND_API zend_class_entry *zend_ce_allow_dynamic_properties;
ZEND_API zend_class_entry *zend_ce_sensitive_parameter; ZEND_API zend_class_entry *zend_ce_sensitive_parameter;
ZEND_API zend_class_entry *zend_ce_sensitive_parameter_value; ZEND_API zend_class_entry *zend_ce_sensitive_parameter_value;
ZEND_API zend_class_entry *zend_ce_override;
static zend_object_handlers attributes_object_handlers_sensitive_parameter_value; static zend_object_handlers attributes_object_handlers_sensitive_parameter_value;
@@ -136,6 +137,11 @@ static HashTable *attributes_sensitive_parameter_value_get_properties_for(zend_o
return NULL; return NULL;
} }
ZEND_METHOD(Override, __construct)
{
ZEND_PARSE_PARAMETERS_NONE();
}
static zend_attribute *get_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset) static zend_attribute *get_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset)
{ {
if (attributes) { if (attributes) {
@@ -371,6 +377,9 @@ void zend_register_attribute_ce(void)
/* This is not an actual attribute, thus the zend_mark_internal_attribute() call is missing. */ /* This is not an actual attribute, thus the zend_mark_internal_attribute() call is missing. */
zend_ce_sensitive_parameter_value = register_class_SensitiveParameterValue(); zend_ce_sensitive_parameter_value = register_class_SensitiveParameterValue();
zend_ce_sensitive_parameter_value->default_object_handlers = &attributes_object_handlers_sensitive_parameter_value; zend_ce_sensitive_parameter_value->default_object_handlers = &attributes_object_handlers_sensitive_parameter_value;
zend_ce_override = register_class_Override();
zend_mark_internal_attribute(zend_ce_override);
} }
void zend_attributes_shutdown(void) void zend_attributes_shutdown(void)

View File

@@ -43,6 +43,7 @@ extern ZEND_API zend_class_entry *zend_ce_attribute;
extern ZEND_API zend_class_entry *zend_ce_allow_dynamic_properties; extern ZEND_API zend_class_entry *zend_ce_allow_dynamic_properties;
extern ZEND_API zend_class_entry *zend_ce_sensitive_parameter; extern ZEND_API zend_class_entry *zend_ce_sensitive_parameter;
extern ZEND_API zend_class_entry *zend_ce_sensitive_parameter_value; extern ZEND_API zend_class_entry *zend_ce_sensitive_parameter_value;
extern ZEND_API zend_class_entry *zend_ce_override;
typedef struct { typedef struct {
zend_string *name; zend_string *name;

View File

@@ -86,3 +86,12 @@ final class SensitiveParameterValue
public function __debugInfo(): array {} public function __debugInfo(): array {}
} }
/**
* @strict-properties
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class Override
{
public function __construct() {}
}

View File

@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead. /* This is a generated file, edit the .stub.php file instead.
* Stub hash: afb6a3f1d14099066d028b1579fff074359da293 */ * Stub hash: ab85fd8b8d2b1f1d2bc6c72c9663b112b8d6d2f8 */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Attribute___construct, 0, 0, 0) ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Attribute___construct, 0, 0, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "Attribute::TARGET_ALL") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "Attribute::TARGET_ALL")
@@ -22,6 +22,8 @@ ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_SensitiveParameterValue___debugInfo, 0, 0, IS_ARRAY, 0) ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_SensitiveParameterValue___debugInfo, 0, 0, IS_ARRAY, 0)
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()
#define arginfo_class_Override___construct arginfo_class_ReturnTypeWillChange___construct
ZEND_METHOD(Attribute, __construct); ZEND_METHOD(Attribute, __construct);
ZEND_METHOD(ReturnTypeWillChange, __construct); ZEND_METHOD(ReturnTypeWillChange, __construct);
@@ -30,6 +32,7 @@ ZEND_METHOD(SensitiveParameter, __construct);
ZEND_METHOD(SensitiveParameterValue, __construct); ZEND_METHOD(SensitiveParameterValue, __construct);
ZEND_METHOD(SensitiveParameterValue, getValue); ZEND_METHOD(SensitiveParameterValue, getValue);
ZEND_METHOD(SensitiveParameterValue, __debugInfo); ZEND_METHOD(SensitiveParameterValue, __debugInfo);
ZEND_METHOD(Override, __construct);
static const zend_function_entry class_Attribute_methods[] = { static const zend_function_entry class_Attribute_methods[] = {
@@ -63,6 +66,12 @@ static const zend_function_entry class_SensitiveParameterValue_methods[] = {
ZEND_FE_END ZEND_FE_END
}; };
static const zend_function_entry class_Override_methods[] = {
ZEND_ME(Override, __construct, arginfo_class_Override___construct, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
static zend_class_entry *register_class_Attribute(void) static zend_class_entry *register_class_Attribute(void)
{ {
zend_class_entry ce, *class_entry; zend_class_entry ce, *class_entry;
@@ -205,3 +214,21 @@ static zend_class_entry *register_class_SensitiveParameterValue(void)
return class_entry; return class_entry;
} }
static zend_class_entry *register_class_Override(void)
{
zend_class_entry ce, *class_entry;
INIT_CLASS_ENTRY(ce, "Override", class_Override_methods);
class_entry = zend_register_internal_class_ex(&ce, NULL);
class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES;
zend_string *attribute_name_Attribute_class_Override = zend_string_init_interned("Attribute", sizeof("Attribute") - 1, 1);
zend_attribute *attribute_Attribute_class_Override = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_Override, 1);
zend_string_release(attribute_name_Attribute_class_Override);
zval attribute_Attribute_class_Override_arg0;
ZVAL_LONG(&attribute_Attribute_class_Override_arg0, ZEND_ATTRIBUTE_TARGET_METHOD);
ZVAL_COPY_VALUE(&attribute_Attribute_class_Override->args[0].value, &attribute_Attribute_class_Override_arg0);
return class_entry;
}

View File

@@ -7538,6 +7538,16 @@ static void zend_compile_func_decl(znode *result, zend_ast *ast, bool toplevel)
} }
zend_compile_attributes(&op_array->attributes, decl->child[4], 0, target, 0); zend_compile_attributes(&op_array->attributes, decl->child[4], 0, target, 0);
zend_attribute *override_attribute = zend_get_attribute_str(
op_array->attributes,
"override",
sizeof("override")-1
);
if (override_attribute) {
op_array->fn_flags |= ZEND_ACC_OVERRIDE;
}
} }
/* Do not leak the class scope into free standing functions, even if they are dynamically /* Do not leak the class scope into free standing functions, even if they are dynamically
@@ -8106,6 +8116,7 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
} else if (EXPECTED(zend_hash_add_ptr(CG(class_table), lcname, ce) != NULL)) { } else if (EXPECTED(zend_hash_add_ptr(CG(class_table), lcname, ce) != NULL)) {
zend_string_release(lcname); zend_string_release(lcname);
zend_build_properties_info_table(ce); zend_build_properties_info_table(ce);
zend_inheritance_check_override(ce);
ce->ce_flags |= ZEND_ACC_LINKED; ce->ce_flags |= ZEND_ACC_LINKED;
zend_observer_class_linked_notify(ce, lcname); zend_observer_class_linked_notify(ce, lcname);
return; return;
@@ -8116,6 +8127,7 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
link_unbound: link_unbound:
/* Link unbound simple class */ /* Link unbound simple class */
zend_build_properties_info_table(ce); zend_build_properties_info_table(ce);
zend_inheritance_check_override(ce);
ce->ce_flags |= ZEND_ACC_LINKED; ce->ce_flags |= ZEND_ACC_LINKED;
} }
} }

View File

@@ -304,7 +304,7 @@ typedef struct _zend_oparray_context {
/* Class cannot be serialized or unserialized | | | */ /* Class cannot be serialized or unserialized | | | */
#define ZEND_ACC_NOT_SERIALIZABLE (1 << 29) /* X | | | */ #define ZEND_ACC_NOT_SERIALIZABLE (1 << 29) /* X | | | */
/* | | | */ /* | | | */
/* Function Flags (unused: 28-30) | | | */ /* Function Flags (unused: 29-30) | | | */
/* ============== | | | */ /* ============== | | | */
/* | | | */ /* | | | */
/* deprecation flag | | | */ /* deprecation flag | | | */
@@ -363,6 +363,9 @@ typedef struct _zend_oparray_context {
/* supports opcache compile-time evaluation (funcs) | | | */ /* supports opcache compile-time evaluation (funcs) | | | */
#define ZEND_ACC_COMPILE_TIME_EVAL (1 << 27) /* | X | | */ #define ZEND_ACC_COMPILE_TIME_EVAL (1 << 27) /* | X | | */
/* | | | */ /* | | | */
/* has #[\Override] attribute | | | */
#define ZEND_ACC_OVERRIDE (1 << 28) /* | X | | */
/* | | | */
/* op_array uses strict mode types | | | */ /* op_array uses strict mode types | | | */
#define ZEND_ACC_STRICT_TYPES (1U << 31) /* | X | | */ #define ZEND_ACC_STRICT_TYPES (1U << 31) /* | X | | */

View File

@@ -1174,6 +1174,11 @@ static zend_always_inline inheritance_status do_inheritance_check_on_method_ex(
} }
perform_delayable_implementation_check(ce, child, child_scope, parent, parent_scope); perform_delayable_implementation_check(ce, child, child_scope, parent, parent_scope);
} }
if (!check_only && child->common.scope == ce) {
child->common.fn_flags &= ~ZEND_ACC_OVERRIDE;
}
return INHERITANCE_SUCCESS; return INHERITANCE_SUCCESS;
} }
/* }}} */ /* }}} */
@@ -1896,6 +1901,28 @@ static void zend_do_implement_interfaces(zend_class_entry *ce, zend_class_entry
} }
/* }}} */ /* }}} */
void zend_inheritance_check_override(zend_class_entry *ce)
{
zend_function *f;
if (ce->ce_flags & ZEND_ACC_TRAIT) {
return;
}
ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, f) {
if (f->common.fn_flags & ZEND_ACC_OVERRIDE) {
ZEND_ASSERT(f->type != ZEND_INTERNAL_FUNCTION);
zend_error_at_noreturn(
E_COMPILE_ERROR, f->op_array.filename, f->op_array.line_start,
"%s::%s() has #[\\Override] attribute, but no matching parent method exists",
ZEND_FN_SCOPE_NAME(f), ZSTR_VAL(f->common.function_name));
}
} ZEND_HASH_FOREACH_END();
}
static zend_class_entry *fixup_trait_scope(const zend_function *fn, zend_class_entry *ce) static zend_class_entry *fixup_trait_scope(const zend_function *fn, zend_class_entry *ce)
{ {
/* self in trait methods should be resolved to the using class, not the trait. */ /* self in trait methods should be resolved to the using class, not the trait. */
@@ -2772,6 +2799,8 @@ static void resolve_delayed_variance_obligations(zend_class_entry *ce) {
check_variance_obligation(obligation); check_variance_obligation(obligation);
} ZEND_HASH_FOREACH_END(); } ZEND_HASH_FOREACH_END();
zend_inheritance_check_override(ce);
ce->ce_flags &= ~ZEND_ACC_UNRESOLVED_VARIANCE; ce->ce_flags &= ~ZEND_ACC_UNRESOLVED_VARIANCE;
ce->ce_flags |= ZEND_ACC_LINKED; ce->ce_flags |= ZEND_ACC_LINKED;
zend_hash_index_del(all_obligations, num_key); zend_hash_index_del(all_obligations, num_key);
@@ -3131,6 +3160,7 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
EG(record_errors) = orig_record_errors; EG(record_errors) = orig_record_errors;
if (!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE)) { if (!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE)) {
zend_inheritance_check_override(ce);
ce->ce_flags |= ZEND_ACC_LINKED; ce->ce_flags |= ZEND_ACC_LINKED;
} else { } else {
ce->ce_flags |= ZEND_ACC_NEARLY_LINKED; ce->ce_flags |= ZEND_ACC_NEARLY_LINKED;
@@ -3342,6 +3372,7 @@ ZEND_API zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_
if ((ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) == ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) { if ((ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) == ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
zend_verify_abstract_class(ce); zend_verify_abstract_class(ce);
} }
zend_inheritance_check_override(ce);
ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE)); ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE));
ce->ce_flags |= ZEND_ACC_LINKED; ce->ce_flags |= ZEND_ACC_LINKED;

View File

@@ -37,6 +37,8 @@ void zend_verify_abstract_class(zend_class_entry *ce);
void zend_build_properties_info_table(zend_class_entry *ce); void zend_build_properties_info_table(zend_class_entry *ce);
ZEND_API zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce, zend_string *lcname, zval *delayed_early_binding); ZEND_API zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce, zend_string *lcname, zval *delayed_early_binding);
void zend_inheritance_check_override(zend_class_entry *ce);
ZEND_API extern zend_class_entry* (*zend_inheritance_cache_get)(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces); ZEND_API extern zend_class_entry* (*zend_inheritance_cache_get)(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces);
ZEND_API extern zend_class_entry* (*zend_inheritance_cache_add)(zend_class_entry *ce, zend_class_entry *proto, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, HashTable *dependencies); ZEND_API extern zend_class_entry* (*zend_inheritance_cache_add)(zend_class_entry *ce, zend_class_entry *proto, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, HashTable *dependencies);