20
votes

I've been fighting this for a bit, and can't figure it out, maybe someone else has or maybe there's a deeper issue here with Slim, PHP, Apache etc. After working just fine for hours, my Slim install will start giving this on all routes:

Fatal error: Class Slim\Collection contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (IteratorAggregate::getIterator) in F:\Projects\example\server\vendor\slim\slim\Slim\Collection.php on line 21

Maddeningly this issue goes away if I restart Apache. (For a few hours anyway.)

I found this where someone had a similar problem two years ago, and the person helping badgered them without actually assisting at all: https://community.apachefriends.org/viewtopic.php?p=250966&sid=96ef58aaeb7fe142a7dcdfd506a8683f

I've tried doing a clean wipe and install of my composer vendor directory. This doesn't fix it. I can clearly see that getIterator is implemented as expected in the file in the error message.

PHP Version 7.0.12, Windows 7, x86 PHP Build

It happened again after a few hours, with a different but similar error message:

Fatal error: Class Pimple\Container contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (ArrayAccess::sqlserver) in F:\Projects\example\server\vendor\pimple\pimple\src\Pimple\Container.php on line 34

This question has a similar problem and "solves" it by restarting PHP, but that clearly isn't an actual solution, and I don't have opcache enabled: PHP 7, Symfony 3: Fatal error 1 abstract method and must therefore be declared abstract or implement the remaining methods

Any guesses? Remember: This message is in files I didn't write, and goes away on Apache restart. Is there some caching with PHP 7 that would cause this?

Edit 3/10/17:

Yes, I've opened a ticket with Slim. I also saw it in a non-slim file (Pimple) so I don't think it is a Slim issue. https://github.com/slimphp/Slim/issues/2160

As I said, my opcache is off. I've confirmed this is true both in the php.ini file and looking at phpinfo().

4
I've tried updating to PHP 7.1 and still am hitting this once a day, forcing an apache restart.Will Shaver
This is similar to my issue: phabricator.wikimedia.org/T152502Will Shaver
I don't have experience with slim so is this the problem file? github.com/slimphp/Slim-Http/blob/master/src/Collection.php If not, then could you post the code? Have you tried contacting the maintainers of the framework?MonkeyZeus
Can you re-create the scenario with a fiddle? It surprises me that an apache restart fixes this since you are mentioning that Opcache is disabled anyway. If constructing the class from the cli works 100% of the time and cache is disabled. Then you need to look at the code. Also are you 100% sure that you don't have another class called "Container" that is in a different namespace and its not trying to instantiate the wrong one under certain conditions?Daryl B
This isn't something I can put in a jsfiddle or similar. The issue is with existing standard libraries, and the code is fine. (As evidenced by the restarting fixing the issue.) Maddeningly, the issue has since gone away but I can't figure out why or if it will return. Quite frustrated. If you're here hoping for a solution, please comment to keep this thread alive.Will Shaver

4 Answers

12
votes

I think you've run into this opcache bug. This isn't exactly the same situation but probably related.

After calling opcache_reset() function we encounter some weird errors. It happens randomly on servers (10 of 400 servers production)

Some letter a replaced by others, Class seems to be already declared.. etc

Example of errors triggered after opcache_reset():

  • PHP Fatal error: Class XXX contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (YYY::funczzz) in /dir/dir/x.php on line 20

The ticket is closed because the developers don't have enough information to reproduce it. If you could come up with the smallest reproducible case I recommend reporting it. Create a very small Slim app and then use JMeter or another tool to make many requests. Post your findings.

Meanwhile the only workaround might be to turn off opcache in php.ini:

opcache.enable=0

Of course this will drastically hurt performance. Until it's fixed you'll have to choose between performance or periodically restarting Apache.

If turning the cache off doesn't work then the only cause I could think of is an intermittent problem with the opcode compiler. Cached or not the compiled version must have an error in it. Opening a reproducible ticket with the PHP devs or debugging the PHP source yourself would be the only way forward if this is the cause.

2
votes

I had the same problem using CodeIgniter and PHP 7.1.x.

I upgraded to PHP 7.2 and the problem no longer occurred.

1
votes

If you develop on Windows, I would recommend that you DON'T use XAMPP or WAMPP, and try out a real development server using Linux on a VM.

Try installing Vagrant and Virtualbox, then head to puphpet.com, which can generate you a virtual machine configuration. Unzip the download, cd in to the folder, type vagrant up. Then just point your host at the VM. I'll bet once you have a real development environment that this error will go away. Your other option is Docker, but that has a bit of a learning curve.

The problem isn't your code (or your vendor code), but your platform.

0
votes

I have encountered this exact behaviour and it was not exactly an opcache bug, even if it was caused by opcache.

The problem was that we had several classes with the same base name, e.g.

Request\GenericProtocol\Dispatcher     abstract
Request\Protocol1\Dispatcher
Request\Protocol2\Dispatcher

Now by default on our installation opcache used an "optimization" that used the basename only as cache key. As a result, whenever a script happened to instantiate a Protocol2 Dispatcher on a clean cache, it subtly sabotaged all subsequent calls with Protocol1. Due to usage patterns, this masqueraded as any other kind of bug.

In the end we just activated the appropriate option:

opcache.use_cwd boolean

If enabled, OPcache appends the current working directory to the script key, thereby eliminating possible collisions between files with the same base name. Disabling this directive improves performance, but may break existing applications.

The breaking condition is this: you have at least two classes with the same basename.

Our next iteration indeed is scheduled to rename a lot of classes

 Request\Protocol1\Dispatcher   ==> Request\Protocol1\Protocol1Dispatcher

to be able to re-disable use_cwd and squeeze a few percents of performance (PTBs and PHBs believe it is worth it), but I know that this may not be possible with every framework out there.