phpDocumentor / Reflection

Reflection library to do Static Analysis for PHP Projects
MIT License
117 stars 51 forks source link

Class used traits not working in 5.0.0 #208

Closed josemmo closed 3 years ago

josemmo commented 3 years ago

In version 5.0.0, in contrast with 4.0.1, Class_::$usedTraits is never initialized when using ProjectFactory.

How to reproduce

index.php

use phpDocumentor\Reflection\File\LocalFile;
use phpDocumentor\Reflection\Php\ProjectFactory;
use phpDocumentor\Reflection\Php\Project;

require __DIR__ . "/vendor/autoload.php";

// Get project files
$files = [
    new LocalFile(__DIR__ . '/TestClass.php'),
    new LocalFile(__DIR__ . '/TestTrait.php')
];

/** @var Project */
$project = ProjectFactory::createInstance()->create('Project', $files);

// Validate output
$expectedClass = $project->getFiles()[__DIR__ . '/TestClass.php']->getClasses()['\App\TestClass'];
$expectedTrait = $expectedClass->getUsedTraits()['\App\TestTrait'] ?? null;
var_dump($expectedTrait);

TestClass.php

namespace App;

class TestClass {
    use TestTrait;

    public function sayBye() {
        echo "Bye!";
    }
}

TestTrait.php

namespace App;

trait TestTrait {
    public function sayHi() {
        echo "Hi!";
    }
}

Output

When using v4.0.1:

object(phpDocumentor\Reflection\Fqsen)#1218 (2) {
  ["fqsen":"phpDocumentor\Reflection\Fqsen":private]=>
  string(14) "\App\TestTrait"
  ["name":"phpDocumentor\Reflection\Fqsen":private]=>
  string(9) "TestTrait"
}

When using v5.0.0:

NULL
jaapio commented 3 years ago

Thanks for reporting this regression. I was looking into this topic some more. And I think we should revisit the way this library handles traits. version 4 had some limitations regarding the usage of traits. Since trait use is way more complex than this lib originally did. And I would like to introduce it full featured. Because we would need it for phpDocumentor itself.

The easiest syntax of traits is this:

class MyClass {
   use MyTrait;
}

But a full blown setup would be something like:

https://www.php.net/manual/en/language.oop5.traits.php#123648

class MyClass {
    use A, B, C {
        //visibility for methods that will be involved in conflict resolution
        B::smallTalk as public;
        A::bigTalk as public;

        //conflict resolution
        B::smallTalk insteadof A, C;
        A::bigTalk insteadof B, C;

        //aliases with visibility change
        B::bigTalk as public Btalk;
        A::smallTalk as public asmalltalk;

        //aliases only, methods already defined as public
        C::bigTalk as Ctalk;
        C::smallTalk as cmallstalk;
    }
}    

This would require a more complex model for used traits. Which we should introduce.

jaapio commented 3 years ago

I reintroduced the original behavior. I will start working on the more complex implementation soon. This will be a different method.