Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Class 'Hoa\Event\Bucket' not found #3907

Closed
MGatner opened this issue Oct 1, 2020 · 8 comments
Closed

Class 'Hoa\Event\Bucket' not found #3907

MGatner opened this issue Oct 1, 2020 · 8 comments

Comments

@MGatner
Copy link

MGatner commented Oct 1, 2020

Bug report

PHPStan is crashing during analysis that includes a controller trait from the framework. PHPUnit tests pass fine using the trait and I can see nothing else about the trait that would cause an issue.

  • Version: 0.12.48
  • OS: Ubuntu 20.04
  • PHP: 7.4
  • Error:
Fatal error: Uncaught Error: Class 'Hoa\Event\Bucket' not found in phar:///opt/phpstan-error/vendor/phpstan/phpstan/phpstan/vendor/hoa/stream/Stream.php:237
Stack trace:
#0 phar:///opt/phpstan-error/vendor/phpstan/phpstan/phpstan/vendor/hoa/stream/Stream.php(468): Hoa\Stream\Stream->close()
#1 phar:///opt/phpstan-error/vendor/phpstan/phpstan/phpstan/vendor/hoa/consistency/Xcallable.php(128): Hoa\Stream\Stream::_Hoa_Stream()
#2 [internal function]: Hoa\Consistency\Xcallable->__invoke()
#3 {main}
  thrown in phar:///opt/phpstan-error/vendor/phpstan/phpstan/phpstan/vendor/hoa/stream/Stream.php on line 237

Code snippet that reproduces the problem

Because of the framework dependency I cannot recreate on PHPStan.org, but I have created a new repo that has a barebones setup and still causes the issue: https://github.com/MGatner/phpstan-error

Expected output

Expected not to crash :)

Possible other occurrences of this "missing class" issue:

@mergeable
Copy link

mergeable bot commented Oct 1, 2020

This bug report is missing a link to reproduction on phpstan.org.
It will most likely be closed after manual review.

@MGatner
Copy link
Author

MGatner commented Oct 1, 2020

Full error output:

> phpstan analyze
Note: Using configuration file /opt/phpstan-error/phpstan.neon.dist.
PHP Fatal error:  require_once(): Failed opening required '/opt/phpstan-error/vendor/codeigniter4/codeigniter4/system/Test/ControllerTester.php' (include_path='.:/usr/share/php') in /opt/phpstan-error/vendor/codeigniter4/codeigniter4/system/Autoloader/Autoloader.php on line 380

Fatal error: require_once(): Failed opening required '/opt/phpstan-error/vendor/codeigniter4/codeigniter4/system/Test/ControllerTester.php' (include_path='.:/usr/share/php') in /opt/phpstan-error/vendor/codeigniter4/codeigniter4/system/Autoloader/Autoloader.php on line 380
PHP Fatal error:  Uncaught Error: Class 'Hoa\Event\Bucket' not found in phar:///opt/phpstan-error/vendor/phpstan/phpstan/phpstan/vendor/hoa/stream/Stream.php:237
Stack trace:
#0 phar:///opt/phpstan-error/vendor/phpstan/phpstan/phpstan/vendor/hoa/stream/Stream.php(468): Hoa\Stream\Stream->close()
#1 phar:///opt/phpstan-error/vendor/phpstan/phpstan/phpstan/vendor/hoa/consistency/Xcallable.php(128): Hoa\Stream\Stream::_Hoa_Stream()
#2 [internal function]: Hoa\Consistency\Xcallable->__invoke()
#3 {main}
  thrown in phar:///opt/phpstan-error/vendor/phpstan/phpstan/phpstan/vendor/hoa/stream/Stream.php on line 237

Fatal error: Uncaught Error: Class 'Hoa\Event\Bucket' not found in phar:///opt/phpstan-error/vendor/phpstan/phpstan/phpstan/vendor/hoa/stream/Stream.php:237
Stack trace:
#0 phar:///opt/phpstan-error/vendor/phpstan/phpstan/phpstan/vendor/hoa/stream/Stream.php(468): Hoa\Stream\Stream->close()
#1 phar:///opt/phpstan-error/vendor/phpstan/phpstan/phpstan/vendor/hoa/consistency/Xcallable.php(128): Hoa\Stream\Stream::_Hoa_Stream()
#2 [internal function]: Hoa\Consistency\Xcallable->__invoke()
#3 {main}
  thrown in phar:///opt/phpstan-error/vendor/phpstan/phpstan/phpstan/vendor/hoa/stream/Stream.php on line 237

@ondrejmirtes
Copy link
Member

Hi, the registered CodeIgniter autoloader does something invasive - it prepends itself before the PHPStan-registered autoloader and so when PHPStan tries to load some class it uses itself, it fails.

This method in vendor/codeigniter4/codeigniter4/system/Autoloader/Autoloader.php is the culprit:

	/**
	 * Register the loader with the SPL autoloader stack.
	 */
	public function register()
	{
		// Since the default file extensions are searched
		// in order of .inc then .php, but we always use .php,
		// put the .php extension first to eek out a bit
		// better performance.
		// http://php.net/manual/en/function.spl-autoload.php#78053
		spl_autoload_extensions('.php,.inc');

		// Prepend the PSR4  autoloader for maximum performance.
		spl_autoload_register([$this, 'loadClass'], true, true); // @phpstan-ignore-line

		// Now prepend another loader for the files in our class map.
		$config = $this->classmap;

		// @phpstan-ignore-next-line
		spl_autoload_register(function ($class) use ($config) {
			if (empty($config[$class]))
			{
				return false;
			}

			include_once $config[$class];
		}, true, // Throw exception
			false // Prepend
		);
	}

When I change true to false in the $prepend argument in the two spl_autoload_register calls then PHPStan starts to work.

@MGatner
Copy link
Author

MGatner commented Oct 1, 2020

Thanks for the fast response! Really great too by the way; I'm was very glad to see you launch a paid version.

I will start a conversation with the framework devs about how important it is for the Autoloader to prepend. I must say I have been using PHPStan with CodeIgniter 4 for weeks and this is the first issue I have had - is there something particular about that file, or the setup, that makes it crash? I've used plenty of other traits, during testing, crossing namespaces, etc... can't think of why this would be any different.

@ondrejmirtes
Copy link
Member

I might have a solution up my sleeve for this problem, so don't ask CI devs yet, I'll give it a try first. Stay tuned :)

@ondrejmirtes
Copy link
Member

Yeah, so I was able to get rid of the Hoa error by removing Consistency::registerShutdownFunction(xcallable(\'Hoa\\Stream\\Stream::_Hoa_Stream\')); from vendor/hoa/stream/Stream.php - this error was just a side effect and really weird - "why is the app talking about some Hoa library I'm not even using!?" phpstan/phpstan-src@edd5c3c

But the problem still persists:

PHP Warning:  require_once(/Users/ondrej/Downloads/phpstan-error/vendor/codeigniter4/codeigniter4/system/Test/ControllerTester.php): failed to open stream: "PHPStan\Reflection\BetterReflection\SourceLocator\FileReadTrapStreamWrapper::stream_open" call failed in /Users/ondrej/Downloads/phpstan-error/vendor/codeigniter4/codeigniter4/system/Autoloader/Autoloader.php on line 380

Warning: require_once(/Users/ondrej/Downloads/phpstan-error/vendor/codeigniter4/codeigniter4/system/Test/ControllerTester.php): failed to open stream: "PHPStan\Reflection\BetterReflection\SourceLocator\FileReadTrapStreamWrapper::stream_open" call failed in /Users/ondrej/Downloads/phpstan-error/vendor/codeigniter4/codeigniter4/system/Autoloader/Autoloader.php on line 380
PHP Fatal error:  require_once(): Failed opening required '/Users/ondrej/Downloads/phpstan-error/vendor/codeigniter4/codeigniter4/system/Test/ControllerTester.php' (include_path='/Users/ondrej/Development/phpstan/vendor/phing/phing/classes:.:/usr/local/Cellar/php/7.4.8/share/php/pear') in /Users/ondrej/Downloads/phpstan-error/vendor/codeigniter4/codeigniter4/system/Autoloader/Autoloader.php on line 380

Fatal error: require_once(): Failed opening required '/Users/ondrej/Downloads/phpstan-error/vendor/codeigniter4/codeigniter4/system/Test/ControllerTester.php' (include_path='/Users/ondrej/Development/phpstan/vendor/phing/phing/classes:.:/usr/local/Cellar/php/7.4.8/share/php/pear') in /Users/ondrej/Downloads/phpstan-error/vendor/codeigniter4/codeigniter4/system/Autoloader/Autoloader.php on line 380

And we could get rid of the error. The CI devs don't need to change anything about prepending the autoloader, that can stay, but the reason why this ends up in fatal error is because the autoloader uses require instead of include.

So you could persuade the devs to use include instead of require, or you could maybe override the method and use include in a child class instead.

Why include works and require doesn't in context of PHPStan - that would take a book to explain 😂 It's because of this logic: https://github.com/Roave/BetterReflection/blob/5b4d1c53768e2a3bc32ab348752663733fd70546/src/SourceLocator/Type/AutoloadSourceLocator.php#L149-L170 + https://github.com/Roave/BetterReflection/blob/4.11.x/src/SourceLocator/Type/AutoloadSourceLocator/FileReadTrapStreamWrapper.php

@MGatner
Copy link
Author

MGatner commented Oct 1, 2020

Thanks so much! I'm actually one of the CI devs so I will definitely lobby for this, assuming there is not some strange reason for the require. Also glad to see you got that bystander issue fixed :)

@github-actions
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 11, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants