Fatal error: Uncaught Error: [] operator not supported for strings in

This post was updated at November 2020 with fresh know-how.
What is new?

Switched deprecated --set option to rector.php config. Switched YAML to PHP configuration.


That's right! PHP 5.6 and 7.0 are entering EOL - end of line life this December. Social networks, Slacks, Twitter, Reddit are full of it. Are you running PHP 7.1? Good, come next year when PHP 7.1 is eoling.

For the rest of you, what will you do when PHP will tell you the message in the title?

The most important info from PHP.net nowadays


You see all this social boom, your boss is scared by "no security support" and you finally have a go to upgrade your PHP code to PHP 7.1. You upgrade your PHP locally to see if everything works:

"Warning: count(): Parameter must be an array or an object that implements Countable in"
"Fatal error: Uncaught Error: [] operator not supported for strings in"
"Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; Filter has a deprecated constructor in"
"Fatal error: Uncaught Error: Call to undefined function ereg() in"
"Fatal error: Cannot use empty list in"

You're probably thinking lets jump to PHP 7.2, while you're at it:

"Deprecated: The each() function is deprecated. This message will be suppressed on further calls in"

Don't do it, always jump by minor versions - for both PHP and packages.


Actually, when you see a message - that's a good sign. How else would you notice this?

// PHP 5.6-
list($a[], $a[]) = [1, 2];

// to get same result in PHP 7.0+
list($a[], $a[]) = array_reverse([1, 2])

True story - see 3v4l.org. The nice silent error just for you!

"I Got This"

But let's say you know that "Deprecated: The each() function is deprecated. This message will be suppressed on further calls in" means refactor each each() usage to foreach().

(Often it's more complicated, but keep this simple for now.)

Some cases are easy, if your variables are well-named:

while (list($key, $callback) = each($callbacks)) {
    // ...
}

foreach ($callbacks as $key => $callback) {
    // ...
}

But some... how would you change this one?

while (list($callback) = each($callbacks)) {
    // ...
}

foreach ($callbacks as $callback) {
    // ...
}

Are you sure? I think it should be like this:

foreach (array_keys($callbacks) as $callback) {
    // ...
}
See pull-request #661

Honestly, I'm not sure either. But I took time to test all possible each() combinations with list(), while() and do/while, put them into awesome 3v4l.org, wrote a bunch of tests and wrote tested rules for Rector.


"Fatal error: Uncaught Error: Call to undefined function ereg() in"

How Rector got into pure PHP Upgrades

At the PHP Asia Conference Rasmus Lerdorf spoke about upgrading PHP as a big problem. Much bigger than upgrading particular frameworks. Many WTF namings in PHP are just for BC sake. I struck me, that there is much more legacy PHP code in every company than there is framework-bound code.

I instantly created an issue at Rector, that deals with PHP 5.3 to 7.4 upgrades. I went full-time on writing PHP upgrade rules - in the train, in the buss, in the plane (the best place to code actually, wonder why).


Today I'm proud to announce 7 new Rector levels that were not here a month ago:

use Rector\Core\Configuration\Option;
use Rector\Set\ValueObject\SetList;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Rector\Config\RectorConfig;

return function (RectorConfig $rectorConfig): void {
    $rectorConfig->sets([
        SetList::PHP_54,
        SetList::PHP_55,
        SetList::PHP_56,
        SetList::PHP_70,
        SetList::PHP_71,
        SetList::PHP_72,
        SetList::PHP_73,
        SetList::PHP_74,
    ]);
};

I finally looked over my small framework bubble and learned a lot about problems of the world PHP community.

How to ereg Correctly?

One example for all:

See pull-request #661
"Fatal error: Uncaught Error: Call to undefined function ereg() in"

That's easy, just add # around and change the function name, right?

-ereg('hi', $string);
+preg_match('#hi#', $string);

But what about?

ereg('[]-z]', $string);
ereg('^[a-z]+[.,][a-z]{3,}$', $string);

Don't reinvent the wheel! Did you know that 8 years ago some guy wrote ereg → preg patterns converter? That some guy is Kang Seonghoon and helped hundreds if not thousands of people to not to give a fuck. Including me. Amazing work and I learned about it just by accidental googling. I wonder how many hidden gems are out there.

Harder, Better, Faster, Stronger... PHP Community

Take the Rector out, run it on your code, let it fix what it can and report the rest you had to do manually in the issues. Maybe it can be automated. You'll be helping each other developer, who upgrades the same PHP version you did. Imagine PHP version 5.3 would be shipped with set like this, covering 100 % of all changes. It's up to us to make a brighter future now.


Happy coding!




Do you learn from my contents or use open-souce packages like Rector every day?
Consider supporting it on GitHub Sponsors. I'd really appreciate it!