mirror of
https://github.com/php/php-src.git
synced 2025-08-15 13:38:49 +02:00
Deprecate returning non-string values from a user output handler (#18932)
https://wiki.php.net/rfc/deprecations_php_8_4
This commit is contained in:
parent
6cc21c4ee6
commit
d8577d9bfb
22 changed files with 603 additions and 17 deletions
|
@ -259,6 +259,13 @@ PHP 8.5 UPGRADE NOTES
|
||||||
4. Deprecated Functionality
|
4. Deprecated Functionality
|
||||||
========================================
|
========================================
|
||||||
|
|
||||||
|
- Core:
|
||||||
|
. Returning a non-string from a user output handler is deprecated. The
|
||||||
|
deprecation warning will bypass the handler with the bad return to ensure
|
||||||
|
it is visible; if there are nested output handlers the next one will still
|
||||||
|
be used.
|
||||||
|
RFC: https://wiki.php.net/rfc/deprecations_php_8_4
|
||||||
|
|
||||||
- Hash:
|
- Hash:
|
||||||
. The MHASH_* constants have been deprecated. These have been overlooked
|
. The MHASH_* constants have been deprecated. These have been overlooked
|
||||||
when the mhash*() function family has been deprecated per
|
when the mhash*() function family has been deprecated per
|
||||||
|
|
|
@ -8,6 +8,7 @@ $counter = 0;
|
||||||
ob_start(function ($buffer) use (&$c, &$counter) {
|
ob_start(function ($buffer) use (&$c, &$counter) {
|
||||||
$c = 0;
|
$c = 0;
|
||||||
++$counter;
|
++$counter;
|
||||||
|
return '';
|
||||||
}, 1);
|
}, 1);
|
||||||
$c .= [];
|
$c .= [];
|
||||||
$c .= [];
|
$c .= [];
|
||||||
|
|
|
@ -7,6 +7,7 @@ opcache.optimization_level = 0x7FFEBFFF & ~0x400
|
||||||
$x = 'non-empty';
|
$x = 'non-empty';
|
||||||
ob_start(function () use (&$c) {
|
ob_start(function () use (&$c) {
|
||||||
$c = 0;
|
$c = 0;
|
||||||
|
return '';
|
||||||
}, 1);
|
}, 1);
|
||||||
$c = [];
|
$c = [];
|
||||||
$x = $c . $x;
|
$x = $c . $x;
|
||||||
|
|
|
@ -6,6 +6,7 @@ $c = str_repeat("abcd", 10);
|
||||||
|
|
||||||
ob_start(function () use (&$c) {
|
ob_start(function () use (&$c) {
|
||||||
$c = 0;
|
$c = 0;
|
||||||
|
return '';
|
||||||
}, 1);
|
}, 1);
|
||||||
|
|
||||||
class X {
|
class X {
|
||||||
|
|
|
@ -11,6 +11,7 @@ ob_start(function() {
|
||||||
register_tick_function(
|
register_tick_function(
|
||||||
function() { }
|
function() { }
|
||||||
);
|
);
|
||||||
|
return '';
|
||||||
});
|
});
|
||||||
?>
|
?>
|
||||||
--EXPECT--
|
--EXPECT--
|
||||||
|
|
|
@ -18,6 +18,7 @@ ob_start(function() {
|
||||||
$a[] = 2;
|
$a[] = 2;
|
||||||
}
|
}
|
||||||
fwrite(STDOUT, "Success");
|
fwrite(STDOUT, "Success");
|
||||||
|
return '';
|
||||||
});
|
});
|
||||||
|
|
||||||
$a = [];
|
$a = [];
|
||||||
|
|
|
@ -18,6 +18,7 @@ ob_start(function() {
|
||||||
$a[] = 2;
|
$a[] = 2;
|
||||||
}
|
}
|
||||||
fwrite(STDOUT, "Success");
|
fwrite(STDOUT, "Success");
|
||||||
|
return '';
|
||||||
});
|
});
|
||||||
|
|
||||||
$a = ["not packed" => 1];
|
$a = ["not packed" => 1];
|
||||||
|
|
|
@ -6,6 +6,7 @@ $counter = 0;
|
||||||
ob_start(function ($buffer) use (&$c, &$counter) {
|
ob_start(function ($buffer) use (&$c, &$counter) {
|
||||||
$c = 0;
|
$c = 0;
|
||||||
++$counter;
|
++$counter;
|
||||||
|
return '';
|
||||||
}, 1);
|
}, 1);
|
||||||
$c .= [];
|
$c .= [];
|
||||||
$c .= [];
|
$c .= [];
|
||||||
|
|
|
@ -5,7 +5,7 @@ session
|
||||||
--FILE--
|
--FILE--
|
||||||
<?php
|
<?php
|
||||||
function output_html($ext) {
|
function output_html($ext) {
|
||||||
return strlen($ext);
|
return (string)strlen($ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
class MySessionHandler implements SessionHandlerInterface {
|
class MySessionHandler implements SessionHandlerInterface {
|
||||||
|
|
|
@ -934,6 +934,7 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl
|
||||||
return PHP_OUTPUT_HANDLER_FAILURE;
|
return PHP_OUTPUT_HANDLER_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool still_have_handler = true;
|
||||||
/* storable? */
|
/* storable? */
|
||||||
if (php_output_handler_append(handler, &context->in) && !context->op) {
|
if (php_output_handler_append(handler, &context->in) && !context->op) {
|
||||||
context->op = original_op;
|
context->op = original_op;
|
||||||
|
@ -948,6 +949,7 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl
|
||||||
if (handler->flags & PHP_OUTPUT_HANDLER_USER) {
|
if (handler->flags & PHP_OUTPUT_HANDLER_USER) {
|
||||||
zval ob_args[2];
|
zval ob_args[2];
|
||||||
zval retval;
|
zval retval;
|
||||||
|
ZVAL_UNDEF(&retval);
|
||||||
|
|
||||||
/* ob_data */
|
/* ob_data */
|
||||||
ZVAL_STRINGL(&ob_args[0], handler->buffer.data, handler->buffer.used);
|
ZVAL_STRINGL(&ob_args[0], handler->buffer.data, handler->buffer.used);
|
||||||
|
@ -959,8 +961,38 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl
|
||||||
handler->func.user->fci.params = ob_args;
|
handler->func.user->fci.params = ob_args;
|
||||||
handler->func.user->fci.retval = &retval;
|
handler->func.user->fci.retval = &retval;
|
||||||
|
|
||||||
#define PHP_OUTPUT_USER_SUCCESS(retval) ((Z_TYPE(retval) != IS_UNDEF) && !(Z_TYPE(retval) == IS_FALSE))
|
if (SUCCESS == zend_call_function(&handler->func.user->fci, &handler->func.user->fcc) && Z_TYPE(retval) != IS_UNDEF) {
|
||||||
if (SUCCESS == zend_call_function(&handler->func.user->fci, &handler->func.user->fcc) && PHP_OUTPUT_USER_SUCCESS(retval)) {
|
if (Z_TYPE(retval) != IS_STRING) {
|
||||||
|
// Make sure that we don't get lost in the current output buffer
|
||||||
|
// by disabling it
|
||||||
|
handler->flags |= PHP_OUTPUT_HANDLER_DISABLED;
|
||||||
|
php_error_docref(
|
||||||
|
NULL,
|
||||||
|
E_DEPRECATED,
|
||||||
|
"Returning a non-string result from user output handler %s is deprecated",
|
||||||
|
ZSTR_VAL(handler->name)
|
||||||
|
);
|
||||||
|
// Check if the handler is still in the list of handlers to
|
||||||
|
// determine if the PHP_OUTPUT_HANDLER_DISABLED flag can
|
||||||
|
// be removed
|
||||||
|
still_have_handler = false;
|
||||||
|
int handler_count = php_output_get_level();
|
||||||
|
if (handler_count) {
|
||||||
|
php_output_handler **handlers = (php_output_handler **) zend_stack_base(&OG(handlers));
|
||||||
|
for (int handler_num = 0; handler_num < handler_count; ++handler_num) {
|
||||||
|
php_output_handler *curr_handler = handlers[handler_num];
|
||||||
|
if (curr_handler == handler) {
|
||||||
|
handler->flags &= (~PHP_OUTPUT_HANDLER_DISABLED);
|
||||||
|
still_have_handler = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Z_TYPE(retval) == IS_FALSE) {
|
||||||
|
/* call failed, pass internal buffer along */
|
||||||
|
status = PHP_OUTPUT_HANDLER_FAILURE;
|
||||||
|
} else {
|
||||||
/* user handler may have returned TRUE */
|
/* user handler may have returned TRUE */
|
||||||
status = PHP_OUTPUT_HANDLER_NO_DATA;
|
status = PHP_OUTPUT_HANDLER_NO_DATA;
|
||||||
if (Z_TYPE(retval) != IS_FALSE && Z_TYPE(retval) != IS_TRUE) {
|
if (Z_TYPE(retval) != IS_FALSE && Z_TYPE(retval) != IS_TRUE) {
|
||||||
|
@ -972,6 +1004,7 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl
|
||||||
status = PHP_OUTPUT_HANDLER_SUCCESS;
|
status = PHP_OUTPUT_HANDLER_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* call failed, pass internal buffer along */
|
/* call failed, pass internal buffer along */
|
||||||
status = PHP_OUTPUT_HANDLER_FAILURE;
|
status = PHP_OUTPUT_HANDLER_FAILURE;
|
||||||
|
@ -996,10 +1029,17 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl
|
||||||
status = PHP_OUTPUT_HANDLER_FAILURE;
|
status = PHP_OUTPUT_HANDLER_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (still_have_handler) {
|
||||||
handler->flags |= PHP_OUTPUT_HANDLER_STARTED;
|
handler->flags |= PHP_OUTPUT_HANDLER_STARTED;
|
||||||
|
}
|
||||||
OG(running) = NULL;
|
OG(running) = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!still_have_handler) {
|
||||||
|
// Handler and context will have both already been freed
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case PHP_OUTPUT_HANDLER_FAILURE:
|
case PHP_OUTPUT_HANDLER_FAILURE:
|
||||||
/* disable this handler */
|
/* disable this handler */
|
||||||
|
@ -1225,6 +1265,19 @@ static int php_output_stack_pop(int flags)
|
||||||
}
|
}
|
||||||
php_output_handler_op(orphan, &context);
|
php_output_handler_op(orphan, &context);
|
||||||
}
|
}
|
||||||
|
// If it isn't still in the stack, cannot free it
|
||||||
|
bool still_have_handler = false;
|
||||||
|
int handler_count = php_output_get_level();
|
||||||
|
if (handler_count) {
|
||||||
|
php_output_handler **handlers = (php_output_handler **) zend_stack_base(&OG(handlers));
|
||||||
|
for (int handler_num = 0; handler_num < handler_count; ++handler_num) {
|
||||||
|
php_output_handler *curr_handler = handlers[handler_num];
|
||||||
|
if (curr_handler == orphan) {
|
||||||
|
still_have_handler = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* pop it off the stack */
|
/* pop it off the stack */
|
||||||
zend_stack_del_top(&OG(handlers));
|
zend_stack_del_top(&OG(handlers));
|
||||||
|
@ -1240,7 +1293,9 @@ static int php_output_stack_pop(int flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* destroy the handler (after write!) */
|
/* destroy the handler (after write!) */
|
||||||
|
if (still_have_handler) {
|
||||||
php_output_handler_free(&orphan);
|
php_output_handler_free(&orphan);
|
||||||
|
}
|
||||||
php_output_context_dtor(&context);
|
php_output_context_dtor(&context);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -18,6 +18,7 @@ $stderr = fopen('php://stderr', 'r');
|
||||||
|
|
||||||
ob_start(function ($buffer) use ($stdout) {
|
ob_start(function ($buffer) use ($stdout) {
|
||||||
fwrite($stdout, $buffer);
|
fwrite($stdout, $buffer);
|
||||||
|
return '';
|
||||||
}, 1);
|
}, 1);
|
||||||
|
|
||||||
print "STDIN:\n";
|
print "STDIN:\n";
|
||||||
|
|
|
@ -34,6 +34,7 @@ file_put_contents('php://fd/2', "Goes to stderrFile\n");
|
||||||
|
|
||||||
ob_start(function ($buffer) use ($stdoutStream) {
|
ob_start(function ($buffer) use ($stdoutStream) {
|
||||||
fwrite($stdoutStream, $buffer);
|
fwrite($stdoutStream, $buffer);
|
||||||
|
return '';
|
||||||
}, 1);
|
}, 1);
|
||||||
|
|
||||||
print "stdoutFile:\n";
|
print "stdoutFile:\n";
|
||||||
|
|
|
@ -5,7 +5,7 @@ Bug #60768 Output buffer not discarded
|
||||||
|
|
||||||
global $storage;
|
global $storage;
|
||||||
|
|
||||||
ob_start(function($buffer) use (&$storage) { $storage .= $buffer; }, 20);
|
ob_start(function($buffer) use (&$storage) { $storage .= $buffer; return ''; }, 20);
|
||||||
|
|
||||||
echo str_repeat("0", 20); // fill in the buffer
|
echo str_repeat("0", 20); // fill in the buffer
|
||||||
|
|
||||||
|
|
|
@ -35,19 +35,24 @@ foreach ($callbacks as $callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
--EXPECT--
|
--EXPECTF--
|
||||||
--> Use callback 'return_empty_string':
|
--> Use callback 'return_empty_string':
|
||||||
|
|
||||||
|
|
||||||
--> Use callback 'return_false':
|
--> Use callback 'return_false':
|
||||||
|
|
||||||
|
Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_false is deprecated in %s on line %d
|
||||||
My output.
|
My output.
|
||||||
|
|
||||||
--> Use callback 'return_null':
|
--> Use callback 'return_null':
|
||||||
|
|
||||||
|
Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_null is deprecated in %s on line %d
|
||||||
|
|
||||||
|
|
||||||
--> Use callback 'return_string':
|
--> Use callback 'return_string':
|
||||||
I stole your output.
|
I stole your output.
|
||||||
|
|
||||||
--> Use callback 'return_zero':
|
--> Use callback 'return_zero':
|
||||||
0
|
|
||||||
|
|
||||||
|
Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_zero is deprecated in %s on line %d
|
||||||
|
0
|
||||||
|
|
147
tests/output/ob_start_callback_bad_return/exception_handler.phpt
Normal file
147
tests/output/ob_start_callback_bad_return/exception_handler.phpt
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
--TEST--
|
||||||
|
ob_start(): Check behaviour with deprecation converted to exception
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class NotStringable {
|
||||||
|
public function __construct(public string $val) {}
|
||||||
|
}
|
||||||
|
class IsStringable {
|
||||||
|
public function __construct(public string $val) {}
|
||||||
|
public function __toString() {
|
||||||
|
return __CLASS__ . ": " . $this->val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$log = [];
|
||||||
|
|
||||||
|
set_error_handler(function (int $errno, string $errstr, string $errfile, int $errline) {
|
||||||
|
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
|
||||||
|
});
|
||||||
|
|
||||||
|
function return_null($string) {
|
||||||
|
global $log;
|
||||||
|
$log[] = __FUNCTION__ . ": <<<" . $string . ">>>";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function return_false($string) {
|
||||||
|
global $log;
|
||||||
|
$log[] = __FUNCTION__ . ": <<<" . $string . ">>>";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function return_true($string) {
|
||||||
|
global $log;
|
||||||
|
$log[] = __FUNCTION__ . ": <<<" . $string . ">>>";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function return_zero($string) {
|
||||||
|
global $log;
|
||||||
|
$log[] = __FUNCTION__ . ": <<<" . $string . ">>>";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function return_non_stringable($string) {
|
||||||
|
global $log;
|
||||||
|
$log[] = __FUNCTION__ . ": <<<" . $string . ">>>";
|
||||||
|
return new NotStringable($string);
|
||||||
|
}
|
||||||
|
|
||||||
|
function return_stringable($string) {
|
||||||
|
global $log;
|
||||||
|
$log[] = __FUNCTION__ . ": <<<" . $string . ">>>";
|
||||||
|
return new IsStringable($string);
|
||||||
|
}
|
||||||
|
|
||||||
|
$cases = [
|
||||||
|
'return_null',
|
||||||
|
'return_false',
|
||||||
|
'return_true',
|
||||||
|
'return_zero',
|
||||||
|
'return_non_stringable',
|
||||||
|
'return_stringable',
|
||||||
|
];
|
||||||
|
foreach ($cases as $case) {
|
||||||
|
$log = [];
|
||||||
|
echo "\n\nTesting: $case\n";
|
||||||
|
ob_start($case);
|
||||||
|
echo "Inside of $case\n";
|
||||||
|
try {
|
||||||
|
ob_end_flush();
|
||||||
|
} catch (\ErrorException $e) {
|
||||||
|
echo $e . "\n";
|
||||||
|
}
|
||||||
|
echo "\nEnd of $case, log was:\n";
|
||||||
|
echo implode("\n", $log);
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Testing: return_null
|
||||||
|
ErrorException: ob_end_flush(): Returning a non-string result from user output handler return_null is deprecated in %s:%d
|
||||||
|
Stack trace:
|
||||||
|
#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d)
|
||||||
|
#1 %s(%d): ob_end_flush()
|
||||||
|
#2 {main}
|
||||||
|
|
||||||
|
End of return_null, log was:
|
||||||
|
return_null: <<<Inside of return_null
|
||||||
|
>>>
|
||||||
|
|
||||||
|
Testing: return_false
|
||||||
|
Inside of return_false
|
||||||
|
ErrorException: ob_end_flush(): Returning a non-string result from user output handler return_false is deprecated in %s:%d
|
||||||
|
Stack trace:
|
||||||
|
#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d)
|
||||||
|
#1 %s(%d): ob_end_flush()
|
||||||
|
#2 {main}
|
||||||
|
|
||||||
|
End of return_false, log was:
|
||||||
|
return_false: <<<Inside of return_false
|
||||||
|
>>>
|
||||||
|
|
||||||
|
Testing: return_true
|
||||||
|
ErrorException: ob_end_flush(): Returning a non-string result from user output handler return_true is deprecated in %s:%d
|
||||||
|
Stack trace:
|
||||||
|
#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d)
|
||||||
|
#1 %s(%d): ob_end_flush()
|
||||||
|
#2 {main}
|
||||||
|
|
||||||
|
End of return_true, log was:
|
||||||
|
return_true: <<<Inside of return_true
|
||||||
|
>>>
|
||||||
|
|
||||||
|
Testing: return_zero
|
||||||
|
0ErrorException: ob_end_flush(): Returning a non-string result from user output handler return_zero is deprecated in %s:%d
|
||||||
|
Stack trace:
|
||||||
|
#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d)
|
||||||
|
#1 %s(%d): ob_end_flush()
|
||||||
|
#2 {main}
|
||||||
|
|
||||||
|
End of return_zero, log was:
|
||||||
|
return_zero: <<<Inside of return_zero
|
||||||
|
>>>
|
||||||
|
|
||||||
|
Testing: return_non_stringable
|
||||||
|
ErrorException: ob_end_flush(): Returning a non-string result from user output handler return_non_stringable is deprecated in %s:%d
|
||||||
|
Stack trace:
|
||||||
|
#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, 69)
|
||||||
|
#1 %s(%d): ob_end_flush()
|
||||||
|
#2 {main}
|
||||||
|
|
||||||
|
End of return_non_stringable, log was:
|
||||||
|
return_non_stringable: <<<Inside of return_non_stringable
|
||||||
|
>>>
|
||||||
|
|
||||||
|
Testing: return_stringable
|
||||||
|
ErrorException: ob_end_flush(): Returning a non-string result from user output handler return_stringable is deprecated in %s:%d
|
||||||
|
Stack trace:
|
||||||
|
#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, 69)
|
||||||
|
#1 %s(%d): ob_end_flush()
|
||||||
|
#2 {main}
|
||||||
|
|
||||||
|
End of return_stringable, log was:
|
||||||
|
return_stringable: <<<Inside of return_stringable
|
||||||
|
>>>
|
|
@ -0,0 +1,143 @@
|
||||||
|
--TEST--
|
||||||
|
ob_start(): Check behaviour with deprecation converted to exception
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class NotStringable {
|
||||||
|
public function __construct(public string $val) {}
|
||||||
|
}
|
||||||
|
class IsStringable {
|
||||||
|
public function __construct(public string $val) {}
|
||||||
|
public function __toString() {
|
||||||
|
return __CLASS__ . ": " . $this->val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$log = [];
|
||||||
|
|
||||||
|
set_error_handler(function (int $errno, string $errstr, string $errfile, int $errline) {
|
||||||
|
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
|
||||||
|
});
|
||||||
|
|
||||||
|
function return_null($string) {
|
||||||
|
global $log;
|
||||||
|
$log[] = __FUNCTION__ . ": <<<" . $string . ">>>";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function return_false($string) {
|
||||||
|
global $log;
|
||||||
|
$log[] = __FUNCTION__ . ": <<<" . $string . ">>>";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function return_true($string) {
|
||||||
|
global $log;
|
||||||
|
$log[] = __FUNCTION__ . ": <<<" . $string . ">>>";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function return_zero($string) {
|
||||||
|
global $log;
|
||||||
|
$log[] = __FUNCTION__ . ": <<<" . $string . ">>>";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function return_non_stringable($string) {
|
||||||
|
global $log;
|
||||||
|
$log[] = __FUNCTION__ . ": <<<" . $string . ">>>";
|
||||||
|
return new NotStringable($string);
|
||||||
|
}
|
||||||
|
|
||||||
|
function return_stringable($string) {
|
||||||
|
global $log;
|
||||||
|
$log[] = __FUNCTION__ . ": <<<" . $string . ">>>";
|
||||||
|
return new IsStringable($string);
|
||||||
|
}
|
||||||
|
|
||||||
|
ob_start('return_null');
|
||||||
|
ob_start('return_false');
|
||||||
|
ob_start('return_true');
|
||||||
|
ob_start('return_zero');
|
||||||
|
ob_start('return_non_stringable');
|
||||||
|
ob_start('return_stringable');
|
||||||
|
|
||||||
|
echo "In all of them\n\n";
|
||||||
|
try {
|
||||||
|
ob_end_flush();
|
||||||
|
} catch (\ErrorException $e) {
|
||||||
|
echo $e->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
echo "Ended return_stringable handler\n\n";
|
||||||
|
|
||||||
|
try {
|
||||||
|
ob_end_flush();
|
||||||
|
} catch (\ErrorException $e) {
|
||||||
|
echo $e->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
echo "Ended return_non_stringable handler\n\n";
|
||||||
|
|
||||||
|
try {
|
||||||
|
ob_end_flush();
|
||||||
|
} catch (\ErrorException $e) {
|
||||||
|
echo $e->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
echo "Ended return_zero handler\n\n";
|
||||||
|
|
||||||
|
try {
|
||||||
|
ob_end_flush();
|
||||||
|
} catch (\ErrorException $e) {
|
||||||
|
echo $e->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
echo "Ended return_true handler\n\n";
|
||||||
|
|
||||||
|
try {
|
||||||
|
ob_end_flush();
|
||||||
|
} catch (\ErrorException $e) {
|
||||||
|
echo $e->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
echo "Ended return_false handler\n\n";
|
||||||
|
|
||||||
|
try {
|
||||||
|
ob_end_flush();
|
||||||
|
} catch (\ErrorException $e) {
|
||||||
|
echo $e->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
echo "Ended return_null handler\n\n";
|
||||||
|
|
||||||
|
echo "All handlers are over\n\n";
|
||||||
|
echo implode("\n", $log);
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
ob_end_flush(): Returning a non-string result from user output handler return_null is deprecated
|
||||||
|
Ended return_null handler
|
||||||
|
|
||||||
|
All handlers are over
|
||||||
|
|
||||||
|
return_stringable: <<<In all of them
|
||||||
|
|
||||||
|
>>>
|
||||||
|
return_non_stringable: <<<ob_end_flush(): Returning a non-string result from user output handler return_stringable is deprecated
|
||||||
|
Ended return_stringable handler
|
||||||
|
|
||||||
|
>>>
|
||||||
|
return_zero: <<<ob_end_flush(): Returning a non-string result from user output handler return_non_stringable is deprecated
|
||||||
|
Ended return_non_stringable handler
|
||||||
|
|
||||||
|
>>>
|
||||||
|
return_true: <<<0ob_end_flush(): Returning a non-string result from user output handler return_zero is deprecated
|
||||||
|
Ended return_zero handler
|
||||||
|
|
||||||
|
>>>
|
||||||
|
return_false: <<<ob_end_flush(): Returning a non-string result from user output handler return_true is deprecated
|
||||||
|
Ended return_true handler
|
||||||
|
|
||||||
|
>>>
|
||||||
|
return_null: <<<ob_end_flush(): Returning a non-string result from user output handler return_true is deprecated
|
||||||
|
Ended return_true handler
|
||||||
|
|
||||||
|
ob_end_flush(): Returning a non-string result from user output handler return_false is deprecated
|
||||||
|
Ended return_false handler
|
||||||
|
|
||||||
|
>>>
|
|
@ -0,0 +1,23 @@
|
||||||
|
--TEST--
|
||||||
|
ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns false)
|
||||||
|
--INI--
|
||||||
|
memory_limit=2M
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
ob_start(function() {
|
||||||
|
// We are out of memory, now trigger a deprecation
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
$a = [];
|
||||||
|
// trigger OOM in a resize operation
|
||||||
|
while (1) {
|
||||||
|
$a[] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Deprecated: main(): Returning a non-string result from user output handler {closure:%s:%d} is deprecated in %s on line %d
|
||||||
|
|
||||||
|
Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d
|
|
@ -0,0 +1,30 @@
|
||||||
|
--TEST--
|
||||||
|
ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns stringable object)
|
||||||
|
--INI--
|
||||||
|
memory_limit=2M
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class IsStringable {
|
||||||
|
public function __construct(public string $val) {}
|
||||||
|
public function __toString() {
|
||||||
|
return __CLASS__ . ": " . $this->val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ob_start(function() {
|
||||||
|
// We are out of memory, now trigger a deprecation
|
||||||
|
return new IsStringable("");
|
||||||
|
});
|
||||||
|
|
||||||
|
$a = [];
|
||||||
|
// trigger OOM in a resize operation
|
||||||
|
while (1) {
|
||||||
|
$a[] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Deprecated: main(): Returning a non-string result from user output handler {closure:%s:%d} is deprecated in %s on line %d
|
||||||
|
|
||||||
|
Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d
|
|
@ -0,0 +1,32 @@
|
||||||
|
--TEST--
|
||||||
|
ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns non-stringable object)
|
||||||
|
--INI--
|
||||||
|
memory_limit=2M
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class NotStringable {
|
||||||
|
public function __construct(public string $val) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
ob_start(function() {
|
||||||
|
// We are out of memory, now trigger a deprecation
|
||||||
|
return new NotStringable("");
|
||||||
|
});
|
||||||
|
|
||||||
|
$a = [];
|
||||||
|
// trigger OOM in a resize operation
|
||||||
|
while (1) {
|
||||||
|
$a[] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Deprecated: main(): Returning a non-string result from user output handler {closure:%s:%d} is deprecated in %s on line %d
|
||||||
|
|
||||||
|
Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d
|
||||||
|
|
||||||
|
Fatal error: Uncaught Error: Object of class NotStringable could not be converted to string in %s:%d
|
||||||
|
Stack trace:
|
||||||
|
#0 {main}
|
||||||
|
thrown in %s on line %d
|
|
@ -0,0 +1,23 @@
|
||||||
|
--TEST--
|
||||||
|
ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns true)
|
||||||
|
--INI--
|
||||||
|
memory_limit=2M
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
ob_start(function() {
|
||||||
|
// We are out of memory, now trigger a deprecation
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
$a = [];
|
||||||
|
// trigger OOM in a resize operation
|
||||||
|
while (1) {
|
||||||
|
$a[] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Deprecated: main(): Returning a non-string result from user output handler {closure:%s:%d} is deprecated in %s on line %d
|
||||||
|
|
||||||
|
Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d
|
|
@ -0,0 +1,23 @@
|
||||||
|
--TEST--
|
||||||
|
ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns zero)
|
||||||
|
--INI--
|
||||||
|
memory_limit=2M
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
ob_start(function() {
|
||||||
|
// We are out of memory, now trigger a deprecation
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
$a = [];
|
||||||
|
// trigger OOM in a resize operation
|
||||||
|
while (1) {
|
||||||
|
$a[] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Deprecated: main(): Returning a non-string result from user output handler {closure:%s:%d} is deprecated in %s on line %d
|
||||||
|
|
||||||
|
Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d
|
|
@ -0,0 +1,89 @@
|
||||||
|
--TEST--
|
||||||
|
ob_start(): Check behaviour with multiple nested handlers with had return values
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$log = [];
|
||||||
|
|
||||||
|
function return_given_string($string) {
|
||||||
|
global $log;
|
||||||
|
$log[] = __FUNCTION__ . ": <<<" . $string . ">>>";
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function return_empty_string($string) {
|
||||||
|
global $log;
|
||||||
|
$log[] = __FUNCTION__ . ": <<<" . $string . ">>>";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function return_false($string) {
|
||||||
|
global $log;
|
||||||
|
$log[] = __FUNCTION__ . ": <<<" . $string . ">>>";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function return_true($string) {
|
||||||
|
global $log;
|
||||||
|
$log[] = __FUNCTION__ . ": <<<" . $string . ">>>";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function return_null($string) {
|
||||||
|
global $log;
|
||||||
|
$log[] = __FUNCTION__ . ": <<<" . $string . ">>>";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function return_string($string) {
|
||||||
|
global $log;
|
||||||
|
$log[] = __FUNCTION__ . ": <<<" . $string . ">>>";
|
||||||
|
return "I stole your output.";
|
||||||
|
}
|
||||||
|
|
||||||
|
function return_zero($string) {
|
||||||
|
global $log;
|
||||||
|
$log[] = __FUNCTION__ . ": <<<" . $string . ">>>";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ob_start('return_given_string');
|
||||||
|
ob_start('return_empty_string');
|
||||||
|
ob_start('return_false');
|
||||||
|
ob_start('return_true');
|
||||||
|
ob_start('return_null');
|
||||||
|
ob_start('return_string');
|
||||||
|
ob_start('return_zero');
|
||||||
|
|
||||||
|
echo "Testing...";
|
||||||
|
|
||||||
|
ob_end_flush();
|
||||||
|
ob_end_flush();
|
||||||
|
ob_end_flush();
|
||||||
|
ob_end_flush();
|
||||||
|
ob_end_flush();
|
||||||
|
ob_end_flush();
|
||||||
|
ob_end_flush();
|
||||||
|
|
||||||
|
echo "\n\nLog:\n";
|
||||||
|
echo implode("\n", $log);
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Log:
|
||||||
|
return_zero: <<<Testing...>>>
|
||||||
|
return_string: <<<
|
||||||
|
Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_zero is deprecated in %s on line %d
|
||||||
|
0>>>
|
||||||
|
return_null: <<<I stole your output.>>>
|
||||||
|
return_true: <<<
|
||||||
|
Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_null is deprecated in %s on line %d
|
||||||
|
>>>
|
||||||
|
return_false: <<<
|
||||||
|
Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_true is deprecated in %s on line %d
|
||||||
|
>>>
|
||||||
|
return_empty_string: <<<
|
||||||
|
Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_false is deprecated in %s on line %d
|
||||||
|
|
||||||
|
Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_true is deprecated in %s on line %d
|
||||||
|
>>>
|
||||||
|
return_given_string: <<<>>>
|
Loading…
Add table
Add a link
Reference in a new issue