mirror of
https://github.com/php/php-src.git
synced 2024-11-23 18:04:36 +08:00
Automatically implement Stringable interface
This commit is contained in:
parent
9e775db025
commit
336eb48c36
@ -410,6 +410,8 @@ PHP 8.0 UPGRADE NOTES
|
||||
. Some consistency fixes to variable syntax have been applied, for example
|
||||
writing `Foo::BAR::$baz` is now allowed.
|
||||
RFC: https://wiki.php.net/rfc/variable_syntax_tweaks
|
||||
. Added Stringable.
|
||||
RFC: https://wiki.php.net/rfc/stringable
|
||||
|
||||
- Date:
|
||||
. Added DateTime::createFromInterface() and
|
||||
|
35
Zend/tests/stringable_automatic_implementation.phpt
Normal file
35
Zend/tests/stringable_automatic_implementation.phpt
Normal file
@ -0,0 +1,35 @@
|
||||
--TEST--
|
||||
Stringable is automatically implemented
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Test {
|
||||
public function __toString() {
|
||||
return "foo";
|
||||
}
|
||||
}
|
||||
|
||||
var_dump(new Test instanceof Stringable);
|
||||
var_dump((new ReflectionClass(Test::class))->getInterfaceNames());
|
||||
|
||||
class Test2 extends Test {
|
||||
public function __toString() {
|
||||
return "bar";
|
||||
}
|
||||
}
|
||||
|
||||
var_dump(new Test2 instanceof Stringable);
|
||||
var_dump((new ReflectionClass(Test2::class))->getInterfaceNames());
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(true)
|
||||
array(1) {
|
||||
[0]=>
|
||||
string(10) "Stringable"
|
||||
}
|
||||
bool(true)
|
||||
array(1) {
|
||||
[0]=>
|
||||
string(10) "Stringable"
|
||||
}
|
17
Zend/tests/type_declarations/variance/stringable.phpt
Normal file
17
Zend/tests/type_declarations/variance/stringable.phpt
Normal file
@ -0,0 +1,17 @@
|
||||
--TEST--
|
||||
Automatic Stringable implementation participates in variance
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Foo {
|
||||
public function test(): Stringable {}
|
||||
}
|
||||
class Bar extends Foo {
|
||||
public function test(): Bar {}
|
||||
public function __toString() {}
|
||||
}
|
||||
|
||||
?>
|
||||
===DONE===
|
||||
--EXPECT--
|
||||
===DONE===
|
@ -6066,6 +6066,24 @@ static void zend_check_magic_method_attr(uint32_t attr, const char* method, zend
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void add_stringable_interface(zend_class_entry *ce) {
|
||||
for (uint32_t i = 0; i < ce->num_interfaces; i++) {
|
||||
if (zend_string_equals_literal(ce->interface_names[i].lc_name, "stringable")) {
|
||||
/* Interface already explicitly implemented */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ce->num_interfaces++;
|
||||
ce->interface_names =
|
||||
erealloc(ce->interface_names, sizeof(zend_class_name) * ce->num_interfaces);
|
||||
// TODO: Add known interned strings instead?
|
||||
ce->interface_names[ce->num_interfaces - 1].name =
|
||||
zend_string_init("Stringable", sizeof("Stringable") - 1, 0);
|
||||
ce->interface_names[ce->num_interfaces - 1].lc_name =
|
||||
zend_string_init("stringable", sizeof("stringable") - 1, 0);
|
||||
}
|
||||
|
||||
void zend_begin_method_decl(zend_op_array *op_array, zend_string *name, zend_bool has_body) /* {{{ */
|
||||
{
|
||||
zend_class_entry *ce = CG(active_class_entry);
|
||||
@ -6147,6 +6165,7 @@ void zend_begin_method_decl(zend_op_array *op_array, zend_string *name, zend_boo
|
||||
} else if (zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_NAME)) {
|
||||
zend_check_magic_method_attr(fn_flags, "__toString", 0);
|
||||
ce->__tostring = (zend_function *) op_array;
|
||||
add_stringable_interface(ce);
|
||||
} else if (zend_string_equals_literal(lcname, ZEND_INVOKE_FUNC_NAME)) {
|
||||
zend_check_magic_method_attr(fn_flags, "__invoke", 0);
|
||||
} else if (zend_string_equals_literal(lcname, ZEND_DEBUGINFO_FUNC_NAME)) {
|
||||
@ -6680,6 +6699,10 @@ zend_op *zend_compile_class_decl(zend_ast *ast, zend_bool toplevel) /* {{{ */
|
||||
|
||||
CG(active_class_entry) = ce;
|
||||
|
||||
if (implements_ast) {
|
||||
zend_compile_implements(implements_ast);
|
||||
}
|
||||
|
||||
zend_compile_stmt(stmt_ast);
|
||||
|
||||
/* Reset lineno for final opcodes and errors */
|
||||
@ -6719,10 +6742,6 @@ zend_op *zend_compile_class_decl(zend_ast *ast, zend_bool toplevel) /* {{{ */
|
||||
}
|
||||
}
|
||||
|
||||
if (implements_ast) {
|
||||
zend_compile_implements(implements_ast);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -184,7 +184,9 @@ Error: 2 - class_implements(): Class does not exist and could not be loaded, %s
|
||||
bool(false)
|
||||
|
||||
--instance of classWithToString--
|
||||
array(0) {
|
||||
array(1) {
|
||||
["Stringable"]=>
|
||||
string(10) "Stringable"
|
||||
}
|
||||
|
||||
--instance of classWithoutToString--
|
||||
|
Loading…
Reference in New Issue
Block a user