mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
Implement Stringable automatically for internal classes
Requiring all internal classes (including those from 3rd-party extensions) to implement Stringable if they provide __toString() is too error prone. Case in point, our _ZendTestClass test class was not doing so, resulting in preloading test failures after recent changes. Instead we automatically implement Stringable, the same as we do for userland classes. We still allow explicit implementations, but ignore them (normally they would result in an error due to duplicate interface implementation). Finally, we need to be careful about not trying to implement Stringable on Stringable itself. In some cases this changes the interface order, in particular the automatic Stringable implementation will now come first.
This commit is contained in:
parent
d478ae73b1
commit
b302bfabe7
4 changed files with 33 additions and 2 deletions
16
Zend/tests/stringable_internal_class.phpt
Normal file
16
Zend/tests/stringable_internal_class.phpt
Normal file
|
@ -0,0 +1,16 @@
|
|||
--TEST--
|
||||
Stringable should be automatically implemented for internal classes
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!extension_loaded('zend-test')) die('skip');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
// _ZendTestClass defines __toString() but does not explicitly implement Stringable.
|
||||
$obj = new _ZendTestClass;
|
||||
var_dump($obj instanceof Stringable);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(true)
|
|
@ -2767,6 +2767,13 @@ static zend_class_entry *do_register_internal_class(zend_class_entry *orig_class
|
|||
lowercase_name = zend_new_interned_string(lowercase_name);
|
||||
zend_hash_update_ptr(CG(class_table), lowercase_name, class_entry);
|
||||
zend_string_release_ex(lowercase_name, 1);
|
||||
|
||||
if (class_entry->__tostring && !zend_string_equals_literal(class_entry->name, "Stringable")
|
||||
&& !(class_entry->ce_flags & ZEND_ACC_TRAIT)) {
|
||||
ZEND_ASSERT(zend_ce_stringable
|
||||
&& "Should be registered before first class using __toString()");
|
||||
zend_do_implement_interface(class_entry, zend_ce_stringable);
|
||||
}
|
||||
return class_entry;
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -2786,6 +2793,7 @@ ZEND_API zend_class_entry *zend_register_internal_class_ex(zend_class_entry *cla
|
|||
zend_do_inheritance(register_class, parent_ce);
|
||||
zend_build_properties_info_table(register_class);
|
||||
}
|
||||
|
||||
return register_class;
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -2798,6 +2806,13 @@ ZEND_API void zend_class_implements(zend_class_entry *class_entry, int num_inter
|
|||
|
||||
while (num_interfaces--) {
|
||||
interface_entry = va_arg(interface_list, zend_class_entry *);
|
||||
if (interface_entry == zend_ce_stringable
|
||||
&& zend_class_implements_interface(class_entry, zend_ce_stringable)) {
|
||||
/* Stringable is implemented automatically,
|
||||
* silently ignore an explicit implementation. */
|
||||
continue;
|
||||
}
|
||||
|
||||
zend_do_implement_interface(class_entry, interface_entry);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ $rc = new ReflectionClass("ReflectionClass");
|
|||
echo $rc;
|
||||
?>
|
||||
--EXPECT--
|
||||
Class [ <internal:Reflection> class ReflectionClass implements Reflector, Stringable ] {
|
||||
Class [ <internal:Reflection> class ReflectionClass implements Stringable, Reflector ] {
|
||||
|
||||
- Constants [3] {
|
||||
Constant [ public int IS_IMPLICIT_ABSTRACT ] { 16 }
|
||||
|
|
|
@ -37,7 +37,7 @@ string(183) "Class [ <internal:Core> class stdClass ] {
|
|||
}
|
||||
|
||||
"
|
||||
string(2194) "Class [ <internal:Core> class Exception implements Throwable, Stringable ] {
|
||||
string(2194) "Class [ <internal:Core> class Exception implements Stringable, Throwable ] {
|
||||
|
||||
- Constants [0] {
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue