I've taken some time the last couple days to compile both the Scalare Type Hints v0.5 (heretofor STHv5) and Coercive Scalar Type Hints (heretofore STHcoerce) patches and test some code against them.
In each case, I modified the `Phly\Http\Response` class from my phly/http package to add scalar type hints, remove previous argument validation, and then ran the unit tests. Here's my details of the experience, and analysis. ### STHv5 With STHv5, my tests failed out of the box. First, I needed to add an error handler that would convert the E_RECOVERABLE_ERROR to an InvalidArgumentException so that I would get useful error messages from PHPUnit. Next, once I had done that, I had tests that were throwing invalid input at methods, and validating that the invalid arguments were caught. This worked in all but one specific case: passing a float value to an argument expecting an integer. In this particular case, the value was coerced to an integer, albeit lossily, and no error was raised. When I changed my test case to operate under strict_types mode, the test executed as I had originally expected, and succeeded. #### Analysis I did not expect the float value to be coerced, particularly as it had a fractional part. Yes, I understand that this is how casting _currently_ works in PHP, and that the patch uses the current casting rules. However, I'd expect that any float with a fractional value would not be cast to an integer; doing so is lossy, and can lead to unexpected results. The strict_types mode operated how I would expect it, but meant I was forced to add the declaration to the top of the file. Which leads to this: My tests operated differently in strict vs normal mode. That means my code does, too. Testing both modes would be difficult to do in an automated fashion; essentially, you're left needing to choose to support one mode or the other. This goes back to the point I was making earlier this week: I worry that having two modes will lead to a schism in userland libraries: those that support strict, and those that do not; there will be little possibility of testing both. ### STHcoerce With STHcoerce, my tests also failed out of the box, but not for the same reason. Instead, I had a bunch of errors reported based on code that PHPUnit was executing! In this case, I discovered that: - PHPUnit passes a boolean false to `debug_backtrace()`... which is documented as expecting an integer! (There are actually several constant values it accepts, all of which are integer values.) In this case, PHPUnit is relying on the fact that the engine casts booleans to the integers 0 and 1. (Zeev has written to the list already indicating that this coercion path will be supported in the patch.) - PHPUnit is passing the results of $reflector->getDocComment() blindly to substr() and preg_match*(). getDocComment() is documented as returning EITHER a string OR boolean false. Again, PHPUnit is relying on PHP to cast boolean false to an empty string. (Zeev has also indicated this coercion path may be re-introduced.) I was able to fix these in a matter of minutes, and then my tests ran, and passed without any changes. #### Analysis STHcoerce worked about how I expect STHv5 will work _if_ _every_ _file_ were declared in strict_types mode. In other words, it uncovered errors in calling both userland and internal functions. Userland typehints worked as I expected, with floats using fractional values not casting to integers. ### Wrap Up STHcoerce was actually far more strict than I found strict_types mode to be in STHv5. The reason is that it's a single, non-optional mode. This poses a potential challenge to migration, as noted in my problems using PHPUnit (Yes, I WILL be sending patches their way soon!): method calls and arguments that previously worked because of how PHP juggles types often do not work, particularly when going from boolean to other scalar values. However, the patch does what I'd expect in terms of preventing operations that would result in either data loss or data additions, all of which can have unexpected side effects if you don't understand the casting rules currently. The flip side to this is that you do not need to make any changes to your code in order to locate and fix errors. What this means from a library/framework author perspective is that, if the STHcoerce patch is merged, I can test against PHP 7, make fixes, and my code is not only forward-compatible, but also backwards to the various PHP 5 versions I might already be supporting — and that code now benefits from being more correct. Because STHv5 is opt-in only, the only way to see similar type errors is to somehow automate the addition of the strict_types declaration to all files in your project. While it can be done with tools like sed and awk, realistically it means that existing libraries cannot and/or will not benefit easily from the changes until they support PHP 7 as a minimum version. Additionally, it poses potential problems in terms of different testing results based on which mode you run in, leading to ambiguity for users. The only way to address the latter as a library author is to specify which mode your code is known to run in. Ironically, I'm seeing STHcoerce as more strict than STHv5 in terms of type handling, due to the fact that every call, userland or internal, is affected. The fact that it's always on makes it simpler for me to test against it now, and makes it easier to make my existing code both forward-compatible and more correct — even if I do not add type hints until I update my minimum supported version to PHP 7. I am slightly worried about the amount of work needed to make code run from v5 to v7 if STHcoerce is adopted. That said, the issues I found in PHPUnit were corrected in minutes (though a more thorough patch that allows early return from methods if doc comments are not strings would be better), and my own library's tests ran without problems once the PHPUnit issues were corrected (both code with and without typehints). Strict_types is definitely interesting, but I found that strict_types mode was more or less how I wanted code to operate, and to opt-in to that means changes to every file in my library — which is a much larger migration problem. In the end: kudos to everyone who is working on these patches and RFCs. I'm excited about scalar type hints in PHP 7! -- Matthew Weier O'Phinney Principal Engineer Project Lead, Zend Framework and Apigility matt...@zend.com http://framework.zend.com http://apigility.org PGP key: http://framework.zend.com/zf-matthew-pgp-key.asc -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php