rfc:typecheckingstrictandweak

Differences

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

Link to this comparison view

rfc:typecheckingstrictandweak [2010/05/22 16:10]
zeev
rfc:typecheckingstrictandweak [2017/09/22 13:28]
Line 1: Line 1:
-====== Request for Comments: Strict and weak parameter type checking ====== 
-  * Version: 0.5 
-  * Date: 2009-06-03 
-  * Author: Lukas Smith <smith@pooteeweet.org>, Zeev Suraski <zeev@php.net> 
-  * Status: In discussion 
-  * First Published at: http://wiki.php.net/rfc/typechecking 
  
-This RFC is provide a proposal for both weak and strict parameter type checking for function/method parameters and why providing only strict type checking would be a mistake. 
- 
-===== Introduction ===== 
- 
-Several people still have asked to expand array/object type hinting to cover other data types, which mostly ask for similar strict type checking (without any type juggling) as for arrays and objects, while also triggering an E_RECOVERABLE_ERROR for failed checks. However this means that the burden for explicit type casting is now on the user of the function/method. This RFC tries to address this issue. 
-===== Why is strict type checking problematic? ===== 
- 
-PHP's type system was designed from the ground up so that scalars auto-convert depending on the context.  That feature became an inherent property of the language, and other than a couple of exceptions - the internal type of a scalar value is not exposed to end users.  The most important exception is the === operator - however, this operator is used in very specific situations.  While there are other exceptions (e.g. gettype()) - in the vast majority of scenarios in PHP, scalar types auto-convert to the necessary scalar depending on the context. 
- 
-For that reason, developers - even seasoned ones - will feel very comfortable sending the string "123" to a function that semantically expects an integer.  If they know how PHP works internally - they rely on the fact the function will auto-convert the type to an integer.  If they don't (and many don't) - they don't even think about the fact that their "123" is a string.  It's a meaningless implementation detail. 
- 
-For these reasons - strict type checking is an alien concept to PHP.  It goes against PHP's type system by making the implementation detail (zval.type) become much more of a front-stage actor. 
- 
-In addition, strict type checking puts the burden of validating input on the callers of an API, instead of the API itself.  Since typically functions are designed so that they're called numerous times - requiring the user to do necessary conversions on the input before calling the function is counterintuitive and inefficient.  It makes much more sense, and it's also much more efficient - to move the conversions to be the responsibility of the called function instead.  It's also more likely that the author of the function, the one choosing to use scalar type hints in the first place - would be more knowledgeable about PHP's types than those using his API. 
- 
-Proponents of strict type hinting often argue that input coming from end users (forms) should be filtered and sanitized anyway, and that this makes for a great opportunity to do necessary type conversions.  While that may be true, it covers a small subset of type checking scenarios.  For example, it doesn't cover input coming from 'trusted' sources like a database or files.  It also doesn't account for the many developers who are simply unaware of PHP's internal type system, or that presently don't see the need to explicitly do type conversions even if they do sanitize their input.  Not to mention those that don't sanitize their input at all... 
- 
-===== Introducing weak type checking ===== 
- 
-In Ilia's recent [[http://news.php.net/php.internals/44573|strict type checking proposal]], he did include a "numeric" and a "scalar" data type, which tried to reducing the above noted issues with strict type checking. The "numeric" type would behave similar to the "is_numeric()" function in that it would not check the type, but would also accept a string with only numbers or a float ([[http://php.net/is_numeric|see the documentation]] for the exact definition). In the same way "scalar" would simply check if the parameter is not an array, object or resource. 
- 
-However it does not cover all specific data types. Moreover "numeric" is not a known data type and is also significantly longer to type than "int". As a result it seems likely that "int" will be used by many developers even where "numeric" would suffice. As a result [[http://news.php.net/php.internals/44619|a new concept was introduced]] to simply allow a syntax to define if the check should be strict or weak. 
- 
-A weak check would examine the content of the variable in a way that would be more strict than the standard type juggling. If the weak check passes, the value would be type casted appropriately. If the weak check fails it would trigger an E_RECOVERABLE_ERROR just as in the strict case. 
- 
-Here is a short list of examples to illustrate the weak type checking. 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  | 
- 
-Further more weak type checking could also be useful once we have generic type casting support via some magic type cast method along the lines of __toString(). In this case the weak type checking would also allow an object to pass if it provides the relevant casting method, though it would then of course automatically cast the object to the given type. 
- 
-===== Proposed API ===== 
- 
-<code php> 
- 
-// "+' denotes strict and "-" denotes weak type checking 
-function add_user(+string name, +string phone_number, -int age) { .. } 
- 
-// "!" denotes strict type checking and "?" denotes weak type checking 
-function add_user(string name, !string phone_number, ?int age) { .. } 
- 
-// "~" denotes weak type checking 
-function add_user(string name, string phone_number, ~int age) { .. } 
- 
-// "()" denotes weak type checking 
-function add_user(string name, string phone_number, (int) age) { .. } 
- 
-// Keep in mind that the "modifier" can either be placed at the start or end 
-function add_user(string! name, string! phone_number, int? age) { .. } 
- 
-// Furthermore one of the two modifiers could be the default 
-// optionally + is the default 
-function add_user(+string name, string phone_number, -int age) { .. } 
-// optionally - is the default 
-function add_user(+string name, +string phone_number, int age) { .. } 
- 
-</code> 
- 
-===== Changelog ===== 
rfc/typecheckingstrictandweak.txt · Last modified: 2017/09/22 13:28 (external edit)