Re: [VOTE] Dump results of expressions in `php -a`
| From: | tyson andre | Date: | Wed, 03 Feb 2021 14:39:51 +0000 |
| Subject: | Re: [VOTE] Dump results of expressions in `php -a` | ||
| References: | 1 2 3 4 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-113058@lists.php.net to get a copy of this message | ||
Hi Bob Weinand,
>>>> Voting has started on
>>>> https://wiki.php.net/rfc/readline_interactive_shell_result_function
>>>> on 2021-01-19, and ends on 2021-02-02.
>>>>
>>>> This RFC proposes to dump the results of non-null expressions using
>>>> var_dump/var_export() by default in
php -a (the interactive shell).
>>>> Additionally, this adds a new function
>>>> readline_interactive_shell_result_function to the readline PHP
>>>> module.
>>>> This function only affects interactive shells - it can optionally be used to set or
>>>> clear a closure when extension_loaded('readline') ===
>>>> true,
>>>> but that closure would only be called in interactive shells (i.e. php -a).
>>>> (That closure would be called instead of the native implementation with the snippet
>>>> of code that was evaluated and the expression's result,
>>>> if a php statement contained a single expression such as
>>>> 2+2; or $x = [1,2]; (that could be
>>>> used as the expression of a return statement)
>>>> - Dumping of expression results can be disabled using an ini setting or at runtime
>>>>
>>>> Thanks,
>>>> - Tyson
>>>
>>> Hey Tyson,
>>>
>>> My main concern in this iteration of the RFC is: what happens with big/deeply nested
>>> objects?
>>> They tend to spew tons of lines if var_dump()'ed. Do we have reasonable
>>> depth/output limitations in default dumping mode?
>>>
>>> I'm often enough using php -a to do some quick ad-hoc processing (example, read a
>>> big json file, and then access a value; instantiating a mediawiki bot framework and calling replace
>>> on it; ...).
>>>
>>> It's really cool to have any interactive feedback at all, but please, at least by
>>> default, limit the output. (An example is the JS REPL in browser console - it shows you a minimal
>>> preview of the object, and then you can expand with your mouse. Obviously with a pure cli
>>> application, this needs different - intuitive - navigation.)
>>>
>>> As it currently stands, this makes php -a unusable in any but the simplest cases,
>>> without just disabling the whole feature.
>>>
>>> I like the whole feature, but the missing output limitation (I have yet enough
>>> nightmares from var_dump()'ing the wrong object filling my shell with tons of irrelevant
>>> information… I don't need that potentially happening on every single evaluated expression)
>>>
>>> Thus I'm voting no, for now.
>>
>> As-is, the entire object or string would be dumped with var_export/var_dump to stdout.
>>
>> Thoughts on the adding following output truncation mechanism
>> (for the default C result dumper implementation)
>> before printing the results of the returned expression
>> (the user output continues to be untruncated, and the existence of cli.pager
>> would not affect this mechanism in case the binary is not actually a pager)?
>> For arrays/objects used with var_dump - the equivalent of
>> ob_start(); var_dump($result); $result = ob_get_clean();
>> would have to be used first from C since var_dump still writes to the output buffer
>> (php_printf(), etc.)
>
>var_dump() tends to be quite intensive in newline usage. I don't think var_dump() (as is)
>is the best mechanism to print. At least I'd use one property/one array argument = single line
>instead of two lines.
>Additionally, when dumping a nested object, it's more valuable to see as much as possible
>from the primary object rather than the deep nesting.
>
>
>> I'd omitted output truncation from the RFC because I wasn't sure how many people
>> would consider it excessive to include a limit on var_dump output, and there was little
>> feedback before the RFC vote started.
>
>Yeah, sorry for the late comment on that :-)
>
>> The simplest implementation would be to truncate to a byte limit and append
>> ... if truncated,
>> but the main concern that's been brought up is the approximate number of lines.
>> Obviously, there'd be a value in truncating the output if there were to be megabytes
>> of output,
>> though exactly what settings make sense as a default would vary.
>
>As mentioned a section earlier, there should be limits according to the nesting-level … e.g.
>if it's the top-level value, a string may have 20 lines printed and array and objects as well.
>And array entries/properties should then be in a single line or take up to max ... 20 /
>count(properties or array entries) lines (width before truncation can be determine from terminal
>width), which then can be mostly in one line flattened output.
>The general rule here should be, show me my object/array at hand and give me a brief overview of
>what's nested within - and if I'm interested in detail, let me (manually) output that
>object.
>Also consider, when dumping strings within (nested) arrays/objects to replace newlines with \n,
>for nicer display.
>
>> C would not print anything (e.g. => ) or even call
>> var_dump/var_export if the limits were set to 0.
>>
>> ```
>> <?php
>>
>> const ASSUMED_BYTES_PER_LINE = 80;
>> const ASSUMED_TAB_WIDTH = 4;
>
>On that topic, may make sense to also fetch the actual terminal width and heights respectively
>(ioctl TIOCGWINSZ).
>I.e. if terminal is 20 lines high, printing 20 lines is a lot. if it's 80 lines high, 20
>lines is acceptable.
>
>> // unmodified
>> var_dump(truncate_string("test short string"));
>> // 5000 'A's followed by "...\n"
>> var_dump(truncate_string(str_repeat('A', 10000)));
>> // 100 lines containing "A" followed by "...\n"
>> var_dump(truncate_string(str_repeat("A\n", 10000)));
>> ```
>
>I'd wager nobody needs a hundred lines, I'd use inspiration from debuggers which
>typically show 5-20 lines max.
>IF you want to print it all, it's just as easy as echo
>$var; though.
>
>So overall: try to make efficient usage of horizontal as well as vertical space while still
>remaining usable and readable.
I'm not sure if I want to do anything that complicated or if there'd be a consensus on how
to indent each level.
Having the same rules at any indent level would be my preference.
Another idea I'd had would be to add a new function
var_dump_as_string(mixed $value, int $use_placeholders_after_lines = -1, int
$use_placeholders_after_lines = -1) to
1. Escape control characters in the same way as the proposed var_representation
2. Replace remaining fields with ... if the line limits or byte limits would be
exceeded by adding a key-value pair
in arrays/objects that have more fields. (go back and truncate the string if necessary)
3. Possibly revisit other representation choices, e.g. put values on the same lines as keys
```
php > echo var_dump_as_string(range(0,99), use_placeholder_after_lines: 5);
array(100) {
[0]=>int(0)
[1]=>int(1)
...
}
php > var_dump("a\n\"b");
string(4) "a
"b"
php > echo var_dump_as_string("a\n\"b");
string(4) "a\n\"b"
```
This would have the following benefits:
1. In addition to being usable in an interactive shell/REPL,
it would be possible to use this in other libraries/applications where dumping too much debug
output is a concern,
or to invoke it manually (e.g. through a userland wrapper function v($value)) when
debugging.
(where recursion detection and object ids are useful to have when debugging)
2. Performance and memory usage would be less of a concern when dumping extremely large objects.
3. This would avoid the chance of mixing php code output from __debugInfo/notices with
the outputted string,
which is possible with ob_start()/ob_get_clean()
4. Avoid mixing in control characters such as newlines with debug output when a var_dump-like
representation is needed.
-Tyson