Well, there are a few questions about the implementation: 1. *Which* type casting rules should it follow?
a. Regular cast rules (like $foo = (int) $foo), where it converts always without error? b. Internal function cast rules, where it warnings on error and prevents execution of the function. c. Current type hinting rules, where if it can't convert cleanly it E_RECOVERABLE_ERRORS Personally, I like C the best. Where if it is passed an invalid value, it attempts to cleanly convert, but errors out if it can't... But I can see other arguments being made... 2. Should (array) be supported? Perhaps. So at that point, foo(array $bar) would do a "strict" check, and foo((array) $bar) would attempt to cast. But my question would be: what would attempt to cast mean? Should it error out if you pass foo(1)? That's what the internal function cast rules do. And to me that's more obvious than silently converting it to foo(array(1))... 3. Should references be supported? My feeling is yes, they should. So if you do foo((array) &$bar), it would cast the original value (if possible) as well. 4. What about consistency? Well, there currently is no consistency. Internal function parameters behave one way, and explicit casts behave another. And even more confusing implicit casts behave yet another way ($a + $b). So to implement this, we'd need to be consistent with one of them. Frankly, I would only want to add consistency to internal function parameters, since the explicit cast is not useful IMHO (it's identical to $bar = (int) $bar), at which point it's not worth adding to save only that one line. But if we're consistent with internal function parameter checking, then it becomes quite useful. We can throw warnings on unclean conversion and prevent execution of the function... That way, all function calls behave the same (as much as I hate the concept of warnings on type hint failure)... So, in that case, function calls become an implicit cast to the type, which is then why the stricter error handling (without breaking the spirit or consistency). 5. What about BC breaks? Well, this entire patch (up to this point) wouldn't require one. it's only adding the casting functionality (which is not implemented today), so no problem. Existing code would still function fine. Thoughts? Should I update the patch to be more inline with what I said above (the implicit hints that are offered by the current internal function argument mechanism: # sapi/cli/php -r 'function foo((int) $bar) { return $bar; } $a = "1"; var_dump(foo($a));' int(1) # sapi/cli/php -r 'function foo((int) $bar) { return $bar; } $a = "foo"; var_dump(foo($a));' Warning: Argument 1 passed to foo() must be of the type integer, string given, called in Command line code on line 1 and defined in Command line code on line 1 However, since it's not raising a terminating error, more changes would need to be made to the VM to check the return status of the argument check (which is currently ignored) to determine if to proceed with the function call, or just return null imediately... Thoughts? Anthony On Fri, Mar 2, 2012 at 5:27 AM, Lazare Inepologlou <linep...@gmail.com> wrote: > +1 for the syntax. There are two nice side effects I would like to > underline. > > > 1. > Error-raising can be clearly delegated to the type juggling mechanism. There > will be no need to implement anything new here but reuse the existing type > juggling system of PHP. That would be very consistent. At the end of the > day, these two syntaxes are completely equivalent: > > function foo((int) $bar) { ... } > function foo($bar) { $bar = (int)$bar; ... } > > > 2. > If we put passing by reference into the picture, it is easy to see why the > following syntax should be a parsing error: > > function foo((int) & $bar) { } // parsing error > > On the contrary, were there no brackets, the resemblance to the syntax of C > would be confusing. > > > > > Lazare INEPOLOGLOU > Ingénieur Logiciel > > > 2012/3/2 Anthony Ferrara <ircmax...@gmail.com> >> >> Hey all, >> >> I know given all the discussion about this topic lately, this is a hot >> topic. But I whipped together a quick POC patch to implement scalar >> type casting for function parameters. Let me describe it: >> >> Patch: https://gist.github.com/1947259 >> >> Example: >> >> function foo( (int) $bar ) { >> var_dump($bar); >> } >> >> foo(1); // int(1) >> foo("1"); // int(1) >> foo(1.5); // int(1) >> foo("foo"); // E_RECOVERABLE_ERROR - Expected integer >> foo(array()); // E_RECOVERABLE_ERROR >> >> Right now, I only implemented the checks for (int), but I add the >> parser constructs for (int), (float), (bool), (string) and (object)... >> >> Now, let's talk why I did what I did: >> >> Why did I use cast syntax? Well, there are really three main reasons. >> First off, to indicate that a cast may happen. Second, to prevent >> needing new tokens (and hence reserved words). And third to provide a >> distinction between a string class type hint and a string scalar type >> hint. >> >> Why did I only implement (int)? Well, because I just wanted to build >> a quick dirty POC that can be executed to see the semantics of >> operation. There are issues with it now, so rather than doing all the >> work to re-do it later, I just implemented int... >> >> Why implement (object)? Because right now, there's no way to say you >> want to accept a generic object without caring about type. So the >> (object) cast/hint would then provide that ability to accept a generic >> object. >> >> Why not implement (resource)? Because that would require a new parser >> token, as it's not available now... >> >> How does the casting work? Right now, it's using a copy of the same >> rules that internal functions use with zend_parse_parameters. That >> way, it brings the operating semantics of internal functions and >> userland functions more inline with each other. >> >> >> >> So with that said, there are some (significant) issues with the patch: >> >> 1. First off, the arg checks happen before separation of the zval on >> non-referenced calls. So that means the cast effects the original >> zval AND the argument. Which is a no-go for a production patch. So >> that means that the cast logic would need to be put after the zval >> split. But we'd still want the checks first, so it's not too >> difficult to segregate, just requires deeper changes. It's not >> difficult (that I can see yet), just more work... Example of the >> problem: >> >> # sapi/cli/php -r 'function foo((int) $bar) { var_dump($bar); } $a = >> "1"; foo($a); var_dump($a);' >> int(1) >> int(1) >> >> 2. Right now, the zend_aprse_arg_impl ( >> http://lxr.php.net/xref/PHP_5_4/Zend/zend_API.c#zend_parse_arg_impl ) >> that's used by internal functions is defined as static. So we'd be >> copying a lot of the code back and forth. In the production patch, >> I'd also want to re-factor that out a bit into either functions or >> macros to handle the type conversion and casting in both places. That >> way, both systems would behave identical (or as close as possible). >> >> >> So, with that said, what do you think? Is this something worth >> pursuing? Are there any fundamental issues that I'm missing? What >> else would we need to cover in a production patch and RFC? >> >> Thanks, >> >> Anthony >> >> -- >> PHP Internals - PHP Runtime Development Mailing List >> To unsubscribe, visit: http://www.php.net/unsub.php >> > -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php