Moving PHP sites to php 7.2 – undefined constants used as a string
PHP7.2 and above will no longer allow Undefined Constants
According to the “Promote the error level of undefined constants” section of the PHP 7.2 Backwards Incompatible Changes Document
Unqualified references to undefined constants will now generate anE_WARNING
(instead of anE_NOTICE
). In the next major version of PHP, they will generate Error exceptions.
There have been many changes to PHP over its many versions – For Matraex’s use of PHP, each version has been mostly compatible with the previous one with only minor changes, until a major decision affected one of the ways we deliberately used what we once called a “Feature” of PHP. (For a full list of incompatible changes look at the Backwards Incompatible Changes sections in the PHP Appendices )
On March 5th, 2017, Rowan Collins proposed to deprecate bareword strings. In PHP 7.2 the messages throw an E_WARNING message and in PHP 8.0 it will through an E_ERROR.
PHP has always been a loosely typed language which allows flexibility in many ways, And we had used this flexibility in order write code in a ways that we belive made it more legible, maintainable and supportable within our coding style. With this new change, hundreds of thousands of lines of code will need to be rewrittend before we can put it on a 7.2 or above server, keys may be difficult to search, we will have inconsistencies in usage of keys depending on whether they are inside or out side of quotes.
Take this one example where lines 1, 3 and 4 below would work, but line 2 would throw a warning in 7.2 and would through an error in 8.0.
- echo “Hello, $user[firstname],”;
- echo “Hello, “.$user[firstname].”,”;
- echo “Hello, “.$user[‘firstname’].”,”;
- echo “Hello, “.$user[“firstname”].”,”;
Matraex would have previously preferred to use methods 1 and then 2, as they require fewer quotes and a search in our IDE of ‘user[first’ would have highlighted both uses.
Mr Collins did evaluate both sides of the decision and wrote a bit about it. He described that “The value of keeping the current behaviour would be for programs written to deliberately take advantage of it”, however he really dismisses that value and gave a stronger argument undefined constants can “mask serious bugs”.
I agree with each of the arguments and our 7.2 scripts will all comply with this new syntax requirement. However, I disagree with the way the solution was indiscriminately executed. A more considerate solution would have been to create a configuration option in PHP to control the requirement and allow developers and system administrators to continue to ‘deliberately’ use ‘undefined constants’. This option would also allow existing stable programs to continue to take advantage of the other features of PHP >=7.2 without a significant refactor. Perhaps the Impact section of the article could attempted to get more feedback from users that had deliberately made heavy investment in this feature.
To be more direct here is my request: PHP developers, please create / allow a configuration option in PHP which will allow undefined constants to be used as strings.
Changing existing code across the 10 + years of PHP projects will take thousands of hours to modify and test, and that is just the projects that still exist. This is a barrier to upgrading to PHP 8.0.
Arguments for a configuration option
- Millions of lines of code which deliberately use undefined constants as string (more likely billions or trillions – I probably have close to one million myself overtime)
- My random belief: PHP should enforce “standards” on those that want or need them, and allow experience users to explicitly choose to ignore them.
- The configuration option would be disabled by default to address all of the problems mentioned in ‘the problem’ section of the article
Dealing with undefined constant warnings
Now we get to more technical area where I document some of the methods we have used to find code that needs to be updated for PHP 7.2 code.
1) Use grep to find all uses of the code
This code finds ALL uses of lower case strings without quotes – because our standards do require constants to be in upper case
grep -Rne ‘\$[A-Z\_a-z]*\[[A-Za-Z\_]\{1,\}\]’ *.php
2) Suppress E_WARNING messages
This is a bad idea, while it will certainly make it so that your code continues to work in 7.2, it will not fix it going into 8.0, and this WILL mask other issues that you do need to know about.
If you want to learn mroe about this, take a look at this discussion about it on Stack Overflow. Definitely read the comments about hiding warnings to get a better feel for it.
3) Create PHP configuration options to make provisions for undefined constants
These options would require the good work of a C developer that works on the PHP source. Some of these ideas may just work as described, they really are just a good start (or continuation) of a discussion for features which could be implemented. I don’t have a ‘bounty’ system but if you are interested in creating any of these options, or would like to group together to coordinate it, please contact me.
- undefined_constants_string_level – Have a PHP directive which declares what E_ level all undefined constant warnings should – default in 8.0 can be E_ERROR
- undefined_constants_string_lowercase – Allow users to configure options which would allow only lowercase (or mixed case) constants as strings – which would allow / reserve upper case for use as constants.
- undefined_constants_string_superglobal – Allow undefined constants to be used when attempting to reference any key to a super global array (such as $_POST[mykey] or S_SERVER[HTTP_HOST]);