How it was
Not so long ago I ran into one problem that arose when moving to php 5.4. The task was to test the functionality that used native functions. By the way,
Fumocker copes with this task perfectly, allowing you to override the built-in functions in tests. I wrote a pack of tests and ran them locally. All tests were successful. Fine! The task was done and I was in complete happiness, until I added a project to
travis-ci . AND?
The build was broken under php 5.4, when under 5.3 everything was glowing green.
This fact led me to the idea that between 5.3 and 5.4 there should be a difference in the overload of functions.
Frankly, I have never before found information about this difference in the description of php 5.4 releases. Therefore, first of all I went to torture Google. But Google could not give a clear answer. All I found was about overloading methods, nothing more. This made me start experimenting with the code.
Well, let's get started?
The first desire arose to create a sandbox to reproduce the situation. For this, I wrote the simplest class that used the built-in function
range :
<?php
')
and a separate file with the redefinition of this function in the same scope:
<?php
Then I wondered what would happen if we include the files with the definition of the class and the function before creating the first
MyClass object:
<?php
In this case, the behavior is the same for the two versions:
$ php54 main.php Overridden
$ php53 main.php Overridden
But what should happen if you connect a file with a function after creating the first instance of
MyClass ?
<?php include_once("MyClass.php"); use MyNamespace\MyClass; $my_obj = new MyClass(); include_once("MyNamespaceFunctions.php"); $other_obj = new MyClass(); echo $my_obj->makeMeRange();
Still no difference:
$ php54 main.php Overridden
$ php53 main.php Overridden
The last chance remains to find the cause of the duplicity of behavior - try calling the function before turning on the file with redefining the same function:
<?php include_once("MyClass.php"); use MyNamespace\MyClass; $my_obj = new MyClass(); $my_obj->makeMeRange(); include_once("MyNamespaceFunctions.php"); $other_obj = new MyClass(); echo $other_obj->makeMeRange();
Aha Gotcha! $ php54 main.php PHP Notice: Array to string conversion in /Volumes/Projects/php-experiments/ …
$ php53 main.php Overridden
And the last-last experiment (I promise):
<?php include_once("MyClass.php"); use MyNamespace\MyClass; $my_obj = new MyClass(); $my_obj->makeMeRange(); include_once("MyNamespaceFunctions.php"); echo $my_obj->makeMeRange();
confirms the difference in function overload between 5.3 and 5.4:
$ php54 main.php PHP Notice: Array to string conversion in /Volumes/Projects/php-experiments/ …
$ php53 main.php Overridden
Eventually
It turns out that php 5.3 allows you to override the function at any time during the execution of the script, if the function has not been redefined before. When at the same time php 5.4 will use only the version of the function that was first used elsewhere in the code.
In addition to the problem described, this article raises a long-standing question - “the relevance of documentation”. Yes, we still have to use inadequate documentation at our own risk and peril. In my opinion, it is a shame on our heads.
PS: I created a repository to test the described behavior. In case you want to check for yourself, just clone the repository and run tests using phpunitPSS: And then there is open tikt # 63201 on bugs.php.net. Any participation in this question is welcome!