Thanks to visit codestin.com
Credit goes to github.com

Skip to content

phpDocumentor\Reflection\Php\File not extendable #207

@Chrico

Description

@Chrico

Glossary

  • Strategies/Strategy = phpDocumentor\Reflection\Php\ProjectFactoryStrategy
  • Element(s) = phpDocumentor\Reflection\Element
  • ProjectFactory = phpDocumentor\Reflection\Php\ProjectFactory
  • File = phpDocumentor\Reflection\Php\File
  • ContextStack = phpDocumentor\Reflection\Php\Factory\ContextStack

Is your feature request related to a problem? Please describe.

I'd like to implement some custom Strategies and Element to parse out of a framework function-calls (similar to what phpDocumentor\Reflection\Php\Factory\Define does).

The ProjectFactory allows to add in its constructor Strategies. The Strategies are build based on the ProjectFactoryStrategy-interface. So it is possible to implement own ones.

class CustomStrategy extends Factory\AbstractFactory implements ProjectFactoryStrategy
{

    public function matches(ContextStack $context, object $object): bool
    {
        return true;
    }

    protected function doCreate(ContextStack $context, object $object, StrategyContainer $strategies): void
    {
        // do something
    }
}

and register them:

$strategies = new ProjectFactoryStrategies([new CustomStrategy()]);
$projectFactory = new ProjectFactory($strategies);

Inside of each Strategy it is possible to access the current File via $file = $context->peek(); in doCreate() via ContextStack. This File implementation is not extendable in many ways:

  1. The File-class is final.
  2. The class only restricts to Element implementation via add*-method (addTrait(), addInterface(), addClass(), ...).
  3. Those Element-implementations like phpDocumentor\Reflection\Php\Constant, phpDocumentor\Reflection\Php\Function_ are all final as well, so not extendable.

On ContextStack we also have no possibility to do anything to Project or File. You can access the Project via ContextStack::getProject() but not decorate/extend it and set back to the stack. Same goes for File.


Describe the solution you'd like

There are 2 options (plus 1 bonus) which come into my mind:

v1)

In 2. it could be possible to extend the phpDocumentor\Reflection\Php\File-class by 2 new methods:

/**
 * @param Element $element
 */ 
public function addCustomElement(Element $element): void
{
    $this->customElements[(string)$element->->getFqsen()] = $element;
}

/**
 * @return Element[]
 */ 
public function getCustomElements(): array 
{
    return $this->customElements;
}

This would allow to implement some custom Elements and set those in Strategies to the File to access them lateron via the Project::getFiles() again:

foreach($project->getFiles() as $file) {
     foreach($file->getCustomElements()() as $customElements) {
          // let's go.
     }
}

v2)

Remove from 3. the final from all classes which implement Element to allow to extend them. This way you could have:

class MyCustomFunction extends phpDocumentor\Reflection\Php\Function_
{
     public function setSomething(): void
     {
           // ..
     }
}

And set this via File::addFunction() in a Strategy to access it lateron via:

foreach($project->getFiles() as $file) {
     foreach($file->getFunctions() as $func) {
          if($func instanceof MyCustomFunction::class){
               // do something
          }
     }
}

v3)

And last but not least to cover my specific use case: Add similar to phpDocumentor\Reflection\Php\Factory\Define following new classes:

  • phpDocumentor\Reflection\Php\Factory\FunctionCall (a Strategy)
  • phpDocumentor\Reflection\Php\FunctionCall (an Element)

to collect all inline function calls in Files. This could be parsed by an own Strategy, so it could be removed/not added to avoid overhead and File could have new methods:

/**
 * @param FunctionCall$element
 */ 
public function addFunctionCall(FunctionCall $funcCall): void
{
    $this->funcCalls[(string)$funcCall->->getFqsen()] = $funcCall;
}

/**
 * @return funcCall[]
 */ 
public function getFunctionCalls(): array 
{
    return $this->funcCalls;
}

Access could be easy as all others are:

foreach($project->getFiles() as $file) {
     foreach($file->getFunctionCalls()() as $funcCalls) {
          // let's go.
     }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions