mirror of
https://github.com/php/php-src.git
synced 2026-04-01 05:02:27 +02:00
Fix bug #64023 (__toString() & SplFileInfo)
Defining a __toString() method was having no effect when concatenating the object. This was because the cast_object() handler would ignore __toString(). Using echo() directly would actually use __toString(), but this was a bug: the ECHO handler would try zend_std_cast_object_tostring() before cast_object(), but cast_object() should have priority as zend_std_cast_object_tostring() assumes an object with a zend_class_entry.
This commit is contained in:
@@ -896,23 +896,12 @@ ZEND_VM_HANDLER(40, ZEND_ECHO, CONST|TMP|VAR|CV, ANY)
|
|||||||
{
|
{
|
||||||
zend_op *opline = EX(opline);
|
zend_op *opline = EX(opline);
|
||||||
zend_free_op free_op1;
|
zend_free_op free_op1;
|
||||||
zval z_copy;
|
|
||||||
zval *z = GET_OP1_ZVAL_PTR(BP_VAR_R);
|
zval *z = GET_OP1_ZVAL_PTR(BP_VAR_R);
|
||||||
|
|
||||||
if (OP1_TYPE != IS_CONST &&
|
if (OP1_TYPE == IS_TMP_VAR && Z_TYPE_P(z) == IS_OBJECT) {
|
||||||
Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL) {
|
INIT_PZVAL(z);
|
||||||
if (OP1_TYPE == IS_TMP_VAR) {
|
|
||||||
INIT_PZVAL(z);
|
|
||||||
}
|
|
||||||
if (zend_std_cast_object_tostring(z, &z_copy, IS_STRING TSRMLS_CC) == SUCCESS) {
|
|
||||||
zend_print_variable(&z_copy);
|
|
||||||
zval_dtor(&z_copy);
|
|
||||||
} else {
|
|
||||||
zend_print_variable(z);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
zend_print_variable(z);
|
|
||||||
}
|
}
|
||||||
|
zend_print_variable(z);
|
||||||
|
|
||||||
FREE_OP1();
|
FREE_OP1();
|
||||||
ZEND_VM_NEXT_OPCODE();
|
ZEND_VM_NEXT_OPCODE();
|
||||||
|
|||||||
@@ -1320,23 +1320,12 @@ static int ZEND_FASTCALL ZEND_ECHO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
|||||||
{
|
{
|
||||||
zend_op *opline = EX(opline);
|
zend_op *opline = EX(opline);
|
||||||
|
|
||||||
zval z_copy;
|
|
||||||
zval *z = &opline->op1.u.constant;
|
zval *z = &opline->op1.u.constant;
|
||||||
|
|
||||||
if (IS_CONST != IS_CONST &&
|
if (IS_CONST == IS_TMP_VAR && Z_TYPE_P(z) == IS_OBJECT) {
|
||||||
Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL) {
|
INIT_PZVAL(z);
|
||||||
if (IS_CONST == IS_TMP_VAR) {
|
|
||||||
INIT_PZVAL(z);
|
|
||||||
}
|
|
||||||
if (zend_std_cast_object_tostring(z, &z_copy, IS_STRING TSRMLS_CC) == SUCCESS) {
|
|
||||||
zend_print_variable(&z_copy);
|
|
||||||
zval_dtor(&z_copy);
|
|
||||||
} else {
|
|
||||||
zend_print_variable(z);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
zend_print_variable(z);
|
|
||||||
}
|
}
|
||||||
|
zend_print_variable(z);
|
||||||
|
|
||||||
ZEND_VM_NEXT_OPCODE();
|
ZEND_VM_NEXT_OPCODE();
|
||||||
}
|
}
|
||||||
@@ -4635,23 +4624,12 @@ static int ZEND_FASTCALL ZEND_ECHO_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
|||||||
{
|
{
|
||||||
zend_op *opline = EX(opline);
|
zend_op *opline = EX(opline);
|
||||||
zend_free_op free_op1;
|
zend_free_op free_op1;
|
||||||
zval z_copy;
|
|
||||||
zval *z = _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC);
|
zval *z = _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC);
|
||||||
|
|
||||||
if (IS_TMP_VAR != IS_CONST &&
|
if (IS_TMP_VAR == IS_TMP_VAR && Z_TYPE_P(z) == IS_OBJECT) {
|
||||||
Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL) {
|
INIT_PZVAL(z);
|
||||||
if (IS_TMP_VAR == IS_TMP_VAR) {
|
|
||||||
INIT_PZVAL(z);
|
|
||||||
}
|
|
||||||
if (zend_std_cast_object_tostring(z, &z_copy, IS_STRING TSRMLS_CC) == SUCCESS) {
|
|
||||||
zend_print_variable(&z_copy);
|
|
||||||
zval_dtor(&z_copy);
|
|
||||||
} else {
|
|
||||||
zend_print_variable(z);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
zend_print_variable(z);
|
|
||||||
}
|
}
|
||||||
|
zend_print_variable(z);
|
||||||
|
|
||||||
zval_dtor(free_op1.var);
|
zval_dtor(free_op1.var);
|
||||||
ZEND_VM_NEXT_OPCODE();
|
ZEND_VM_NEXT_OPCODE();
|
||||||
@@ -7898,23 +7876,12 @@ static int ZEND_FASTCALL ZEND_ECHO_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
|||||||
{
|
{
|
||||||
zend_op *opline = EX(opline);
|
zend_op *opline = EX(opline);
|
||||||
zend_free_op free_op1;
|
zend_free_op free_op1;
|
||||||
zval z_copy;
|
|
||||||
zval *z = _get_zval_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC);
|
zval *z = _get_zval_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC);
|
||||||
|
|
||||||
if (IS_VAR != IS_CONST &&
|
if (IS_VAR == IS_TMP_VAR && Z_TYPE_P(z) == IS_OBJECT) {
|
||||||
Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL) {
|
INIT_PZVAL(z);
|
||||||
if (IS_VAR == IS_TMP_VAR) {
|
|
||||||
INIT_PZVAL(z);
|
|
||||||
}
|
|
||||||
if (zend_std_cast_object_tostring(z, &z_copy, IS_STRING TSRMLS_CC) == SUCCESS) {
|
|
||||||
zend_print_variable(&z_copy);
|
|
||||||
zval_dtor(&z_copy);
|
|
||||||
} else {
|
|
||||||
zend_print_variable(z);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
zend_print_variable(z);
|
|
||||||
}
|
}
|
||||||
|
zend_print_variable(z);
|
||||||
|
|
||||||
if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
|
if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
|
||||||
ZEND_VM_NEXT_OPCODE();
|
ZEND_VM_NEXT_OPCODE();
|
||||||
@@ -21823,23 +21790,12 @@ static int ZEND_FASTCALL ZEND_ECHO_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
|||||||
{
|
{
|
||||||
zend_op *opline = EX(opline);
|
zend_op *opline = EX(opline);
|
||||||
|
|
||||||
zval z_copy;
|
|
||||||
zval *z = _get_zval_ptr_cv(&opline->op1, EX(Ts), BP_VAR_R TSRMLS_CC);
|
zval *z = _get_zval_ptr_cv(&opline->op1, EX(Ts), BP_VAR_R TSRMLS_CC);
|
||||||
|
|
||||||
if (IS_CV != IS_CONST &&
|
if (IS_CV == IS_TMP_VAR && Z_TYPE_P(z) == IS_OBJECT) {
|
||||||
Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL) {
|
INIT_PZVAL(z);
|
||||||
if (IS_CV == IS_TMP_VAR) {
|
|
||||||
INIT_PZVAL(z);
|
|
||||||
}
|
|
||||||
if (zend_std_cast_object_tostring(z, &z_copy, IS_STRING TSRMLS_CC) == SUCCESS) {
|
|
||||||
zend_print_variable(&z_copy);
|
|
||||||
zval_dtor(&z_copy);
|
|
||||||
} else {
|
|
||||||
zend_print_variable(z);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
zend_print_variable(z);
|
|
||||||
}
|
}
|
||||||
|
zend_print_variable(z);
|
||||||
|
|
||||||
ZEND_VM_NEXT_OPCODE();
|
ZEND_VM_NEXT_OPCODE();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1873,6 +1873,10 @@ static int spl_filesystem_object_cast(zval *readobj, zval *writeobj, int type TS
|
|||||||
spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(readobj TSRMLS_CC);
|
spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(readobj TSRMLS_CC);
|
||||||
|
|
||||||
if (type == IS_STRING) {
|
if (type == IS_STRING) {
|
||||||
|
if (Z_OBJCE_P(readobj)->__tostring) {
|
||||||
|
return std_object_handlers.cast_object(readobj, writeobj, type TSRMLS_CC);
|
||||||
|
}
|
||||||
|
|
||||||
switch (intern->type) {
|
switch (intern->type) {
|
||||||
case SPL_FS_INFO:
|
case SPL_FS_INFO:
|
||||||
case SPL_FS_FILE:
|
case SPL_FS_FILE:
|
||||||
|
|||||||
20
ext/spl/tests/bug64023.phpt
Normal file
20
ext/spl/tests/bug64023.phpt
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
--TEST--
|
||||||
|
Bug #64023: Overloading __toString() in SplFileInfo has no effect
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class A extends \SplFileInfo
|
||||||
|
{
|
||||||
|
public function __toString() {return ' -expected- ';}
|
||||||
|
}
|
||||||
|
|
||||||
|
$a = new A('/');
|
||||||
|
|
||||||
|
// Works
|
||||||
|
echo $a, $a->__toString(), $a->__toString() . '', "\n";
|
||||||
|
|
||||||
|
// Does not work - outputs parent::__toString()
|
||||||
|
echo $a . '', "\n";
|
||||||
|
|
||||||
|
--EXPECT--
|
||||||
|
-expected- -expected- -expected-
|
||||||
|
-expected-
|
||||||
Reference in New Issue
Block a user