Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision |
rfc:typecheckingweak [2009/07/12 13:52] – Some fixes and additions. zeev | rfc:typecheckingweak [2009/07/13 07:23] – Remove a note which turns out to be more confusing than useful zeev |
---|
| |
<code php> | <code php> |
function foo(int x) {} | function foo(int $x) {} |
function bar(x, string y) {} | function bar($x, string $y) {} |
function baz(int x, float y, string z) {} | function baz(int $x, float $y, string $z) {} |
function foobar(int &x) {} | function foobar(int &$x) {} |
</code> | </code> |
| |
bar('whatever', 17.5); // argument will be converted to a string '17.5' before being passed to bar() | bar('whatever', 17.5); // argument will be converted to a string '17.5' before being passed to bar() |
foobar(17.5); // will fail (scalar value cannot be passed by reference) | foobar(17.5); // will fail (scalar value cannot be passed by reference) |
$x=17.5; foobar($x); // $x will be converted to 17(int), and then passed to foobar() | $x=17.5; foobar($x); // $x will be converted to 17(int), and then passed to foobar(); $x remains 17(int) after the call to foobar() |
</code> | </code> |
| |
- Emit an error or throw an exception. | - Emit an error or throw an exception. |
| |
**Note:** In step 2, if the argument is designated as a pass-by-reference argument - the conversion will apply to the variable being passed. This is consistent with the expectation that arguments passed by reference may be modified by the function they're sent to. | |
| |
| |
===== Conversion Logic ===== | ===== Conversion Logic ===== |
| |
^ value ^ string ^ float ^ int ^ numeric ^ bool ^ | ^ value ^ string ^ float ^ int ^ numeric ^ bool ^ |
^ true (boolean) | //fail// | 1.0 | 1 | 1 | //as-is// | | ^ true (boolean) | //fail// | 1.0 | 1 | 1 | //as-is// | |
^ false (boolean) | //fail// | 0.0 | 0 | 0 | //as-is// | | ^ false (boolean) | //fail// | 0.0 | 0 | 0 | //as-is// | |
^ 0 (integer) | '0' | 0.0 | //as-is// | //as-is// | false | | ^ 0 (integer) | '0' | 0.0 | //as-is// | //as-is// | false | |
^ 1 (integer) | '1' | 1.0 | //as-is// | //as-is// | true | | ^ 1 (integer) | '1' | 1.0 | //as-is// | //as-is// | true | |
^ 12 (integer) | '12' | 12.0 | //as-is// | //as-is// | true | | ^ 12 (integer) | '12' | 12.0 | //as-is// | //as-is// | true | |
^ 12.0 (double) | '12.0' | //as-is// | 12 | //as-is// | true | | ^ 12.0 (double) | '12.0' | //as-is// | 12 | //as-is// | true | |
^ 12.34 (double) | '12.34' | //as-is// | 12 | //as-is// | true | | ^ 12.34 (double) | '12.34' | //as-is// | 12 | //as-is// | true | |
^ 'true' (string) | //as-is// | //fail// | //fail// | //fail// | //fail// | | ^ 'true' (string) | //as-is// | //fail// | //fail// | //fail// | //fail// | |
^ 'false' (string) | //as-is// | //fail// | //fail// | //fail// | //fail// | | ^ 'false' (string) | //as-is// | //fail// | //fail// | //fail// | //fail// | |
^ '0' (string) | //as-is// | 0.0 | 0 | 0 | false | | ^ '0' (string) | //as-is// | 0.0 | 0 | 0 | false | |
^ '1' (string) | //as-is// | 1.0 | 1 | 1 | true | | ^ '1' (string) | //as-is// | 1.0 | 1 | 1 | true | |
^ '12' (string) | //as-is// | 12.0 | 12 | 12 | true | | ^ '12' (string) | //as-is// | 12.0 | 12 | 12 | true | |
^ '0xA' (string) | //as-is// | 10.0 | 10 | 10 | true | | ^ '0xA' (string) | //as-is// | 10.0 | 10 | 10 | true | |
^ '12abc' (string) | //as-is// | //fail// | //fail// | //fail// | //fail// | | ^ '12abc' (string) | //as-is// | //fail// | //fail// | //fail// | //fail// | |
^ '12.0' (string) | //as-is// | 12.0 | 12 | 12.0 | true | | ^ '12.0' (string) | //as-is// | 12.0 | 12 | 12.0 | true | |
^ '12.34' (string) | //as-is// | 12.34 | 12 | 12.34 | true | | ^ '12.34' (string) | //as-is// | 12.34 | 12 | 12.34 | true | |
^ 'foo' (string) | //as-is// | //fail// | //fail// | //fail// | //fail// | | ^ 'foo' (string) | //as-is// | //fail// | //fail// | //fail// | //fail// | |
^ empty string (TBD) | //as-is// | //fail// | //fail// | //fail// | //fail// | | ^ empty string (TBD) | //as-is// | //fail// | //fail// | //fail// | //fail// | |
^ array () (array) | //fail// | //fail// | //fail// | //fail// | //fail// | | ^ array () (array) | //fail// | //fail// | //fail// | //fail// | //fail// | |
^ array (0 => 12) (array) | //fail// | //fail// | //fail// | //fail// | //fail// | | ^ array (0 => 12) (array) | //fail// | //fail// | //fail// | //fail// | //fail// | |
^ NULL (NULL) | empty string | 0.0 | 0 | 0 | false | | ^ NULL (NULL) | empty string | 0.0 | 0 | 0 | false | |
| ^ object | //fail++// | //fail++// | //fail++// | //fail++// | //fail++// | |
| |
//fail// - designates failure, either emitting an error or throwing an exception | //as-is// - designates that the value is passed as-is, without conversion |
| |
//as-is// - designates that the value is passed as-is, without conversion | //fail// - designates failure, either emitting an error or throwing an exception |
| |
| //fail++// - fail, unless a matching conversion function exists (e.g. __toString()) - in which case it will be called and used |
| |
| |
| **Note:** 'scalar' and 'array' type hints remain unchanged - an array typed argument will only accept arrays, and will otherwise fail; A scalar typed argument will accept any kind of scalar argument, but will fail on objects and arrays. |
| |
In a nutshell, the conversion logic is quite similar to the one employed by internal functions, with one key difference - it is designed to fail in case of a conversion that is unlikely to 'make sense'. Specifically, it breaks away from PHP's internal function behavior in two key places: | In a nutshell, the conversion logic is quite similar to the one employed by internal functions, with one key difference - it is designed to fail in case of a conversion that is unlikely to 'make sense'. Specifically, it breaks away from PHP's internal function behavior in two key places: |
| |
<code php> | <code php> |
function baz(int x, float y, string z) {} | function baz(int $x, float $y, string $z) {} |
| |
// Strict type checking | // Strict type checking |