Initially, we tried to use IDE’s, which are very popular among developers, but, unfortunately, they either don’t support the syntax and features of PHP7 yet, or they didn’t function well enough to find all the obviously dangerous places in the code. After conducting a bit of research (i.e. googling), we decided to try the php7mar utility, which is a static code analyzer implemented in PHP. This PHP7 utility is very simple to use, works fairly quickly, and gives you your results in a text file. Of course, it’s not a panacea; there are both false positives and failures to find particularly well-hidden problem spots. Despite this, the utility helped us root out about 90% of the problems, which dramatically sped up and simplified the process of getting the code ready for PHP7.
The most commonly encountered and potentially dangerous problems for us were the following:
Changes in the behavior of func_get_arg() and func_get_args(). In the 5th version of PHP, these functions return argument values at the moment of transmission, but in version seven this happens at the moment when func_get_args() is called. In other words, if the argument variable changes inside the function before func_get_args() is called, then the behavior of the code may differ from that of version five. The same thing happens when the app’s business logic breaks down, but there is nothing in the logs.
Indirect access to object variables, properties, and methods. And once again, the danger lies in the fact that the behavior can change “silently”. For those looking for more information, the differences between versions are described in detail here.
Use of reserved class names. In PHP7, you can no longer use bool, int, float, string, null, true and false as class names. And yeah, we had a Null class. Its absence actually makes things easier though, because it often resulted in errors.
Many potentially problematic foreach constructions that use a reference were found. Since we tried earlier not to change the iterable array inside foreach or count on its internal pointer though, practically all of them behaved the same in versions 5 and 7.