9

Debugging legacy code and I have a strange issue. The legacy code is being moved to PHP 7.2. I don't know which version of PHP it was originally written for but it does work in PHP 5.6.

Below is my example of the problem...

$variable = '';
$variable['key'] = 'Hello World!';

echo $variable['key'] // H

When I echo $variable['key'] it only gets the first character from the value. I know now that it is because $variable is initially declared as a string.

But why does this work in PHP 5.6? What can I do to make this work in 7.2 without trawling through thousands of lines of code?

Is there a directive like strict_types I can use?

itsliamoco
  • 1,028
  • 1
  • 12
  • 28
  • 1
    For anyone curious about the output in different PHP versions: https://3v4l.org/Q8iiY – Namoshek Nov 16 '18 at 16:07
  • 4
    It's because the string `'key'` when treated as an integer becomes `0` - since `$variable` is a string what you're doing is `'Hello World'[0]` ... which is `H` – CD001 Nov 16 '18 at 16:07
  • 1
    ^^^ So remove `$variable = '';` or do `$variable = [];` – AbraCadaver Nov 16 '18 at 16:08
  • Can't find any reference to this behavior in my limited searches but chances are you'll just want to fix all the buggy code -- which, hopefully your project isn't too large. This is incorrect syntax either way, not really sure why PHP 5 would behave like that except: PHP. Can't find any related php.ini settings either. – sheng Nov 16 '18 at 16:11
  • Unfortunately, `phpstan` doesn't consider this bad code. So I also don't see a good way of automatically fixing these issues. – Namoshek Nov 16 '18 at 16:14
  • Not sure, but maybe `call_user_func()` can help there: http://php.net/manual/en/function.call-user-func.php . You can also `eval()` there, but it won't be well seen ;) Good luck! – NVRM Nov 16 '18 at 16:21
  • May be I am wrong .. But try var_dump($variable) it will revel more .. – Confused Nov 16 '18 at 16:33

1 Answers1

6

From php.net

Warning Writing to an out of range offset pads the string with spaces. Non-integer types are converted to integer. Illegal offset type emits E_NOTICE. Only the first character of an assigned string is used. As of PHP 7.1.0, assigning an empty string throws a fatal error. Formerly, it assigned a NULL byte.

http://php.net/manual/en/language.types.string.php#language.types.string.substr

So "key" is converted to 0, and the first character is set. Because this is a char type, only "H" is set from the given string.

$variable = '';
$variable['key'] = 'Hello World!';

echo $variable;       
echo $variable['key'];

If you change your code to the above you can see better what happens.

So the text 'ello World!' is lost and gone in PHP >= 7.1 because you set the first character, the type stays string.

In php 5.6 you will get Notice: Array to string conversion in /in/N2poP on line 6

So in prior versions you overwrite the complete variable, and the initial empty string would be gone, PHP simply creates a new array. This behavior only happens with an empty string!

This is also noted in the documentation: http://php.net/manual/en/language.types.string.php#language.types.string.substr

Note: As of PHP 7.1.0, applying the empty index operator on an empty string throws a fatal error. Formerly, the empty string was silently converted to an array.

The easiest solution would be removing the $variable = ''; part, it's invalid anyway and never used in your legacy code. or by replacing it with $variable = [];

Because this behavior only happens with an empty string in php < 7.1 you could use a regular expression to find all places where you should refactor to fix the issue.

Sander Visser
  • 4,144
  • 1
  • 31
  • 42