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
|
||||
========================================
|
||||
|
||||
- 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:
|
||||
. The MHASH_* constants have been deprecated. These have been overlooked
|
||||
when the mhash*() function family has been deprecated per
|
||||
|
|
|
@ -8,6 +8,7 @@ $counter = 0;
|
|||
ob_start(function ($buffer) use (&$c, &$counter) {
|
||||
$c = 0;
|
||||
++$counter;
|
||||
return '';
|
||||
}, 1);
|
||||
$c .= [];
|
||||
$c .= [];
|
||||
|
|
|
@ -7,6 +7,7 @@ opcache.optimization_level = 0x7FFEBFFF & ~0x400
|
|||
$x = 'non-empty';
|
||||
ob_start(function () use (&$c) {
|
||||
$c = 0;
|
||||
return '';
|
||||
}, 1);
|
||||
$c = [];
|
||||
$x = $c . $x;
|
||||
|
|
|
@ -6,6 +6,7 @@ $c = str_repeat("abcd", 10);
|
|||
|
||||
ob_start(function () use (&$c) {
|
||||
$c = 0;
|
||||
return '';
|
||||
}, 1);
|
||||
|
||||
class X {
|
||||
|
|
|
@ -11,6 +11,7 @@ ob_start(function() {
|
|||
register_tick_function(
|
||||
function() { }
|
||||
);
|
||||
return '';
|
||||
});
|
||||
?>
|
||||
--EXPECT--
|
||||
|
|
|
@ -18,6 +18,7 @@ ob_start(function() {
|
|||
$a[] = 2;
|
||||
}
|
||||
fwrite(STDOUT, "Success");
|
||||
return '';
|
||||
});
|
||||
|
||||
$a = [];
|
||||
|
|
|
@ -18,6 +18,7 @@ ob_start(function() {
|
|||
$a[] = 2;
|
||||
}
|
||||
fwrite(STDOUT, "Success");
|
||||
return '';
|
||||
});
|
||||
|
||||
$a = ["not packed" => 1];
|
||||
|
|
|
@ -6,6 +6,7 @@ $counter = 0;
|
|||
ob_start(function ($buffer) use (&$c, &$counter) {
|
||||
$c = 0;
|
||||
++$counter;
|
||||
return '';
|
||||
}, 1);
|
||||
$c .= [];
|
||||
$c .= [];
|
||||
|
|
|
@ -5,7 +5,7 @@ session
|
|||
--FILE--
|
||||
<?php
|
||||
function output_html($ext) {
|
||||
return strlen($ext);
|
||||
return (string)strlen($ext);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool still_have_handler = true;
|
||||
/* storable? */
|
||||
if (php_output_handler_append(handler, &context->in) && !context->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) {
|
||||
zval ob_args[2];
|
||||
zval retval;
|
||||
ZVAL_UNDEF(&retval);
|
||||
|
||||
/* ob_data */
|
||||
ZVAL_STRINGL(&ob_args[0], handler->buffer.data, handler->buffer.used);
|
||||
|
@ -959,17 +961,48 @@ 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.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) && PHP_OUTPUT_USER_SUCCESS(retval)) {
|
||||
/* user handler may have returned TRUE */
|
||||
status = PHP_OUTPUT_HANDLER_NO_DATA;
|
||||
if (Z_TYPE(retval) != IS_FALSE && Z_TYPE(retval) != IS_TRUE) {
|
||||
convert_to_string(&retval);
|
||||
if (Z_STRLEN(retval)) {
|
||||
context->out.data = estrndup(Z_STRVAL(retval), Z_STRLEN(retval));
|
||||
context->out.used = Z_STRLEN(retval);
|
||||
context->out.free = 1;
|
||||
status = PHP_OUTPUT_HANDLER_SUCCESS;
|
||||
if (SUCCESS == zend_call_function(&handler->func.user->fci, &handler->func.user->fcc) && Z_TYPE(retval) != IS_UNDEF) {
|
||||
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 */
|
||||
status = PHP_OUTPUT_HANDLER_NO_DATA;
|
||||
if (Z_TYPE(retval) != IS_FALSE && Z_TYPE(retval) != IS_TRUE) {
|
||||
convert_to_string(&retval);
|
||||
if (Z_STRLEN(retval)) {
|
||||
context->out.data = estrndup(Z_STRVAL(retval), Z_STRLEN(retval));
|
||||
context->out.used = Z_STRLEN(retval);
|
||||
context->out.free = 1;
|
||||
status = PHP_OUTPUT_HANDLER_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -996,10 +1029,17 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl
|
|||
status = PHP_OUTPUT_HANDLER_FAILURE;
|
||||
}
|
||||
}
|
||||
handler->flags |= PHP_OUTPUT_HANDLER_STARTED;
|
||||
if (still_have_handler) {
|
||||
handler->flags |= PHP_OUTPUT_HANDLER_STARTED;
|
||||
}
|
||||
OG(running) = NULL;
|
||||
}
|
||||
|
||||
if (!still_have_handler) {
|
||||
// Handler and context will have both already been freed
|
||||
return status;
|
||||
}
|
||||
|
||||
switch (status) {
|
||||
case PHP_OUTPUT_HANDLER_FAILURE:
|
||||
/* disable this handler */
|
||||
|
@ -1225,6 +1265,19 @@ static int php_output_stack_pop(int flags)
|
|||
}
|
||||
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 */
|
||||
zend_stack_del_top(&OG(handlers));
|
||||
|
@ -1240,7 +1293,9 @@ static int php_output_stack_pop(int flags)
|
|||
}
|
||||
|
||||
/* destroy the handler (after write!) */
|
||||
php_output_handler_free(&orphan);
|
||||
if (still_have_handler) {
|
||||
php_output_handler_free(&orphan);
|
||||
}
|
||||
php_output_context_dtor(&context);
|
||||
|
||||
return 1;
|
||||
|
|
|
@ -18,6 +18,7 @@ $stderr = fopen('php://stderr', 'r');
|
|||
|
||||
ob_start(function ($buffer) use ($stdout) {
|
||||
fwrite($stdout, $buffer);
|
||||
return '';
|
||||
}, 1);
|
||||
|
||||
print "STDIN:\n";
|
||||
|
|
|
@ -34,6 +34,7 @@ file_put_contents('php://fd/2', "Goes to stderrFile\n");
|
|||
|
||||
ob_start(function ($buffer) use ($stdoutStream) {
|
||||
fwrite($stdoutStream, $buffer);
|
||||
return '';
|
||||
}, 1);
|
||||
|
||||
print "stdoutFile:\n";
|
||||
|
|
|
@ -5,7 +5,7 @@ Bug #60768 Output buffer not discarded
|
|||
|
||||
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
|
||||
|
||||
|
|
|
@ -35,19 +35,24 @@ foreach ($callbacks as $callback) {
|
|||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
--EXPECTF--
|
||||
--> Use callback 'return_empty_string':
|
||||
|
||||
|
||||
--> 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.
|
||||
|
||||
--> 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':
|
||||
I stole your output.
|
||||
|
||||
--> 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