rfc:typecheckingstrictandweak

Differences

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

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
Next revision Both sides next revision
rfc:typecheckingstrictandweak [2010/05/24 00:48]
cataphract behavior of zend_parse_parameters
rfc:typecheckingstrictandweak [2010/06/08 15:48]
dmitry Added patch
Line 27: Line 27:
  
 The proposed solution implements a 'weaker' kind of type hinting - which arguably is more consistent with the rest of PHP's type system. The proposed solution implements a 'weaker' kind of type hinting - which arguably is more consistent with the rest of PHP's type system.
-Instead of validating the zval.type property only - it uses similar rules to those used by PHP's auto-conversion system to look into the value in question, and determine whether it 'makes sense' in the required context.  If it does - it will be converted to the required type (if it isn't already of that type);  If it doesn't - an error will be generated.+Instead of validating the zval.type property only - it uses rules in line with the spirit of PHP and it's auto-conversion system to look into the value in question, and determine whether it 'makes sense' in the required context.  If it does - it will be converted to the required type (if it isn't already of that type);  If it doesn't - an error will be generated.
  
-For example, consider a function getUserById() that expects an integer value.  With [[http://news.php.net/php.internals/44573|strict type hinting]], if you feed it with $id, which happens to hold a piece of data from the database with the string value "42", it will be rejected.  With auto-converting type hinting, PHP will determine that $id is a string that has an integer format - and it is therefore suitable to be fed into getUserById().  It will then convert the value it to an integer, and pass it on to getUserById().  That means that getUserById() can rely that it will *always* get its input as an integer - but the caller will still have the luxury of sending non-integer but integer-formatted input to it.  Also note that the conversion rules proposed here are slightly stricter than PHP's auto-conversion rules.  Mainly, the string "abc" will be rejected as valid input for an integer type-hinted argument, and not be passed-on as zero.+For example, consider a function getUserById() that expects an integer value.  With [[http://news.php.net/php.internals/44573|strict type hinting]], if you feed it with $id, which happens to hold a piece of data from the database with the string value "42", it will be rejected.  With auto-converting type hinting, PHP will determine that $id is a string that has an integer format - and it is therefore suitable to be fed into getUserById().  It will then convert the value it to an integer, and pass it on to getUserById().  That means that getUserById() can rely that it will **always** get its input as an integer - but the caller will still have the luxury of sending non-integer but integer-formatted input to it.
  
-The key advantages of the proposed solution are that there's less burden on those calling APIs (fail only when really necessary)it's consistent with the rest of PHP, and perhaps most importantly - it does not require everyone to become intimately familiar with PHP's type system. +The key advantages of the proposed solutions are that there's less burden on those calling APIs (fail only when really necessary). It should be noted that most of the time coding is spend consuming existing API's and not creating new ones. Furthermore it's consistent with the rest of PHP in the sense that most of PHP does not care about exact matching zval types, and perhaps most importantly - it does not require everyone to become intimately familiar with PHP's type system.
- +
-Here is a short list of examples to illustrate the weak type hinting. Note that just like the current array/object hints, a NULL is only allowed if the parameter defaults to NULL. +
- +
-^ value                   ^ string ^ float ^ int   ^ numeric ^ scalar ^ bool ^ array ^ +
-^ true (boolean)          | fail   | fail  | fail  | fail    | pass   | pass | fail  | +
-^ false (boolean)         | fail   | fail  | fail  | fail    | pass   | pass | fail  | +
-^ 0 (integer)             | fail   | pass  | pass  | pass    | pass   | pass | fail  | +
-^ 1 (integer)             | fail   | pass  | pass  | pass    | pass   | pass | fail  | +
-^ 12 (integer)            | fail   | pass  | pass  | pass    | pass   | fail | fail  | +
-^ 12 (double)             | fail   | pass  | fail  | pass    | pass   | fail | fail  | +
-^ 12.34 (double)          | fail   | pass  | fail  | pass    | pass   | fail | fail  | +
-^ 'true' (string)         | pass   | fail  | fail  | fail    | pass   | fail | fail  | +
-^ 'false' (string)        | pass   | fail  | fail  | fail    | pass   | fail | fail  | +
-^ '0' (string)            | pass   | fail  | fail  | pass    | pass   | pass | fail  | +
-^ '1' (string)            | pass   | fail  | fail  | pass    | pass   | pass | fail  | +
-^ '12' (string)           | pass   | fail  | fail  | pass    | pass   | fail | fail  | +
-^ '12abc' (string)        | pass   | fail  | fail  | fail    | pass   | fail | fail  | +
-^ '12.0' (string)         | pass   | fail  | fail  | pass    | pass   | fail | fail  | +
-^ '12.34' (string)        | pass   | fail  | fail  | pass    | pass   | fail | fail  | +
-^ 'foo' (string)          | pass   | fail  | fail  | fail    | pass   | fail | fail  | +
-^ array () (array)        | fail   | fail  | fail  | fail    | fail   | fail | pass  | +
-^ array (0 => 12) (array) | fail   | fail  | fail  | fail    | fail   | fail | pass  | +
-^ NULL (NULL)             | fail   | fail  | fail  | fail    | fail   | fail | fail  | +
-^ %%''%% (string)             | pass   | fail  | fail  | fail    | pass   | fail | fail  |+
  
 Furthermore, weak type hinting may be a step on the way to create generic type casting magic methods along the lines of %%__toString()%%, allowing objects to auto-convert to scalar types as necessary (TBD). Furthermore, weak type hinting may be a step on the way to create generic type casting magic methods along the lines of %%__toString()%%, allowing objects to auto-convert to scalar types as necessary (TBD).
  
-===== Current behavior of zend_parse_parameters =====+===== Option (1): current type juggeling rules with E_STRICT on data loss ===== 
 + 
 +The auto-conversion would follow the current type juggeling rules. However in case of a cast that leads to data loss (like casting from '123abc' to an integer leading to 123 an E_STRICT notice would be raised.
  
 For reference, here's the current behavior of zend_parse_parameters, used in most internal functions. For reference, here's the current behavior of zend_parse_parameters, used in most internal functions.
Line 84: Line 62:
 ^ NULL (NULL)               | pass   | pass   | pass   | pass   | fail   | ^ NULL (NULL)               | pass   | pass   | pass   | pass   | fail   |
 ^ %%''%% (string)               | pass   | fail   | fail   | pass   | fail   | ^ %%''%% (string)               | pass   | fail   | fail   | pass   | fail   |
 +===== Option (2): new type juggeling rules with E_STRICT on data loss =====
 +
 +The conversion rules proposed here are slightly stricter than PHP's auto-conversion rules.  Mainly, the string "abc" will be rejected as valid input for an integer type-hinted argument, and not be passed-on as zero and it would not auto-convert from/to array's.
 +
 +An E_STRICT would be raised if due to auto-conversion there would be data loss. So for example "2", 2 as well as 2.5 would convert to a float if one is expected. However 2.5 would not silently convert to an integer if one is expected. Similarly "123abc" would not convert to an integer or float. This might also be a potential approach to type juggling in general in some future version of PHP.
 +
 +Here is a short list of examples to illustrate the weak type hinting. Note that just like the current array/object hints, a NULL is only allowed if the parameter defaults to NULL.
 +
 +(Note the following table should probably be reviewed in light of recent updates to this RFC)
 +^ value                   ^ string ^ float ^ int   ^ numeric ^ scalar ^ bool ^ array ^
 +^ true (boolean)          | fail   | fail  | fail  | fail    | pass   | pass | fail  |
 +^ false (boolean)         | fail   | fail  | fail  | fail    | pass   | pass | fail  |
 +^ 0 (integer)             | fail   | pass  | pass  | pass    | pass   | pass | fail  |
 +^ 1 (integer)             | fail   | pass  | pass  | pass    | pass   | pass | fail  |
 +^ 12 (integer)            | fail   | pass  | pass  | pass    | pass   | fail | fail  |
 +^ 12 (double)             | fail   | pass  | fail  | pass    | pass   | fail | fail  |
 +^ 12.34 (double)          | fail   | pass  | fail  | pass    | pass   | fail | fail  |
 +^ 'true' (string)         | pass   | fail  | fail  | fail    | pass   | fail | fail  |
 +^ 'false' (string)        | pass   | fail  | fail  | fail    | pass   | fail | fail  |
 +^ '0' (string)            | pass   | fail  | fail  | pass    | pass   | pass | fail  |
 +^ '1' (string)            | pass   | fail  | fail  | pass    | pass   | pass | fail  |
 +^ '12' (string)           | pass   | fail  | fail  | pass    | pass   | fail | fail  |
 +^ '12abc' (string)        | pass   | fail  | fail  | fail    | pass   | fail | fail  |
 +^ '12.0' (string)         | pass   | fail  | fail  | pass    | pass   | fail | fail  |
 +^ '12.34' (string)        | pass   | fail  | fail  | pass    | pass   | fail | fail  |
 +^ 'foo' (string)          | pass   | fail  | fail  | fail    | pass   | fail | fail  |
 +^ array () (array)        | fail   | fail  | fail  | fail    | fail   | fail | pass  |
 +^ array (0 => 12) (array) | fail   | fail  | fail  | fail    | fail   | fail | pass  |
 +^ NULL (NULL)             | fail   | fail  | fail  | fail    | fail   | fail | fail  |
 +^ %%''%% (string)         | pass   | fail  | fail  | fail    | pass   | fail | fail  |
 +
 +===== Option (3): current type juggeling rules with E_FATAL on data loss =====
 +
 +The auto-conversion would follow the current type juggeling rules. However in case of a cast that leads to data loss (like casting from '123abc' to an integer leading to 123 an E_FATAL notice would be raised.
 +
 +===== Patch =====
 +
 +  * {{rfc:week_typechecking.diff.txt}}
  
 ===== Changelog ===== ===== Changelog =====
 +  * restructured to provide 3 options (two with current type juggeling rules and E_STRICT or E_FATAL on data loss conversion and one with new type juggeling rules and E_STRICT on data loss.
rfc/typecheckingstrictandweak.txt · Last modified: 2017/09/22 13:28 (external edit)