nikic/php-ast

Idea: Expose array of E_COMPILE_WARNINGs encountered during parsing

TysonAndre opened this issue · 3 comments

Alternately, look into making it possible for user callbacks to handle E_COMPILE_WARNINGs in php 8.


It's possible to get the most recent error with error_clear_last()/error_get_last(), but it's not possible to get the full list of warnings.

  • So if a user wants to suppress the last compile warning in the file in an application using php-ast, other compile warnings currently might get introduced unnoticed. This is hopefully a rare occurrence.

The global variable zend_error_cb can be overridden by extensions. It should be able to add values to an output reference array, if one is provided (this functionality would also be nice for token_get_all() to have in the future).

This idea will probably have issues if used in combination with PECL threading extensions.

  1. Before parsing the code, copy the old error handler and set the new error handler.
    The new error handler will call the old error handler for type != E_COMPILE_WARNING~, and append to the reference array for type == E_COMPILE_WARNING` without calling the old error handler.
  2. Parse the code
ext/soap/soap.c
586:    zend_error_cb = old_error_handler;
791:    old_error_handler = zend_error_cb;
792:    zend_error_cb = soap_error_handler;

#define call_old_error_handler(error_num, error_filename, error_lineno, format, args) \
{ \
	va_list copy; \
	va_copy(copy, args); \
	old_error_handler(error_num, error_filename, error_lineno, format, copy); \
	va_end(copy); \
}

In php-src itself: I'm also fuzzy on why E_DEPRECATED can be emitted during parsing and will be handled by user callbacks, but E_COMPILE_WARNING is considered unsafe to use with user callbacks. Calling user callbacks (set_error_handler) for both of these seem like they would be emitted during tokenization (in Zend/zend_language_scanner.l), which would be equally safe/unsafe.

var_export(ast\parse_code('<?php $x = (real)$y;', 70));                                         
Deprecated: The (real) cast is deprecated, use (float) instead in string code on line 1
ast\Node::__set_state(array(

Also, this behavior was introduced in 2000, and there have been improvements to the engine (e.g. the Error class) since then. php/php-src@b80b8381d4c#diff-b09edfedd835ebc4491e565c147190e7R559

I reported https://bugs.php.net/bug.php?id=78537 for the first proposal. I'm not sure which considerations are still an issue.

It doesn't seem like E_DEPRECATED getting emitted when parsing causes any obvious crashes if the user error handler throws

php > set_error_handler(function ($errno, $errstr) { echo "Will throw $errno $errstr\n"; throw new Exception("throwing $errstr"); });
php > token_get_all('<?php if (false) {$x = (real)(real)3;
php ' $y = (real)"2";}', TOKEN_PARSE);
Will throw 8192 The (real) cast is deprecated, use (float) instead
Warning: Uncaught Exception: throwing The (real) cast is deprecated, use (float) instead in php shell code:1
Stack trace:
#0 [internal function]: {closure}(8192, 'The (real) cast...', '', 1, Array)
#1 php shell code(2): token_get_all('<?php if (false...', 1)
#2 {main}
  thrown in php shell code on line 1

The PR 4758 for php-src makes this obsolete.