. 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
--- /dev/null
+--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"
+}
}
/* }}} */
+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);
} 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)) {
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 */
}
}
- 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);
}