framework icon indicating copy to clipboard operation
framework copied to clipboard

Uncaught Error: Class 'Doctrine\Common\Annotations\AnnotationReader' not found

Open jgiacobbi opened this issue 9 years ago • 27 comments

Hello, I'm trying to use Go in a project, but it's crashing out of the box. It seems strange to me because I would think a crash this basic would affect more people. Perhaps it's my environment. I added some print debugging to the composer ClassLoader and the AopComposerLoader. As you can see it successfully locates the files on disk and includes them, but in the case of the doctrine AnnotationReader it tries to apply the go.source.transforming.loader filter and crashes the program.

Searching for class Symfony\Component\Console\Application with extension .php File path before rewrite: /root/git/project/vendor/composer/../symfony/console/Application.php File path after rewrite: php://filter/read=go.source.transforming.loader/resource=/root/git/project/vendor/composer/../symfony/console/Application.php Searching for class Go\Instrument\Transformer\StreamMetaData with extension .php File path before rewrite: /root/git/project/vendor/composer/../goaop/framework/src/Instrument/Transformer/StreamMetaData.php File path after rewrite: /root/git/project/vendor/composer/../goaop/framework/src/Instrument/Transformer/StreamMetaData.php Including /root/git/project/vendor/composer/../goaop/framework/src/Instrument/Transformer/StreamMetaData.php Searching for class Go\Instrument\Transformer\WeavingTransformer with extension .php File path before rewrite: /root/git/project/vendor/composer/../goaop/framework/src/Instrument/Transformer/WeavingTransformer.php File path after rewrite: /root/git/project/vendor/composer/../goaop/framework/src/Instrument/Transformer/WeavingTransformer.php Including /root/git/project/vendor/composer/../goaop/framework/src/Instrument/Transformer/WeavingTransformer.php Searching for class Go\Core\AdviceMatcher with extension .php File path before rewrite: /root/git/project/vendor/composer/../goaop/framework/src/Core/AdviceMatcher.php File path after rewrite: /root/git/project/vendor/composer/../goaop/framework/src/Core/AdviceMatcher.php Including /root/git/project/vendor/composer/../goaop/framework/src/Core/AdviceMatcher.php Searching for class Go\Core\AspectLoader with extension .php File path before rewrite: /root/git/project/vendor/composer/../goaop/framework/src/Core/AspectLoader.php File path after rewrite: /root/git/project/vendor/composer/../goaop/framework/src/Core/AspectLoader.php Including /root/git/project/vendor/composer/../goaop/framework/src/Core/AspectLoader.php Searching for class Doctrine\Common\Annotations\AnnotationReader with extension .php File path before rewrite: /root/git/project/vendor/composer/../doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationReader.php File path after rewrite: php://filter/read=go.source.transforming.loader/resource=/root/git/project/vendor/composer/../doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationReader.php PHP Fatal error: Uncaught Error: Class 'Doctrine\Common\Annotations\AnnotationReader' not found in /root/git/project/vendor/goaop/framework/src/Core/GoAspectContainer.php:88 Stack trace: #0 /root/git/project/vendor/goaop/framework/src/Core/Container.php(65): Go\Core\GoAspectContainer->Go\Core{closure}(Object(Go\Core\GoAspectContainer)) #1 /root/git/project/vendor/goaop/framework/src/Core/Container.php(87): Go\Core\Container->Go\Core{closure}(Object(Go\Core\GoAspectContainer)) #2 /root/git/project/vendor/goaop/framework/src/Core/GoAspectContainer.php(50): Go\Core\Container->get('aspect.annotati...') #3 /root/git/project/vendor/goaop/framework/src/Core/Container.php(65): Go\Core\GoAspectContainer->Go\Core{closure}(Object(Go\Core\GoAspectContainer)) #4 /root/git/project/vendor/goaop/framework/src/Core/Container.php(87): Go\Core\Container->Go\Core{closure}(Object(Go\Core\GoAspectContainer)) #5 /root/git/project/vendor/goaop/framework/src/Core/GoAspectContai in /root/git/project/vendor/goaop/framework/src/Core/GoAspectContainer.php on line 88

jgiacobbi avatar Jun 16 '16 18:06 jgiacobbi

Hi, I have an idea that this is due to the composer update. Could you please, show me an information about:

  1. Version of PHP
  2. Version of goaop/framework
  3. Version of composer

lisachenko avatar Jun 17 '16 12:06 lisachenko

Hello. This is all from the machine I'm testing on. I'm running 16.04 server if that makes a difference.

php --version
PHP 7.0.4-7ubuntu2.1 (cli) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies
    with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies
cat composer.json | grep goaop
                "goaop/framework": "2.0.0"

I had the version set to "*", but I tried "2.0.0" as a debugging step. Didn't seem to make a difference.

composer --version
Composer version 1.1.2 2016-05-31 19:48:11

jgiacobbi avatar Jun 17 '16 12:06 jgiacobbi

Could you also show me the config for initialization, especially appDir, includePaths and excludePaths for your app.

Maybe you just include vendor libraries too? Not only the src folder of your app? In this case AOP will try to intercept and analyze itself and will definitely crash. To solve this, just add vendor directory to the excludePaths option.

lisachenko avatar Jun 17 '16 12:06 lisachenko

That was causing the crash. I had include paths set to ( ".." ). I didn't realize that was the issue because it was working perfectly for about three weeks before it started crashing. I gave a demo and everything. Strangeness.

Thanks for the help, and the framework!

jgiacobbi avatar Jun 17 '16 13:06 jgiacobbi

You are welcome! )

lisachenko avatar Jun 17 '16 13:06 lisachenko

I think that I should put a guard into the kernel that will throw an exception for this misconfiguration.

lisachenko avatar Jun 17 '16 13:06 lisachenko

More setup documentation would be helpful. It's easy to get 90% of the way there but if the starting example doesn't work it's hard to get more information.

jgiacobbi avatar Jun 17 '16 13:06 jgiacobbi

In some cases, we actually want to do AOP on dependencies resolved to the /vendor path (or other path that is configured). How would we go about preventing self initialization by default during the configuration phase?

Happy to commit to a PR as this improves integration stability. @lisachenko what do you think works best towards releasing a fix?

RubieV avatar Aug 24 '16 11:08 RubieV

Hi, @RubieV!

In the case when you want to apply AOP to vendor libraries as well, you should mark all framework dependencies as excluded to prevent analysis. Sorry, that I haven't put this guard because of lack of time (I'm learning for driving license and planning my new flat, so no free time for my OSS pojects)

I will be happy to accept a PR that can automatically calculate (or ask the composer) for directories of dependencies and put them into the excludePaths option. One more hint: could you please make a PR related to the 1,x branch for cascade merge (or we can check this new github feature for PR :smiley: ).

lisachenko avatar Aug 25 '16 07:08 lisachenko

This is a strange issue I am facing too. I am not sure if I understand the problem and how to fix it.

I just upgraded from 1.1.1 to 2.0.0 and now there is the error:

PHP Fatal error: Class 'Doctrine\Common\Annotations\AnnotationReader' not found in /var/www/xyz/vendor/goaop/framework/src/Core/GoAspectContainer.php on line 88

infabo avatar Aug 31 '16 11:08 infabo

OK, issue nailed down.

https://github.com/goaop/framework/blob/master/src/Instrument/FileSystem/Enumerator.php#L109

It is checked if the current realpath is within an excludePath.

Now in my setup, the exludepaths contains "..", so the comparison does not match:

$realpath -> /var/www/xyz/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationReader.php $excludePath = /var/www/xyz/vendor/composer/../doctrine

So there is no match and AOP tries to rewrite. How to overcome? I don't know why the ComposerLoader Prefixes contain a relative part?

infabo avatar Aug 31 '16 12:08 infabo

autoload_static.php in vendor/composer says:

public static $prefixesPsr0 = array (
        'D' =>
        array (
            'Doctrine\\Common\\Lexer\\' =>
            array (
                0 => __DIR__ . '/..' . '/doctrine/lexer/lib',
            ),
            'Doctrine\\Common\\Annotations\\' =>
            array (
                0 => __DIR__ . '/..' . '/doctrine/annotations/lib',
            ),
            'Dissect' =>
            array (
                0 => __DIR__ . '/..' . '/jakubledl/dissect/src',
            ),
        ),
    );

This is where it comes from. But why does it only affect me and not all others using GOAOP?

infabo avatar Aug 31 '16 12:08 infabo

wow, if I fix the path-problem with using realpath($excludePath) then the next fatal error rises:

PHP Fatal error: Class 'PhpParser\Node\Name' not found

edit:

Wow, really seems like you need to exclude the whole vendor path like said before, but then there will be another error:

Class Mage_Core_Controller_Varien_Action was not found by locator

Trace:
#0 /var/www/xyz/vendor/goaop/parser-reflection/src/ReflectionEngine.php(124): Go\ParserReflection\ReflectionEngine::locateClassFile('Mage_Core_Contr...')

infabo avatar Aug 31 '16 12:08 infabo

OK, now I got it. Had to implement my own Locator for this. But still got an issue, if the Locator can't resolve a specific classname - it still fails with "was not found by locator". Is there any way to avoid the exception? andrewsville/php-token-reflection did return a dummy class in this case.

$class = $broker->getClass('Nonexistent'); // returns a TokenReflection\Dummy\ReflectionClass instance

This is very annoying, upgrading from 1.x to 2.x is a pain....

infabo avatar Sep 01 '16 07:09 infabo

Ok, I can overcome this problem by creating a dummy-file on runtime. But it seems like in 2.x it is not possible anymore to intercept non-namespaced classes anymore....or it is a problem of the new parser reflection library, which fails to find a namespace.

Namespace was not found in the file /var/www/xyz/htdocs/app/code/core/Mage/Core/Model/Translate.php

bye bye, aop framework. It was a joy - until 2.x appeared. :/

infabo avatar Sep 01 '16 07:09 infabo

Hi, @infabo

Sorry for the inconvenience, I'm going to recheck each of your case, maybe on weekends or on my vacation. Unfortunately, I haven't free time right now, but I'm appreciate your time spending on debugging and reporting, so I'll definitely fix them all and report you in this task.

So you will know, that your work won't be lost. And hopefully, you will be able to return back to it with reliable behaviour.

Best regards, Alexander

lisachenko avatar Sep 06 '16 10:09 lisachenko

This should be related to https://github.com/goaop/parser-reflection/issues/31

lisachenko avatar Sep 06 '16 10:09 lisachenko

puh, after this long time it is even hard to follow my own debug-observations. Bug still there. :/

infabo avatar Jan 19 '17 11:01 infabo

The original problem seems to be, that Doctrine Annotations lib switched to PSR-4 (was PSR-0) before. So the excludePath detection does not work anymore, because the code only fetches composer PSR-0 prefixes.

infabo avatar Feb 21 '17 13:02 infabo

Wow, it seems like I have solved all the issues described by me above. Seems like the "thing" with "Namespace was not found in the file" is not an issue anymore. Works for now. Only drawback by now, v2.1.0 adds another ~200ms to my application time. Not clear what causing it, but since 1.x already had some runtime overhead - this is now beyond acceptable (maybe around 300-400ms extra). Not acceptable in my opinion.

infabo avatar Feb 21 '17 14:02 infabo

Hi, @infabo. Thank you for constant reporting! Issues with namespace should be fixed in goaop/parser-reflection, so yes, confirming that several cases were fixed.

But let's check what going on with performance. 2.x branch uses AST-based reflection, so parsing can be slower. But if cache is already prepared and opcache is enabled then fast hit is expected. Only known overhead exists with class loading. Could you report how many classes are loaded in your application for your typical request?

I know one way with ever tighter integration with composer to completely exclude this overhead with class loading with hot cache. But it requires a lot of changes in the engine. So let's start with numbers and reasons why your application performance is suffered. Maybe you could create 2 XDebug profiles without AOP/with AOP for me to check this for you?

lisachenko avatar Feb 21 '17 16:02 lisachenko

Is this issue still open?

shiva805 avatar Jul 03 '17 10:07 shiva805

i am surprised because "AnnotationReader" instance working vendor/goaop/framework/src/Core/GoAspectContainer.php constructor where as not working with anonymous (inside $this->share('aspect.annotation.reader', function(Container $container) {)

shiva805 avatar Jul 03 '17 14:07 shiva805

Hi, @shiva-050865

This issue is typically occurs when AOP framework tries to intercept it's own classes (you should check that vendor dir is excluded from processing). You can try to add vendor dir to the excludePaths option for the kernel.

Unfortunately, I tried to rewrite this part of code several times, but it's very tricky and I haven't succeeded yet. Maybe for v3.0 it will work without excluding framework's core libraries directories automatically.

lisachenko avatar Jul 03 '17 14:07 lisachenko

@lisachenko Thank you for response..

But once I ignored vendor from AspectKernel getting following error.

Catchable fatal error: Argument 1 passed to TestMonitorAspect::beforeMethodExecution() must implement interface Go\Aop\Intercept\MethodInvocation, instance of Go\Aop\Framework\StaticInitializationJoinpoint given, called in /media/drive/bejgam.shiva/vendor/goaop/framework/src/Aop/Framework/BeforeInterceptor.php on line 33 and defined in /media/drive/bejgam.shiva/app/aspect/TestMonitorAspect.php on line 29

php Version: PHP 5.6.22-1

shiva805 avatar Jul 05 '17 05:07 shiva805

@shiva-050865 Ah, looks like you are using within type of joinpoint. This joinpoint will match not only with public, protected and static methods, but also with class initialization and property access.

You should add additional qualifier like this: within(bla-bla-bla) && execution(public **->*(*)) to filter only public method execution.

Or you can change typehint to the Joinpoint class and just echo this instance to see what was intercepted by the AOP engine.

lisachenko avatar Jul 05 '17 11:07 lisachenko

@lisachenko Might be small question am not finding that how you are relating annotations with aspect.. am trying to create custom annotation with aspect. I just followed following article http://go.aopphp.com/blog/2013/07/21/implementing-logging-aspect-with-doctrine-annotations/

Am using yii2

shiva805 avatar Jul 06 '17 10:07 shiva805

No more relevant, as version 4 will use native PHP Attributes instead of Doctrine annotations.

lisachenko avatar Apr 13 '24 13:04 lisachenko