AspectMock icon indicating copy to clipboard operation
AspectMock copied to clipboard

Parent class not found by locator

Open biserantonov opened this issue 7 years ago • 10 comments

When using custom autoloader and try to get an instance of a class which has parent or implements an interface form the same custom namespace I have an error "PHP Fatal error: Uncaught InvalidArgumentException: Class [parent class name] was not found by locator in /workspace/projects/test/vendor/goaop/parser-reflection/src/ReflectionEngine.php:112".

I have very simple setup:

<?php

require_once __DIR__ . '/vendor/autoload.php';

$kernel = AspectMock\Kernel::getInstance();
$kernel->init([
    'debug' => true,
    'includePaths' => [__DIR__. '/lib'],
]);
$kernel->loadFile(__DIR__ . '/autoload.php'); // custom autoloader

$b = new \lib\B();

Class \lib\B:

namespace lib;

class B extends A {}

Class \lib\A:

namespace lib;

class A
{
    public function getName()
    {
        return static::class;
    }
}

Class B is loaded via my custom autoloader, but then the locator tries to load parent class A via composer autoloader and returns this error. Is this a bug, or I'm doing something wrong?

biserantonov avatar Dec 05 '16 09:12 biserantonov

I am also seeing this error. It appears it is the goasp framework's Go\ParserReflection\ReflectionEngine::$locator that causes the issue. I don't see where AspectMock touches the engine which is bootstrapped to use the Go\ParserReflection\Locator\ComposerLocator.

I'm currently trying to correct the issue by calling ReflectionEngine::init with a combination of FilterInjectorTransformer but haven't found the key yet.

pdelre avatar Dec 05 '16 21:12 pdelre

I've had limited success with having a Locator that autoloads the class then and uses \ReflectionClass to report what file it is loaded from. I am eventually getting a segfault/xdebug nesting limit however.

<?php

require_once __DIR__ . '/vendor/autoload.php';

$kernel = AspectMock\Kernel::getInstance();
$kernel->init([
    'debug' => true,
    'includePaths' => [__DIR__. '/lib'],
]);
$kernel->loadFile(__DIR__ . '/autoload.php'); // custom autoloader

// set the autoloading Locator
\Go\ParserReflection\ReflectionEngine::init(new lib\AutoLoadingLocator());

$b = new \lib\B();

Class \lib\AutoLoadingLocator:

namespace lib;

class AutoLoadingLocator implements \Go\ParserReflection\LocatorInterface {
  public function locateClass($className) {
    return (new ReflectionClass($className))->getFileName();
  }
}

pdelre avatar Dec 05 '16 22:12 pdelre

Hi, guys! In order to use custom autoloader you should re-init ReflectionEngine with composite class locator that will be able to locate your classes or you can use CallableLocator with closure for resolving paths.

Or, even better you could switch your code base to the PSR0/PSR-4 :+1:

lisachenko avatar Dec 06 '16 06:12 lisachenko

Thank you both for the responses. I'm using Yii2 framework for my project so I added psr-0 autoloader in composer and fixed the issue, but since I didn't saw it in the examples I wasn't sure if this is the right way to do it. Maybe it's good idea to update examples.

biserantonov avatar Dec 06 '16 08:12 biserantonov

Thank you for the verification. We won't be able to change our codebase to PSR-0/4 but I could modify our autoloaders to expose the path resolving and see if that resolves the segfaulting from relying on \Reflection.

pdelre avatar Dec 06 '16 12:12 pdelre

I believe the segfault I was seeing is actually around https://github.com/goaop/parser-reflection/issues/43. Will update that project with any new issues.

Getting into an inf loop with a class like this:

class Foo {
    const MINUTE = 60;
    const HOUR = 3600;

    const DEFAULT = self::MINUTE;
}

pdelre avatar Dec 06 '16 15:12 pdelre

Hi, guys! In order to use custom autoloader you should re-init ReflectionEngine with composite class locator that will be able to locate your classes or you can use CallableLocator with closure for resolving paths.

hi @lisachenko could you point to or provide an example for this?

I have some locator issues using a facade class which calls classes using a variable

kzap avatar Sep 16 '17 04:09 kzap

@kzap i had the exact same issue getting AspectMock to work while using classes in the root namespace.

Think of the following structure i had

<?php
class dataobject {}
<?php
namespace fubar;

class A extends \dataobject {}

I got the same error that the class dataobjectcould not be located. The locator looked into the classmap of composer and couldn't find the class.

After i moved dataobject into a namespace (e.g. fu\dataobject) everything worked as intended.

icanhazstring avatar Mar 22 '18 18:03 icanhazstring

@icanhazstring Yes thats what I did, put everything inside a Namespace and it worked :)

kzap avatar Apr 11 '18 14:04 kzap

Sorry for playing an archeologist but I recently ecnountered similar problem. The difference is that I use no custom autoloader and everything is inside namespaces. But if I extend my classes or implement my interfaces it throws exact same errors

Class app\controllers\BaseController was not found by locator
Class app\models\MyInterface was not found by locator

I would appreciate any input cause im running out of ideas.

gglazewski avatar Jan 16 '20 09:01 gglazewski