rfc:var_info

PHP RFC: var_info

Introduction

Debug, error, and exception messages in PHP often contain type information about variables that did not satisfy a defined validation constraint. The idiomatic way to add this type information is currently via the gettype() function, however, the information that can be retrieved via that function is very sparse and developers need to repeat certain patterns over and over again to enrich it. This RFC proposes a new function called var_info() that addresses this issue and helps developers to create better debug, error, and exception messages in their software.

Proposal

Research of big and successful PHP userland projects (e.g. a search with is_object\([^\)]+\)\s*\?\s*get_class\([^\)]+\)\s*:\s*gettype shows 44 results in a fresh Drupal 8.2.x checkout with all composer dependencies installed) has shown that the gettype() function is often used as follows:

$type = is_object($var) ? get_class($var) : gettype($var);

The result of such a check is then mostly used as part of an error message. It is trivial to write the above line of code, and the performance hit of an additional function call is negligible (due to the fact that it is usually only executed in error branches of software). Nevertheless, it is an unnecessary hurdle, and the so retrieved information on the type is not very extensive. Hence, the proposal for a new function that is called var_info() that works as follows:

echo var_info([]);                               // array
echo var_info([SomeClass::class, 'someMethod']); // callable array
echo var_info([new SomeClass, 'someMethod']);    // callable array
echo var_info(false);                            // false
echo var_info(-1.0);                             // negative float
echo var_info(0.0);                              // zero float
echo var_info(1.0);                              // positive float
echo var_info(INF);                              // infinite float
echo var_info(NAN);                              // invalid float
echo var_info(-1);                               // negative int
echo var_info(0);                                // zero int
echo var_info(1);                                // positive int
echo var_info(new stdClass);                     // object of class stdClass
echo var_info(new Some\Namespaced\UserClass);    // object of class Some\Namespaced\UserClass
echo var_info(unserialize('O:1:"A":0:{}'));      // object of class __PHP_Incomplete_Class
echo var_info(function () {});                   // object of class Closure
echo var_info(STDIN);                            // resource of type stream
$fh = tmpfile();
fclose($fh);
echo var_info($fh);                              // closed resource
echo var_info('string');                         // string
echo var_info('strlen');                         // callable string
echo var_info('SomeClass::someMethod');          // callable string
echo var_info('10');                             // numeric string
echo var_info('1.0');                            // numeric string
echo var_info(true);                             // true

The following table summarizes the possible return values in a more readable form:

Return Value Comment
array
callable array is_callable()
false bool(false)
negative float $var < 0.0
zero float $var === 0.0 || $var === -0.0
positive float $var > 0.0
infinite float is_infinite()
invalid float is_nan()
negative int $var < 0
zero int $var === 0 || $var === -0
positive int $var > 0
object of class %s %s will contain the result of get_class().
resource of type %s %s will contain the result of get_resource_type().
closed resource If no type is available anymore or is invalid/unknown.
string
callable string is_callable()
numeric string is_numeric()
true bool(true)

The return values do not contain any kind of special characters like brackets in order to not interfere with the formatting a developer might choose to format her message (e.g. ( and ) are not appropriate within ( and ) in English language). This should be taken into account in possible future extensions of this function.

Developers should however not rely on the returned values for anything other than outputting them. This is because the returned values might change in any major PHP release, the PHP team will of course take careful care not to alter the output during non-major releases, but it is still highly discouraged.

Prefix Choice

The function prefix var_ was chosen on purpose because another possibly more suitable prefix like val_ or value_ would introduce a new prefix to the PHP ecosystem. It is true that this function can be used with the return value of functions too as well as with literal values, however, exactly the same argument is true for var_dump() and var_export(). Naming consistency is very important and this tiny blemish is on purpose in this case.

Core Inclusion

Writing a function that does exactly the same as the proposed var_info() function in userland is trivial. However, the inclusion of tiny dependencies for every day tasks is not something library developers want since every dependency results in an maintainability increase. Another solution would be to copy the few lines of code that provide the functionality from project to project, it should be obvious that this is never an appropriate solution for any kind of problem. Hence, such a tiny but portable functionality is best provided by the platform itself. The inclusion in core should support developers while creating useful error messages, in tiny scripts as well as fully fledged applications and replace calls to gettype() for that purpose or even var_dump()/var_export().

Backward Incompatible Changes

None

Proposed PHP Version(s)

This RFC targets the next feature release, currently 7.1.0.

RFC Impact

To SAPIs

None

To Existing Extensions

None

To Opcache

None

New Constants

None

php.ini Defaults

None

Open Issues

  • Whether to output negative zero float for -0.0 values or not.
  • Whether to output invalid object instead of object of class __PHP_Incomplete_Class.

Unaffected PHP Functionality

Everything

Future Scope

None

Proposed Voting Choices

This RFC will have a single poll that requires a 50%+1 majority.

Accept var_info function?
Real name Yes No
bishop (bishop)  
colinodell (colinodell)  
danack (danack)  
derick (derick)  
eliw (eliw)  
galvao (galvao)  
guilhermeblanco (guilhermeblanco)  
hywan (hywan)  
jhdxr (jhdxr)  
kalle (kalle)  
kguest (kguest)  
kinncj (kinncj)  
lcobucci (lcobucci)  
leigh (leigh)  
marcio (marcio)  
mike (mike)  
nikic (nikic)  
ocramius (ocramius)  
pollita (pollita)  
rasmus (rasmus)  
santiagolizardo (santiagolizardo)  
stas (stas)  
trowski (trowski)  
tularis (tularis)  
zimt (zimt)  
Final result: 0 25
This poll has been closed.

Patches and Tests

The GitHub Pull Request #1957 contains the implementation as well as tests for the new function. The changes in the PR are considered final, however, a thorough code review would be much appreciated and might result in minor changes.

References

Rejected Features

None

rfc/var_info.txt · Last modified: 2017/09/22 13:28 by 127.0.0.1