rfc:readable_var_representation

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
rfc:readable_var_representation [2021/01/23 20:56] tandrerfc:readable_var_representation [2021/02/19 15:19] (current) – vote declined tandre
Line 1: Line 1:
 ====== PHP RFC: var_representation() : readable alternative to var_export() ====== ====== PHP RFC: var_representation() : readable alternative to var_export() ======
-  * Version: 0.2+  * Version: 0.3
   * Date: 2021-01-22   * Date: 2021-01-22
   * Author: Tyson Andre, tandre@php.net   * Author: Tyson Andre, tandre@php.net
-  * Status: Under Discussion+  * Status: Declined
   * First Published at: http://wiki.php.net/rfc/readable_var_representation   * First Published at: http://wiki.php.net/rfc/readable_var_representation
   * Implementation: https://github.com/php/php-src/pull/6619 (currently using another name)   * Implementation: https://github.com/php/php-src/pull/6619 (currently using another name)
Line 25: Line 25:
   - Always render empty lists on a single line instead of two lines.   - Always render empty lists on a single line instead of two lines.
   - Prepend ''\'' to class names so that generated code snippets can be used in namespaces without any issues.   - Prepend ''\'' to class names so that generated code snippets can be used in namespaces without any issues.
-  - Support the bit flag ''VAR_REPRESENTATION_SINGLE_LINE=1'' in a new optional parameter ''int $flags = 0'' accepting a bitmask. If the value of $flags includes this flags, ''var_representation()'' will return a single-line representation for arrays/objects, though strings with embedded newlines will still cause newlines in the output.+  - Support the bit flag ''VAR_REPRESENTATION_SINGLE_LINE=1'' in a new optional parameter ''int $flags = 0'' accepting a bitmask. If the value of $flags includes this flags, ''var_representation()'' will return a single-line representation for arrays/objects.
  
 <code php> <code php>
Line 49: Line 49:
 php > echo var_representation([]);  // always print zero-element arrays without a newline php > echo var_representation([]);  // always print zero-element arrays without a newline
 [] []
 +// lines are indented by a multiple of 2, similar to var_export but not exactly the same
 +php > echo var_representation([(object) ['key' => (object) ['inner' => [1.0], 'other' => new ArrayObject([2])], 'other' => false]]);
 +[
 +  (object) [
 +    'key' => (object) [
 +      'inner' => [
 +        1.0,
 +      ],
 +      'other' => \ArrayObject::__set_state([
 +        2,
 +      ]),
 +    ],
 +    'other' => false,
 +  ],
 +]
 </code> </code>
  
Line 62: Line 77:
   'x' => null,   'x' => null,
 ] ]
 +
 +
 </code> </code>
  
Line 197: Line 214:
   * You are generating a snippet of code to ''eval()'' in a situation where the snippet will occasionally or frequently be read by a human - see the section [[#supporting_namespaces|Supporting Namespaces]]. (If the output never needs to be read by a human, ''return unserialize(' . var_export(serialize($data), true) . ');'' can be used)   * You are generating a snippet of code to ''eval()'' in a situation where the snippet will occasionally or frequently be read by a human - see the section [[#supporting_namespaces|Supporting Namespaces]]. (If the output never needs to be read by a human, ''return unserialize(' . var_export(serialize($data), true) . ');'' can be used)
   * The output is occasionally or frequently read by humans (e.g. CLI or web app output, a REPL, unit test output, etc.).    * The output is occasionally or frequently read by humans (e.g. CLI or web app output, a REPL, unit test output, etc.). 
-  * The output contains control characters such as newlines, tabs, ''\r'' or ''\x00'' and may be viewed or edited by other users in a text editor/IDE. Many IDEs may convert from windows line endings (''\r\n'') to unix line endings(''\r\n'') automatically.+  * The output contains control characters such as newlines, tabs, ''\r'' or ''\x00'' and may be viewed or edited by other users in a text editor/IDE. Many IDEs may convert from windows line endings (''\r\n'') to unix line endings(''\n'') (or vice versa) automatically.
   * You want to unambiguously see control characters in the raw output regardless of how likely they are (e.g. dumping php ini settings, debugging mysterious test failures, etc)   * You want to unambiguously see control characters in the raw output regardless of how likely they are (e.g. dumping php ini settings, debugging mysterious test failures, etc)
   * You are writing unit tests for applications supporting PHP 8.1+ (or a var_representation polyfill) that test the exact string representation of the output (e.g. phpt tests of php-src and PECL extensions) - see the section [[#printing_to_stdout_by_default_or_configurably|Printing to stdout by default or configurably]].   * You are writing unit tests for applications supporting PHP 8.1+ (or a var_representation polyfill) that test the exact string representation of the output (e.g. phpt tests of php-src and PECL extensions) - see the section [[#printing_to_stdout_by_default_or_configurably|Printing to stdout by default or configurably]].
Line 330: Line 347:
  
 Adding more flags here would increase the scope of the rfc and complexity of implementing the change and for reviewing/understanding the implementation. Adding more flags here would increase the scope of the rfc and complexity of implementing the change and for reviewing/understanding the implementation.
 +
 +=== Supporting an indent option ===
 +
 +This was left out since I felt it would increase the scope of the RFC too much.
 +
 +If  an ''indent'' option might be supported by also allowing ''var_representation(value: $value, flags: ['flags' => VAR_REPRESENTATION_SINGLE_LINE, 'indent' => "\t"])'' or by bitmask flags such as ''VAR_REPRESENTATION_INDENT_FOUR_SPACES''/''VAR_REPRESENTATION_INDENT_TABS''/''VAR_REPRESENTATION_INDENT_NONE''.
 +
 +The fact that embedded newlines are now no longer emitted as parts of strings makes it easier to efficiently convert the indentation to spaces or tabs using ''preg_replace'' or ''preg_replace_callback''
 +
 +<code php>
 +php > echo var_representation([[['key' => 'value  with  space']]]);
 +[
 +  [
 +    [
 +      'key' => 'value  with  space',
 +    ],
 +  ],
 +]
 +php > echo preg_replace('/^((  )+)/m', '\1\1', var_representation([[['key' => 'value  with  space']]]));
 +[
 +    [
 +        [
 +            'key' => 'value  with  space',
 +        ],
 +    ],
 +]
 +</code>
 +````
  
 ==== Adding magic methods such as __toRepresentation() to PHP ==== ==== Adding magic methods such as __toRepresentation() to PHP ====
Line 347: Line 392:
 It may be useful to override this string representation through additional flags, callbacks, or other mechanisms. It may be useful to override this string representation through additional flags, callbacks, or other mechanisms.
 However, I don't know if there's widespread interest in that, and this would increase the scope of this RFC. However, I don't know if there's widespread interest in that, and this would increase the scope of this RFC.
 +
 +==== Emitting code comments in result about references/types/recursion ====
 +
 +Adding a comment such as ''/* resource(2) of type (stream) */ null'' to the var_representation output with an opt-in flag (e.g. ''VAR_REPRESENTATION_ADD_TYPE_COMMENTS'') to add this information may be useful to explore in follow-up work (to meet more use cases of ''var_dump'').
 +
 +(Or ''/* RECURSION  */ NULL'', or ''[/* reference */ 123, /* reference */ 123]'', etc.)
  
 ===== Discussion ===== ===== Discussion =====
Line 419: Line 470:
 The last time ''var_export()'' changed was from ''<nowiki>stdClass::__set_state(array())</nowiki>'' to ''(object) []'' in PHP 7.3.0, but that was something that had a clearer reason to fix - ''<nowiki>stdClass::__set_state</nowiki>'' is an undeclared function and many users were inconvenienced by being unable to generate code for stdClass instances. The last time ''var_export()'' changed was from ''<nowiki>stdClass::__set_state(array())</nowiki>'' to ''(object) []'' in PHP 7.3.0, but that was something that had a clearer reason to fix - ''<nowiki>stdClass::__set_state</nowiki>'' is an undeclared function and many users were inconvenienced by being unable to generate code for stdClass instances.
  
-===== Proposed Voting Choices ===== +===== Vote ===== 
-Yes/No, requiring 2/3 majority.+This is a Yes/No vote, requiring 2/3 majority. Voting started on 2021-02-05 and ended 2021-02-19. 
 + 
 +<doodle title="Add var_representation($value, int $flags=0): string to php?" auth="tandre" voteType="single" closed="true"> 
 +   * Yes 
 +   * No 
 +</doodle>
  
 ===== References ===== ===== References =====
Line 577: Line 633:
   - This may be much slower and end users may not expect that - a lot of small stream writes with dynamic C function calls would be something I'd expect to take much longer than converting to a string then writing to the stream.  (e.g. I assume a lot of small echo $str; is much faster than ''\fwrite(\STDOUT, $str);'' in the internal C implementation) (if we call ''->serialize()'' first, then there's less of a reason to expose ''->serializeFile()'' and ''->serializeStream()'')   - This may be much slower and end users may not expect that - a lot of small stream writes with dynamic C function calls would be something I'd expect to take much longer than converting to a string then writing to the stream.  (e.g. I assume a lot of small echo $str; is much faster than ''\fwrite(\STDOUT, $str);'' in the internal C implementation) (if we call ''->serialize()'' first, then there's less of a reason to expose ''->serializeFile()'' and ''->serializeStream()'')
   - Adding even more ways to dump to a stream/file. Should that include stream wrappers such as http://?  For something like XML/YAML/CSV, being able to write to a file makes sense because those are formats many other applications/languages can consume, which isn't the case for var_export.   - Adding even more ways to dump to a stream/file. Should that include stream wrappers such as http://?  For something like XML/YAML/CSV, being able to write to a file makes sense because those are formats many other applications/languages can consume, which isn't the case for var_export.
 + 
 +==== Changing var_dump ====
 +
 +var_dump is a function which I consider to have goals that are incompatible ways.
 +If an exact representation of reference cycles, identical objects, and circular object data is needed, the code snippet ''unserialize("....")'' can be generated using ''var_representation(serialize($value))'' (or var_export).
 +
 +In particular, var_dump() dumps object ids, indicates objects that are identical to each other, shows recursion, and shows the presence of references. It also redundantly annotates values with their types, and generates output for types that cannot be evaluated (e.g. ''resource(2) of type (stream)'').
 +
 +Adding a comment such as ''/* resource(2) of type (stream) */ null'' to the var_representation output with an opt-in flag to add this information may be useful to explore in follow-up work.
 +
 +https://externals.io/message/112967#112970
  
 ===== Changelog ===== ===== Changelog =====
  
   * 0.2: Add the section "When would a user use var_representation?". Add a comparison with other languages.   * 0.2: Add the section "When would a user use var_representation?". Add a comparison with other languages.
 +  * 0.3: Add more examples, add discussion section on indent
rfc/readable_var_representation.1611435400.txt.gz · Last modified: 2021/01/23 20:56 by tandre