PHP 7.4 released! How Badoo Upgrades

Today, finally, the release of PHP 7.4 is published!





Its new features have already been repeatedly described , including on Habré . These are arrow functions, typed class properties, and much more syntactic sugar. But most of all, we were waiting for a new release because of performance : in version 7.4, not only preload appeared, but PHP itself became much faster.



Bad (or good?) News - with the release of PHP 7.4, active support for PHP 7.2 ceases . His latest release is scheduled for mid-December. We have been experimenting with PHP 7.4 for a long time, and recently we are actively engaged in the transition to it, since now we are on the almost unsupported version 7.2.



Congratulations to all on the long-awaited release! And below I’ll talk a little about how we upgrade to the new version.



Despite the fact that we have a huge code base, we have been living in PHP for 13 years. We have repeatedly had to upgrade to new versions, and the transition process is well-established.



If greatly simplified, we can distinguish several steps:





Our edits in the PHP repository



Problem with preload ( fix )



This time, something has changed in the process: since we were waiting for preload, we started to carry out part of the work back in July, during version 7.4.0beta1. As a result, this resulted in a rather large amount of time spent debugging for us, because PHP 7.4 was then completely raw. But on the other hand, as a result, we found an unpleasant bug, fixed it and sent the fix to the upstream, which helped the whole community.



Then it's time to do the tests.



Problem with access to private properties ( fix )



In order to run tests in general, you need to update PHPUnit, SoftMocks and PHP-Parser as part of them. We have a large code base, and even updating PHPUnit required rewriting a huge number of tests.



After we managed to run the tests, we saw a very strange thing. There have been many crashes with the following error:



PHP Fatal error: Cannot access private property ClassLoader::$classMap in vendor/composer/ClassLoader.php
      
      





Access to the private property of a class is carried out only inside it, but PHP reports an error: you cannot access the private property as if the call came from another class.



The problem was complicated by the fact that it was reproduced unstably. A long debug with gdb showed that really for some reason EG (fake_scope) doesn’t have the class within which the property is accessed, but another that is not related to it.



After we found a minimal reproduce case (which, for a moment, requires three classes, an autoloader and Reflection), fixed the cause of the problem and started fixing it in the upstream, it turned out that this problem has existed since PHP 7.3 (most likely, after this change), the whole world lived with her for a year and she did not bother anyone before us.



Fix Badoo Code Incompatibility



Now we are correcting all incompatibilities of our code with PHP 7.4. The vast majority of incompatibilities for us (more than a hundred places,> 80% of all incompatibilities) were caused by the addition of the "Trying to access array offset on value of type null / bool / int" error ( corresponding to RFC ). It occurs when using the syntax of accessing an array element on other data types.



The following example illustrates the problem well:



 $a = false; var_dump($a['somekey']); // PHP 7.3: // NULL // // PHP 7.4: // Notice: Trying to access array offset on value of type bool in Command line code on line 1 // NULL
      
      





Offhand it seems that this should not occur in real code, but, as practice has shown, this is a fairly common case: for example, a function can return an array in the normal case and false / null in case of an error, and further up the stack information about false / null is lost, and this case is not handled separately.



This is a rather weakly propagated, but useful change in PHP: it allows you to find many potential errors in the code.



The second update in terms of problems brought up is a change in the way method_exists () works. By the way, at the moment there is no information about it in the release notes or upgrading guide. Its essence is as follows:



 class A1 {    private function priv() {} } class B1 extends A1 {} var_dump(method_exists(B1::class, 'priv')); // PHP 7.3: bool(true) // PHP 7.4: bool(false)
      
      





This feature, again, is hard to come across in real code. But, as it turned out, we unintentionally actively exploited this in tests.



Of course, we are confronted to different degrees with other incompatibilities, including numerous changes related to reflection ( example one , example two ), changes to hexdec () and the like, prohibition of array_key_exists () even for ArrayAccess objects, with incompatibilities in various dependency libraries connected via Composer, and even with all sorts of exotic things, such as stream_set_option (), which became mandatory for stream wrappers on include. But in sum, the costs of adapting to all these changes cannot be compared with the case of using the syntax of arrays on non-arrays.



At the moment, we have finished working with unit tests: they fully pass in PHP 7.4. We are working on API tests and plan to start switching between different clusters and environments by the end of the year.



I want to invite to this discussion for discussion: have you already tried PHP 7.4? If so, what was your experience like? Are you going to cross?



All Articles