Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
On Tue, 28 May 2024, Tim Düsterhus wrote: > On 5/28/24 16:26, Derick Rethans wrote: > > > I have just checked this for Xdebug, and you're definitely right > > with that. With the removal of the ZEND_EXIT opcode, it can not now > > detect a scope/function exit now. > > Can you clarify why ZEND_EXIT is special for Xdebug when compared to > any other function that unconditionally throws or unconditionally > calls exit(); by itself, i.e. any other function with a `never` return > type? For each op_array, Xdebug tries to figure out every possible path by following jumps. Certain opcodes, such as GENERATOR_RETURN, THROW, RETURN, and EXIT [1] are considered as an exit point out of the function. A path ends there. If there is a function call to a function with a 'never' return type, then that function will potentially throw, or exit. But that's not relevant for the analysis, as these userland functions will have their own oparrays with their entry and exit points. I can't through this mechanism know when an *internal* function does something similar, as it looks like just a normal function call (unless I hard code the check for a call to 'exit'). [1] https://github.com/xdebug/xdebug/blob/master/src/coverage/code_coverage.c#L348 > > It also breaks my "do tasks on ZEND_EXIT" with the profiler. It is > > used to always write the closing profiling footer to the files. > > Without me being able to overload thati opcode, data would not be > > complete. I even have two bugs (with tests) for this: > > > > - https://bugs.xdebug.org/68 > > - https://bugs.xdebug.org/631 > > Likewise, how is ZEND_EXIT special here? How does it work differently than a > script that runs to completion without calling exit(); or a script that fails, > e.g. due to an uncaught exception or due to reaching the memory limit? I overload EXIT so that I can flush the profile file before the script actually fully ends. This is useful for testing through phpt tests. It looks like I might be able to use existing function observers for this, but I haven't fully made that work yet. cheers, Derick -- https://derickrethans.nl | https://xdebug.org | https://dram.io Author of Xdebug. Like it? Consider supporting me: https://xdebug.org/support mastodon: @derickr@phpc.social @xdebug@phpc.social
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
Hi On 5/28/24 16:26, Derick Rethans wrote: I have just checked this for Xdebug, and you're definitely right with that. With the removal of the ZEND_EXIT opcode, it can not now detect a scope/function exit now. Can you clarify why ZEND_EXIT is special for Xdebug when compared to any other function that unconditionally throws or unconditionally calls exit(); by itself, i.e. any other function with a `never` return type? It also breaks my "do tasks on ZEND_EXIT" with the profiler. It is used to always write the closing profiling footer to the files. Without me being able to overload thati opcode, data would not be complete. I even have two bugs (with tests) for this: - https://bugs.xdebug.org/68 - https://bugs.xdebug.org/631 Likewise, how is ZEND_EXIT special here? How does it work differently than a script that runs to completion without calling exit(); or a script that fails, e.g. due to an uncaught exception or due to reaching the memory limit? Best regards Tim Düsterhus
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
On Tue, 28 May 2024, Gina P. Banyard wrote: > On Tuesday, 28 May 2024 at 15:26, Derick Rethans wrote: > > > On Mon, 27 May 2024, Ilija Tovilo wrote: > > > > > On Sun, May 26, 2024 at 11:47 PM Gina P. Banyard intern...@gpb.moe > > > wrote: > > > > > > > On Wednesday, 8 May 2024 at 14:40, Gina P. Banyard > > > > intern...@gpb.moe wrote: > > > > > > > > > I would like to formally propose my idea for exit() as a > > > > > function brought up to the list on 2024-02-24 [1] with the > > > > > following RFC: https://wiki.php.net/rfc/exit-as-function > > > > > > > > As there haven't been any comments for nearly two weeks, I'm > > > > planning on opening the vote for the RFC on Tuesday. > > > > > > Right now, I am not going to be in favour of this. Specfically > > because the Backward Incompatible Changes don't list some of the > > backward breaking changes, and no mitigations are provided. See > > below. > > > > I also don't see the benefit from doing this in the first place. > > exit/die has always meant "bail straight out", without any function > > semantics (from https://www.php.net/exit): > > > > exit — Output a message and terminate the current script > > > > exit is a language construct and it can be called without > > parentheses if no status is passed. > > > > It's not that this a particularly new or novel behaviour. > > > > I saw somewhere else in the thread that the exit construct could > > already throw a catchable exception. I consider that a bug. > > Considering the whole point of the RFC is to make it a function, I'm > not sure why saying the current exit behaviour is not new or novel > serves any purpose. I understand that that is the point, but I don't think it's argued *why* that needs to happen. > Is catching a TypeError a bug? Is catching a ValueError a bug? Is > catching any sort of engine Error a bug? exit throwing any Exception is the bug I was referring to. > Because this is effectively what you are saying, and if this is the > case, we might as well just reverse the "Exceptions in the engine" RFC > from 2014 [1] to make all those Errors fatal errors again which bail > out immediately. This RFC makes exit() a function such that either it > exits normally, or a TypeError is thrown if you feed it nonsense, > consistently with all our type juggling semantics. > > Moreover, when exit() was changed to use an Exception internally there > were various people in favour of being able to catch it, and have it > run finally blocks (like other programming languages do) [2] It should > also be noted exit() does not just bail out and do nothing else, any > destructors will be run before the exiting, so one can still run > userland code after it has been called [3] > > > I have just checked this for Xdebug, and you're definitely right > > with that. With the removal of the ZEND_EXIT opcode, it can not now > > detect a scope/function exit now. > > > > It also breaks my "do tasks on ZEND_EXIT" with the profiler. It is > > used to always write the closing profiling footer to the files. > > Without me being able to overload thati opcode, data would not be > > complete. I even have two bugs (with tests) for this: > > > > - https://bugs.xdebug.org/68 > > - https://bugs.xdebug.org/631 > > > > Xdebug has been overloading ZEND_EXIT for nearly 20 years now. > > AFAIK Opcodes are not part of any backwards compatibility guarantees. AFAIK it isn't documented otherwise either. Just because it's not documented, doesn't mean we should remove long term existing functionality. > You could overwrite the function pointer of exit() at MINIT with a > custom implementation. I can, but overriding functions for this sort of thing is a little bit of a hack, and I prefer having an actual API. It is also a runtime feature, not a compile time (see below again). > Alternatively, you could use the zend_is_unwind_exit() engine API to > check if the exception that has been thrown is the one that > corresponds to an exit call, this would work as of PHP 8.0. > Finally, the one that makes more work for me, is to add a new observer > API that indicates an exit() and hook into that one. That seems a fairly sensible thing to add. But that only addresses my profiler use case, and not the branch/path detection use case. > > > > > This could be re-added by checking for the never return type instead. > > > > > > I can't quite see a way on how to do that? The EXIT is replaced by an > > INIT_FCALL/DO_ICALL: > > > > 4 0 E > EXT_STMT > >1ECHO '55' > > 5 2EXT_STMT > > - 3 > EXIT > > -6 4* EXT_STMT > > - 5* ECHO '675' > > -7 6* EXT_STMT > > - 7* > RETURN null > > + 3INIT_FCALL 'exit' > > + 4DO_ICALL > > +6 5EXT_STMT > > + 6ECHO '675' > > +7 7
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
On Tuesday, 28 May 2024 at 15:26, Derick Rethans wrote: > On Mon, 27 May 2024, Ilija Tovilo wrote: > > > On Sun, May 26, 2024 at 11:47 PM Gina P. Banyard intern...@gpb.moe > > wrote: > > > > > On Wednesday, 8 May 2024 at 14:40, Gina P. Banyard > > > intern...@gpb.moe wrote: > > > > > > > I would like to formally propose my idea for exit() as a function > > > > brought up to the list on 2024-02-24 [1] with the following RFC: > > > > https://wiki.php.net/rfc/exit-as-function > > > > > > As there haven't been any comments for nearly two weeks, I'm > > > planning on opening the vote for the RFC on Tuesday. > > > Right now, I am not going to be in favour of this. Specfically because > the Backward Incompatible Changes don't list some of the backward > breaking changes, and no mitigations are provided. See below. > > I also don't see the benefit from doing this in the first place. > exit/die has always meant "bail straight out", without any function > semantics (from https://www.php.net/exit): > > exit — Output a message and terminate the current script > > exit is a language construct and it can be called without > parentheses if no status is passed. > > It's not that this a particularly new or novel behaviour. > > I saw somewhere else in the thread that the exit construct could already > throw a catchable exception. I consider that a bug. Considering the whole point of the RFC is to make it a function, I'm not sure why saying the current exit behaviour is not new or novel serves any purpose. Is catching a TypeError a bug? Is catching a ValueError a bug? Is catching any sort of engine Error a bug? Because this is effectively what you are saying, and if this is the case, we might as well just reverse the "Exceptions in the engine" RFC from 2014 [1] to make all those Errors fatal errors again which bail out immediately. This RFC makes exit() a function such that either it exits normally, or a TypeError is thrown if you feed it nonsense, consistently with all our type juggling semantics. Moreover, when exit() was changed to use an Exception internally there were various people in favour of being able to catch it, and have it run finally blocks (like other programming languages do) [2] It should also be noted exit() does not just bail out and do nothing else, any destructors will be run before the exiting, so one can still run userland code after it has been called [3] > I have just checked this for Xdebug, and you're definitely right with > that. With the removal of the ZEND_EXIT opcode, it can not now detect a > scope/function exit now. > > It also breaks my "do tasks on ZEND_EXIT" with the profiler. It is used > to always write the closing profiling footer to the files. Without me > being able to overload thati opcode, data would not be complete. > I even have two bugs (with tests) for this: > > - https://bugs.xdebug.org/68 > - https://bugs.xdebug.org/631 > > Xdebug has been overloading ZEND_EXIT for nearly 20 years now. AFAIK Opcodes are not part of any backwards compatibility guarantees. You could overwrite the function pointer of exit() at MINIT with a custom implementation. Alternatively, you could use the zend_is_unwind_exit() engine API to check if the exception that has been thrown is the one that corresponds to an exit call, this would work as of PHP 8.0. Finally, the one that makes more work for me, is to add a new observer API that indicates an exit() and hook into that one. > > > This could be re-added by checking for the never return type instead. > > > I can't quite see a way on how to do that? The EXIT is replaced by an > INIT_FCALL/DO_ICALL: > > 4 0 E > EXT_STMT > > 1 ECHO '55' > 5 2 EXT_STMT > - 3 > EXIT > > - 6 4* EXT_STMT > - 5* ECHO '675' > - 7 6* EXT_STMT > - 7* > RETURN null > > + 3 INIT_FCALL 'exit' > + 4 DO_ICALL > + 6 5 EXT_STMT > + 6 ECHO '675' > + 7 7 EXT_STMT > + 8 > RETURN null > > > The opcodes don't have direct access to the type mask structure as far > as I know. You can access the zend_function pointer from the opcode which has access to the type-mask info. Or, if required, the Zend/Optimizer/zend_func_infos.h file can be amended to include exit() and die() and expose the MAY_BE_NEVER return type. Best regards, Gina P. Banyard [1] https://wiki.php.net/rfc/engine_exceptions_for_php7 [2] https://externals.io/message/107497 [3] https://3v4l.org/gO9IK
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
On Mon, 27 May 2024, Ilija Tovilo wrote: > On Sun, May 26, 2024 at 11:47 PM Gina P. Banyard > wrote: > > > > On Wednesday, 8 May 2024 at 14:40, Gina P. Banyard > > wrote: > > > > > I would like to formally propose my idea for exit() as a function > > > brought up to the list on 2024-02-24 [1] with the following RFC: > > > https://wiki.php.net/rfc/exit-as-function > > > > As there haven't been any comments for nearly two weeks, I'm > > planning on opening the vote for the RFC on Tuesday. Right now, I am not going to be in favour of this. Specfically because the Backward Incompatible Changes don't list some of the backward breaking changes, and no mitigations are provided. See below. I also don't see the benefit from doing this in the first place. exit/die has always meant "bail straight out", without any function semantics (from https://www.php.net/exit): exit — Output a message and terminate the current script exit is a language construct and it can be called without parentheses if no status is passed. It's not that this a particularly new or novel behaviour. I saw somewhere else in the thread that the exit construct could already throw a catchable exception. I consider that a bug. > As mentioned early on in private, I don't see a convincing reason to > remove tokenizer/parser support for exit/die. I'd rather see this > handled in the parser directly, by converting the standalone keywords > to function calls. This avoids any backwards incompatibility, and > avoids special handling in zend_compile_const. > > Another thing that's probably not too important: The PR likely breaks > dead code elimination for exit() and die(). I have just checked this for Xdebug, and you're definitely right with that. With the removal of the ZEND_EXIT opcode, it can not now detect a scope/function exit now. It also breaks my "do tasks on ZEND_EXIT" with the profiler. It is used to always write the closing profiling footer to the files. Without me being able to overload thati opcode, data would not be complete. I even have two bugs (with tests) for this: - https://bugs.xdebug.org/68 - https://bugs.xdebug.org/631 Xdebug has been overloading ZEND_EXIT for nearly 20 years now. > This could be re-added by checking for the never return type instead. I can't quite see a way on how to do that? The EXIT is replaced by an INIT_FCALL/DO_ICALL: 4 0 E > EXT_STMT 1ECHO'55' 5 2EXT_STMT - 3 > EXIT -6 4* EXT_STMT - 5* ECHO'675' -7 6* EXT_STMT - 7* > RETURN null + 3INIT_FCALL 'exit' + 4DO_ICALL +6 5EXT_STMT + 6ECHO'675' +7 7EXT_STMT + 8 > RETURN null The opcodes don't have direct access to the type mask structure as far as I know. cheers, Derick
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
On Tue, May 28, 2024 at 2:10 PM Gina P. Banyard wrote: > > On Monday, 27 May 2024 at 02:31, Ilija Tovilo wrote: > > > > On Wednesday, 8 May 2024 at 14:40, Gina P. Banyard intern...@gpb.moe > > > wrote: > > > > > > > I would like to formally propose my idea for exit() as a function > > > > brought up to the list on 2024-02-24 [1] with the following RFC: > > > > https://wiki.php.net/rfc/exit-as-function > > > > > > As mentioned early on in private, I don't see a convincing reason to > > remove tokenizer/parser support for exit/die. I'd rather see this > > handled in the parser directly, by converting the standalone keywords > > to function calls. This avoids any backwards incompatibility, and > > avoids special handling in zend_compile_const. > > I must be honest, I don't really understand how parsers work, so I went with > what I could understand and implement. > But I'm struggling to see a reason for keeping the token in the first place, > and what issues hooking into zend_compile_const() has. Mostly because I think handling exit and die as constants is misleading. exit; isn't a constant any more than yield; is. Instead, you could turn exit; into the same AST as exit(); (i.e. a function call), which will make the compiler handle it automatically. If you wish, I can have a quick look. > > Another thing that's probably not too important: The PR likely breaks > > dead code elimination for exit() and die(). This could be re-added by > > checking for the never return type instead. > > Checking for a never return type seems more robust if it wasn't already > supported by DCE. > I will see if I can do this. That would be great! I agree that this can be done in retrospect. Ilija
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
On Monday, 27 May 2024 at 02:31, Ilija Tovilo wrote: > Hi Gina > > On Sun, May 26, 2024 at 11:47 PM Gina P. Banyard intern...@gpb.moe wrote: > > > On Wednesday, 8 May 2024 at 14:40, Gina P. Banyard intern...@gpb.moe wrote: > > > > > I would like to formally propose my idea for exit() as a function brought > > > up to the list on 2024-02-24 [1] with the following RFC: > > > https://wiki.php.net/rfc/exit-as-function > > > > As there haven't been any comments for nearly two weeks, I'm planning on > > opening the vote for the RFC on Tuesday. > > > As mentioned early on in private, I don't see a convincing reason to > remove tokenizer/parser support for exit/die. I'd rather see this > handled in the parser directly, by converting the standalone keywords > to function calls. This avoids any backwards incompatibility, and > avoids special handling in zend_compile_const. I must be honest, I don't really understand how parsers work, so I went with what I could understand and implement. But I'm struggling to see a reason for keeping the token in the first place, and what issues hooking into zend_compile_const() has. > > Another thing that's probably not too important: The PR likely breaks > dead code elimination for exit() and die(). This could be re-added by > checking for the never return type instead. Checking for a never return type seems more robust if it wasn't already supported by DCE. I will see if I can do this. > You'd also need to > special-case the lookup of exit/die in namespaced code, where it will > always refer to the global function (as they cannot be declared in > userland). This is a pre-existing issue with assert() too then, I am happy to fix this at the same time if the RFC passes. Best regards, Gina P. Banyard
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
On Monday, 27 May 2024 at 19:10, Claude Pache wrote: > Hi Gina, > > It is ok, for `exit` to be wired to a function. However, the paren-less > `exit` syntax is absolutely reasonable and should be kept in the long term > (more on this below). It is true that your proposal doesn’t remove the > paren-less form, but the implementation (a hack around constant evaluation) > strongly suggests that it is desirable to deprecate it in the future (hey, it > is even the very first item of the `Future scope` section). Therefore, I > think it is preferable to keep proper parsing rules for `exit`. > > Now here is why I think that `exit` syntax without parentheses is reasonable. > For me, `exit` is a control-flow instruction, saying to terminate the > program, just like `return` terminates a function or `break` terminates a > loop. I don’t care about implementation details, whether it is implemented as > invoking a never-returning function, or as throwing a hidden exception, or > whatever. The fact is, in typical use: > > `php header("Location: /somewhere/else.php"); exit;` > > I would consider an oddity and useless noise to put empty parentheses after a > bare `exit`, just as I wouldn’t consider to put empty parentheses after a > bare `return`. > > (BTW... I wouldn’t describe a bare `yield` (equivalent to `yield null`) as > “constant” evaluation, even if it may be found in same positions as a “real” > constant.) > > —Claude Adding something to Future Scope does not mean I will pursue this, this is just a possible direction that can be done and needs to be argued on its own merits. And frankly I have no intension on pushing this, I would _rather_ remove support for passing strings to exit() than removing the paren-less form. It should be noted that in other programming languages, exit() is a function that requires an argument for the status code. So I don't think of it as a control-flow instruction (because I don't see terminating something as control flow) but if that's how you see it fine. If that's the only reason for keeping proper parsing rules, I'm not sure whether that's worthwhile IMHO. Best regards, Gina P. Banyard
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
On Tuesday, 28 May 2024 at 07:53, Daikaras wrote: > > I feel like the reasoning in this RFC is misguided. `exit` behavior is > not consistent with functions because it is not a function. But it is > consistent with constructs like `echo`. Or am I wrong? I'm all for > stricter typing but not at a cost of reliability. `exit` IMO should > always terminate script, no exceptions (no pun intended :)). Otherwise, > it may have security implications in some codebases, as Saki pointed > out. So I'd rather have it error fatally like for example `break` does > when passed non-integers. And on the same note maybe syntax could be > improved to not require parentheses when passing the code (so `exit 0;` would > be valid) since it seems to be the cause of the confusion. > > Just my 2c. > > p.s. In B/C table you should mention that passing Stringable objects > will throw TypeError when `strict_types` are enabled. This is not the cause of my confusion. If you had read the RFC carefully, you would have seen that exit() already throws a TypeError that can be caught if you pass in a non-stringable object. So the argument that it should always exit is invalid. Moreover, in other programming languages exit() is a function, and I don't see a reason for having something be a language construct when there is no need for it. Best regards, Gina P. Banyard
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function PHP internals
On 2024.05.08 16:40, Gina P. Banyard wrote: Hello Internals, I would like to formally propose my idea for exit() as a function brought up to the list on 2024-02-24 [1] with the following RFC: https://wiki.php.net/rfc/exit-as-function There have been some slight tweaks to the implementation, namely that the transformation from a "constant" to a function is done at compile time and we do not hook into the behaviour of constants any longer. Let me know what you think. Best regards, Gina P. Banyard [1] https://externals.io/message/122483 I don't quite get the reasoning behind this change. `exit` behavior is not consistent with functions because it is not a function. But it is consistent with other constructs like `echo`. Or am I wrong? I'm all for stricter typing but not at a cost of reliability. `exit` IMO should always terminate script, no exceptions (no pun intended :)). Otherwise, it may have security implications in some codebases, as Saki pointed out. So I'd rather go the other way and have it error fatally like for example `break` does when passed non-integers. And on the same note maybe syntax could be improved to *not* require parentheses when passing the code (so `exit 0;` would be valid code) since this seems to be the cause of the confusion. Just my 2c. p.s. In B/C table you should mention that passing Stringable objects will throw TypeError when `strict_types` is enabled.
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
Hi Gina On Sun, May 26, 2024 at 11:47 PM Gina P. Banyard wrote: > > On Wednesday, 8 May 2024 at 14:40, Gina P. Banyard wrote: > > > > > I would like to formally propose my idea for exit() as a function brought > > up to the list on 2024-02-24 [1] with the following RFC: > > https://wiki.php.net/rfc/exit-as-function > > As there haven't been any comments for nearly two weeks, I'm planning on > opening the vote for the RFC on Tuesday. As mentioned early on in private, I don't see a convincing reason to remove tokenizer/parser support for exit/die. I'd rather see this handled in the parser directly, by converting the standalone keywords to function calls. This avoids any backwards incompatibility, and avoids special handling in zend_compile_const. Another thing that's probably not too important: The PR likely breaks dead code elimination for exit() and die(). This could be re-added by checking for the never return type instead. You'd also need to special-case the lookup of exit/die in namespaced code, where it will always refer to the global function (as they cannot be declared in userland). Ilija
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
On Tuesday, 14 May 2024 at 17:24, Juliette Reinders Folmer wrote: > On 11-5-2024 16:43, Gina P. Banyard wrote: > >> On Thursday, 9 May 2024 at 15:17, Jorg Sowa >> [](mailto:jorg.s...@gmail.com) wrote: >> I don't think there are any other "functions" like this. >>> What about list(), isset(), print(), echo(), require(), include(), unset(), >>> empty()? We use them the same way as functions, but those are not real >>> functions. >> >> list() (and array()) may look like functions but do not behave like one as >> they affect the current scope by setting various variables. >> >> isset()/empty()/unset() require to work with undefined variables and have >> deeply ingrained behaviour within the engine, so making them simple >> functions is not as much of a "trivial" change. >> >> print, echo, include(_once) and require(_once) do not mandate their >> "argument" to be passed within parenthethis, so making them functions does >> not simplify the lexer/parser nor removes them as keywords. >> Also I don't know the last time I've used those language constructs "like a >> function". > > Seeing this list, makes me wonder: what about eval() ? eval() might make sense to try and convert to a function, this would probably also cleany solve the complaint about not being able to disable eval() [1][2] Best regards, Gina P. Banyard [1] https://bugs.php.net/bug.php?id=62397 [2] https://github.com/php/php-src/pull/4084
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
On 11-5-2024 16:43, Gina P. Banyard wrote: On Thursday, 9 May 2024 at 15:17, Jorg Sowa wrote: > I don't think there are any other "functions" like this. What about list(), isset(), print(), echo(), require(), include(), unset(), empty()? We use them the same way as functions, but those are not real functions. list() (and array()) may look like functions but do not behave like one as they affect the current scope by setting various variables. isset()/empty()/unset() require to work with undefined variables and have deeply ingrained behaviour within the engine, so making them simple functions is not as much of a "trivial" change. print, echo, include(_once) and require(_once) do not mandate their "argument" to be passed within parenthethis, so making them functions does not simplify the lexer/parser nor removes them as keywords. Also I don't know the last time I've used those language constructs "like a function". Seeing this list, makes me wonder: what about eval() ?
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
On 11 May 2024 15:43:19 BST, "Gina P. Banyard" wrote: >print, echo, include(_once) and require(_once) do not mandate their "argument" >to be passed within parenthethis, so making them functions does not simplify >the lexer/parser nor removes them as keywords. It's actually a much stronger difference than that: parentheses are not parsed as surrounding the argument lists for those keywords at all. A while ago, I added notes to the manual pages of each showing how this can lead to misleading code, e.g. one of the examples on https://www.php.net/print is this: print(1 + 2) * 3; // outputs "9"; the parentheses cause 1+2 to be evaluated first, then 3*3 // the print statement sees the whole expression as one argument echo has further peculiarities, because it takes an unparenthesised list of arguments, and can't be used in an expression. While it would probably have been better if those had been parsed like functions to begin with, changing them now would not just be pointless, it would be actively dangerous, changing the behaviour of existing code. Regards, Rowan Tommins [IMSoP]
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
On Thursday, 9 May 2024 at 16:18, Saki Takamachi wrote: > Hi Gina, > > > Hello Internals, > > > > I would like to formally propose my idea for exit() as a function brought > > up to the list on 2024-02-24 [1] with the following RFC: > > https://wiki.php.net/rfc/exit-as-function > > > > There have been some slight tweaks to the implementation, namely that the > > transformation from a "constant" to a function is done at compile time and > > we do not hook into the behaviour of constants any longer. > > > > Let me know what you think. > > > > Best regards, > > > > Gina P. Banyard > > > > [1] https://externals.io/message/122483 > > > I generally agree :) > > My only concern is that if this function throws an error and I catch it, > won't it proceed against the user's intentions about it. I am concerned that > this may lead to data corruption and personal information leaks due to > unintentional data being inserted into the DB. > > `try { exit([]); } catch (Throwable) { // }` > > Probably no one likes to write code like this, and even if there are, there > are probably very few, but code that is written with the assumption that exit > will always stop processing may be a little dangerous. > > Is it nonsense to always stop processing even if an error occurs? Or, how > about creating an uncatchable exception class specifically for exits? Or is > this level of risk negligible? > > I am writing down the ideas I came up with, so please excuse me if there are > any mistakes in my understanding. > > Regard, > > Saki You can already escape an exit() call, either by setting an error handler that throws, or by passing a non-stringable object. See: https://3v4l.org/vR3up Best regards, Gina P. Banyard
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
On Thursday, 9 May 2024 at 15:17, Jorg Sowa wrote: >> I don't think there are any other "functions" like this. > What about list(), isset(), print(), echo(), require(), include(), unset(), > empty()? We use them the same way as functions, but those are not real > functions. > Kind regards, > Jorg list() (and array()) may look like functions but do not behave like one as they affect the current scope by setting various variables. isset()/empty()/unset() require to work with undefined variables and have deeply ingrained behaviour within the engine, so making them simple functions is not as much of a "trivial" change. print, echo, include(_once) and require(_once) do not mandate their "argument" to be passed within parenthethis, so making them functions does not simplify the lexer/parser nor removes them as keywords. Also I don't know the last time I've used those language constructs "like a function". Hope this clarifies things. Best regards, Gina P. Banyard
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
On Saturday, 11 May 2024 at 09:05, Juliette Reinders Folmer wrote: > On 8-5-2024 15:40, Gina P. Banyard wrote: > >> I would like to formally propose my idea for exit() as a function brought up >> to the list on 2024-02-24 [1] with the following RFC: >> https://wiki.php.net/rfc/exit-as-function >> There have been some slight tweaks to the implementation, namely that the >> transformation from a "constant" to a function is done at compile time and >> we do not hook into the behaviour of constants any longer. > > No objections from my side, though, yes, PHPCS will need to be > updated/adjusted to work around this, but that's no biggie. > > When reading the RFC, there are two things about which I still have questions. > > 1. As things are, `exit` and `die` cannot be used as a label for a goto > statement. > > ```php > goto exit; > > exit: > echo 'exited'; > ``` > https://3v4l.org/fluuk and https://3v4l.org/cNMEW > > Will that change now `exit` would no longer be a reserved keyword ? I had not thought about goto labels, but indeed it would be possible to use exit and die as goto labels with this RFC. I have clarrified this change in the RFC text and added tests for this in the PR. > 2. The RFC mentions the "old" semantics regarding type juggling for exit/die > - always cast to string - and it mentions that passing resources or arrays in > the new situation will become a TypeError, but that still leaves some room > for interpretation for the other types, in particular the handling of > booleans. > > How I read the RFC, the type juggling would change as follows (but I may well > be wrong!): > > | Param passed | Old | New | Consequences | > |---|-|---|---| > | integer | integer | integer | No change, interpreted as exit code | > | string | string | string | No change, interpreted as status message | > | bool | string | integer | Was status message, now exit code | > | float | string | integer | Was status message, now exit code, "Implicit > conversion from float to int loses precision" deprecation notice | > | null | string | integer | Was status message, now exit code, "Passing null > to parameter #1 ($status) of type string\|int is deprecated" | > | stringable object | string | string | No change, interpreted as status > message | > | non-stringable object | string | TypeError | | > | array | string | TypeError | | > | resource | string | TypeError | | > > Might it be an idea to make all the type juggling changes explicit in the RFC > ? (and correct whatever I interpreted incorrectly) I have done so, and fixed the one case you got wrong. Best regards, Gina P. Banyard
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
On 8-5-2024 15:40, Gina P. Banyard wrote: I would like to formally propose my idea for exit() as a function brought up to the list on 2024-02-24 [1] with the following RFC: https://wiki.php.net/rfc/exit-as-function There have been some slight tweaks to the implementation, namely that the transformation from a "constant" to a function is done at compile time and we do not hook into the behaviour of constants any longer. No objections from my side, though, yes, PHPCS will need to be updated/adjusted to work around this, but that's no biggie. When reading the RFC, there are two things about which I still have questions. 1. As things are, `exit` and `die` cannot be used as a label for a goto statement. ```php goto exit; exit: echo 'exited'; ``` https://3v4l.org/fluuk and https://3v4l.org/cNMEW Will that change now `exit` would no longer be a reserved keyword ? 2. The RFC mentions the "old" semantics regarding type juggling for exit/die - always cast to string - and it mentions that passing resources or arrays in the new situation will become a TypeError, but that still leaves some room for interpretation for the other types, in particular the handling of booleans. How I read the RFC, the type juggling would change as follows (but I may well be wrong!): | Param passed | Old | New | Consequences | |---|-|---|---| | integer | integer | integer | No change, interpreted as exit code | | string| string | string| No change, interpreted as status message | | bool | string | integer | Was status message, now exit code | | float | string | integer | Was status message, now exit code, "Implicit conversion from float to int loses precision" deprecation notice | | null | string | integer | Was status message, now exit code, "Passing null to parameter #1 ($status) of type string\|int is deprecated" | | stringable object | string | string| No change, interpreted as status message | | non-stringable object | string | TypeError | | | array | string | TypeError | | | resource | string | TypeError | | Might it be an idea to make all the type juggling changes explicit in the RFC ? (and correct whatever I interpreted incorrectly) Smile, Juliette
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
Hi Tim, > This is already the case. `exit` throws an internal uncatchable Exception. > Quoting from the RFC: Thanks, I had overlooked that. I have no other concerns. Regards, Saki
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
Hi On 5/9/24 17:18, Saki Takamachi wrote: Is it nonsense to always stop processing even if an error occurs? Or, how about creating an uncatchable exception class specifically for exits? Or is this level of risk negligible? This is already the case. `exit` throws an internal uncatchable Exception. Quoting from the RFC: Finally, the need for exit() to be a language construct with its own dedicated opcode is not a requirement any more since PHP 8.0 as the opcode throws a special kind of exception which cannot be caught, 2) nor executes finally blocks, to unwind the stack normally. Best regards Tim Düsterhus
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
Hi On 5/9/24 16:27, Larry Garfield wrote: I support this. My only question (which applies to current exit() as well), is what the exit code is when you pass a string as the parameter. That's not clear from the exit() docs currently, but the RFC made me wonder. (This may be just a doc fix and we move on with life.) If a string is passed, the exit_status is left untouched [1]. In practice this should always result in an exit status of 0, because I can't see how the exit_status would be non-zero before `exit("foo");` successfully executes. Best regards Tim Düsterhus [1] https://github.com/php/php-src/blob/f88fc9c6e8262fe48eb9cf078e32e63af19047f2/Zend/zend_vm_def.h#L7541-L7570
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
Hi On 5/9/24 16:17, Jorg Sowa wrote: I don't think there are any other "functions" like this. What about list(), isset(), print(), echo(), require(), include(), unset(), empty()? We use them the same way as functions, but those are not real functions. All of them require to be followed by an expression (or some other non-empty token), thus they do not act like constants the same way 'exit' and 'die' do: - unset, isset, empty, list must be followed by '('. - echo is a statement and needs to be terminated with ';'. - print is an expression and requires a single non-empty expression. - The include family is an expression and requires a single non-empty expression. Best regards Tim Düsterhus PS: Today I learned that echo and print are not aliases.
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
Hi Gina, > Hello Internals, > > I would like to formally propose my idea for exit() as a function brought up > to the list on 2024-02-24 [1] with the following RFC: > https://wiki.php.net/rfc/exit-as-function > > There have been some slight tweaks to the implementation, namely that the > transformation from a "constant" to a function is done at compile time and we > do not hook into the behaviour of constants any longer. > > Let me know what you think. > > Best regards, > > Gina P. Banyard > > [1] https://externals.io/message/122483 I generally agree :) My only concern is that if this function throws an error and I catch it, won't it proceed against the user's intentions about it. I am concerned that this may lead to data corruption and personal information leaks due to unintentional data being inserted into the DB. ``` try { exit([]); } catch (Throwable) { // } ``` Probably no one likes to write code like this, and even if there are, there are probably very few, but code that is written with the assumption that exit will always stop processing may be a little dangerous. Is it nonsense to always stop processing even if an error occurs? Or, how about creating an uncatchable exception class specifically for exits? Or is this level of risk negligible? I am writing down the ideas I came up with, so please excuse me if there are any mistakes in my understanding. Regard, Saki
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
On Wed, May 8, 2024, at 1:40 PM, Gina P. Banyard wrote: > Hello Internals, > > I would like to formally propose my idea for exit() as a function > brought up to the list on 2024-02-24 [1] with the following RFC: > https://wiki.php.net/rfc/exit-as-function > > There have been some slight tweaks to the implementation, namely that > the transformation from a "constant" to a function is done at compile > time and we do not hook into the behaviour of constants any longer. > > Let me know what you think. > > Best regards, > > Gina P. Banyard > > [1] https://externals.io/message/122483 I support this. My only question (which applies to current exit() as well), is what the exit code is when you pass a string as the parameter. That's not clear from the exit() docs currently, but the RFC made me wonder. (This may be just a doc fix and we move on with life.) --Larry Garfield
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
> I don't think there are any other "functions" like this. What about list(), isset(), print(), echo(), require(), include(), unset(), empty()? We use them the same way as functions, but those are not real functions. Kind regards, Jorg
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
On Thu, 9 May 2024, Flávio Heleno wrote: > On Thu, May 9, 2024 at 7:51 AM Niels Dossche > wrote: > > > On 08/05/2024 15:40, Gina P. Banyard wrote: > > > Hello Internals, > > > > > > I would like to formally propose my idea for exit() as a function > > > brought up to the list on 2024-02-24 [1] with the following RFC: > > > https://wiki.php.net/rfc/exit-as-function > > > > > > There have been some slight tweaks to the implementation, namely > > > that the transformation from a "constant" to a function is done at > > > compile time and we do not hook into the behaviour of constants > > > any longer. > > > > > > Let me know what you think. > > > > Thanks for proposing this, I'm in favor of this change because this > > creates more consistency. > > Is there a list of other "functions" that are handled as "constants"? I don't think there are any other "functions" like this. That's why removing the special case for "exit" and "die" is a good idea. cheers, Derick
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
On Thu, May 9, 2024 at 7:51 AM Niels Dossche wrote: > On 08/05/2024 15:40, Gina P. Banyard wrote: > > Hello Internals, > > > > I would like to formally propose my idea for exit() as a function > brought up to the list on 2024-02-24 [1] with the following RFC: > > https://wiki.php.net/rfc/exit-as-function > > > > There have been some slight tweaks to the implementation, namely that > the transformation from a "constant" to a function is done at compile time > and we do not hook into the behaviour of constants any longer. > > > > Let me know what you think. > > > > Best regards, > > > > Gina P. Banyard > > > > [1] https://externals.io/message/122483 > > Hi Gina > > Thanks for proposing this, I'm in favor of this change because this > creates more consistency. > > Kind regards > Niels > Hi all, Is there a list of other "functions" that are handled as "constants"? -- Atenciosamente, Flávio Heleno
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
On 08/05/2024 15:40, Gina P. Banyard wrote: > Hello Internals, > > I would like to formally propose my idea for exit() as a function brought up > to the list on 2024-02-24 [1] with the following RFC: > https://wiki.php.net/rfc/exit-as-function > > There have been some slight tweaks to the implementation, namely that the > transformation from a "constant" to a function is done at compile time and we > do not hook into the behaviour of constants any longer. > > Let me know what you think. > > Best regards, > > Gina P. Banyard > > [1] https://externals.io/message/122483 Hi Gina Thanks for proposing this, I'm in favor of this change because this creates more consistency. Kind regards Niels
Re: [PHP-DEV] [RFC] Transform exit() from a language construct into a standard function
Hi On 5/8/24 15:40, Gina P. Banyard wrote: Let me know what you think. The fewer not-actually-a-function functions, the better. I don't have any remarks and I'm in favor. Best regards Tim Düsterhus