Git Product home page Git Product logo

reflection's Introduction

License: MIT Qa workflow Coveralls Coverage Scrutinizer Code Coverage Scrutinizer Code Quality Stable Version Unstable Version

Reflection

Using this library it is possible to statically reflect one or more files and create an object graph representing your application's structure, including accompanying in-source documentation using DocBlocks.

The information that this library provides is similar to what the (built-in) Reflection extension of PHP provides; there are however several advantages to using this library:

  • Due to its Static nature it does not execute procedural code in your reflected files where Dynamic Reflection does.
  • Because the none of the code is interpreted by PHP (and executed) Static Reflection uses less memory.
  • Can reflect complete files
  • Can reflect a whole project by reflecting multiple files.
  • Reflects the contents of a DocBlock instead of just mentioning there is one.
  • Is capable of analyzing code written for any PHP version (starting at 5.2) up to and including your installed PHP version.

Features

  • [Creates an object graph] containing the structure of your application much like a site map shows the structure of a website.
  • Can read and interpret code of any PHP version starting with 5.2 up to and including your currently installed version of PHP.
  • Due it's clean interface it can be in any application without a complex setup.

Installation

In order to inspect a codebase you need to tell composer to include the phpdocumentor/reflection package. This can easily be done using the following command in your command line terminal:

composer require phpdocumentor/reflection:~5.0

After the installation is complete no further configuration is necessary and you can immediately start using it.

Basic Usage

This Reflection library uses PSR-4 and it is recommended to use a PSR-4 compatible autoloader to load all the files containing the classes for this library.

An easy way to do this is by including the composer autoloader as shown here:

include 'vendor/autoload.php';

Once that is done you can use the createInstance() method of the \phpDocumentor\Reflection\Php\ProjectFactory class to instantiate a new project factory and pre-configure it with sensible defaults. Optional you can specify the parser version that shall be used as an argument of createInstance(). By default the php7 parser is prefered. And php5 is used as a fallback. See the documentation of phpparser for more info.

$projectFactory = \phpDocumentor\Reflection\Php\ProjectFactory::createInstance();

At this point we are ready to analyze your complete project or just one file at the time. Just pass an array of file paths to the create method of the project factory.

$projectFiles = [new \phpDocumentor\Reflection\File\LocalFile('tests/example.file.php')];
$project = $projectFactory->create('My Project', $projectFiles);

When the process is ready a new object of type phpDocumentor\Reflection\Php\Project will be returned that contains a complete hierarchy of all files with their classes, traits and interfaces (and everything in there), but also all namespaces and packages as a hierarchical tree.

See the example script for a detailed and commented example

reflection's People

Contributors

adrianhardy avatar arogachev avatar ashnazg avatar benji07 avatar boekkooi avatar boenrobot avatar carusogabriel avatar cebe avatar dependabot-preview[bot] avatar dependabot[bot] avatar dirx avatar donatj avatar gammamatrix avatar github-actions[bot] avatar gquemener avatar grahamcampbell avatar hemberger avatar jaapio avatar jeromegamez avatar joncave avatar jrfnl avatar ksimka avatar leovie avatar mbed67 avatar mvriel avatar othercorey avatar rgeraads avatar sonnysantino avatar staabm avatar wintersilence avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

reflection's Issues

FileReflector fails to process file with class constant visibility modifier

Class like

test.php

class My {
    public const DYMMY = 1;
}

generates parser error Parse Error: Syntax error, unexpected T_CONST, expecting T_FUNCTION

Code example
parser.php

<?php
require_once('vendor/autoload.php');

use phpDocumentor\Reflection\FileReflector;

$reflector = new FileReflector('test.php', true);
$reflector->process();

composer.json

"require": {
  "php": ">=7.1.0",
   "phpdocumentor/reflection": ">=3.0.0",
    "phpdocumentor/reflection-docblock": "~2.0"
}

Add support for php8 Attributes

https://wiki.php.net/rfc/attributes_v2

At the moment it is unsure what attributes will add to this library. But we should be able to detect the docblocks correctly.
Maybe add attributes as objects on their parent:

  • functions (including closures and short closures)
  • classes (including anonymous classes), interfaces, traits
  • class constants
  • class properties
  • class methods
  • function/method parameters

More?

Parameter type hint ignored

class C {
  function foo(MyArgInterface $x) {
  }
}

Here it seems that phpDocumentor does not detect the "MyArgInterface" argument type.
nikic's php-parser does correctly detect the type, but then here in \phpDocumentor\Reflection\Php\Factory\Argument::create():

    return new ArgumentDescriptor($object->name, $default, $object->byRef, $object->variadic);

This should be changed to

    $argDescriptor = new ArgumentDescriptor($object->name, $default, $object->byRef, $object->variadic);
    if (!empty($object->type)) {
        $argDescriptor->addType((string)$object->type);
    }
    return $argDescriptor;

So it adds the type.

Not sure what other consequences this would have, so I am just proposing this for discussion.

Upgrade nikic/php-parser

The required version of the nikic/php-parser package is still ~0.9.4 on the master branch. Would it be possible to use a version 1.0 or superior or the develop branch will be merged to the master soon?

Reflection is not standalone

Although this Reflection library is its own package it is not standalone as it depends on phpDocumentor\Event\Dispatcher from phpdocumentor/phpdocumentor. See the BaseReflector for example.

This means that any package that requires just phpdocumentor/reflection cannot actually use it directly without encountering fatal errors.

A couple of options I can think of:

  • Require Symfony's event dispatcher (it's currently only suggested) and require a dispatcher instance to be injected
  • Require phpdocumentor/phpdocumentor --- this kind of defeats the point of a separate package for Reflection
  • Make a new phpdocumentor/event-dispatcher package that both Reflection and phpDocumentor2 can use

Cannot use ProjectFactory in a PHPUnit test

This simple test case fail:

<?php

namespace Dunglas\PhpDocToTypeHint\Tests;

class ConverterTest extends \PHPUnit_Framework_TestCase
{
    public function testConvertFunction()
    {
        \phpDocumentor\Reflection\Php\ProjectFactory::createInstance();
    }
}

Here is the stack trace:

kdbook:phpdoc-to-type-hint dunglas$ php ../phpunit.phar tests/ConverterTest.php 
PHPUnit 5.0.8 by Sebastian Bergmann and contributors.

PHP Fatal error:  Cannot use phpDocumentor\Reflection\Types\Context as Context because the name is already in use in /Users/dunglas/workspace/phpdoc-to-type-hint/vendor/phpdocumentor/reflection-docblock/src/DocBlock/StandardTagFactory.php on line 18
PHP Stack trace:
PHP   1. {main}() /Users/dunglas/workspace/phpunit.phar:0
PHP   2. PHPUnit_TextUI_Command::main() /Users/dunglas/workspace/phpunit.phar:509
PHP   3. PHPUnit_TextUI_Command->run() phar:///Users/dunglas/workspace/phpunit.phar/phpunit/TextUI/Command.php:105
PHP   4. PHPUnit_TextUI_TestRunner->doRun() phar:///Users/dunglas/workspace/phpunit.phar/phpunit/TextUI/Command.php:154
PHP   5. PHPUnit_Framework_TestSuite->run() phar:///Users/dunglas/workspace/phpunit.phar/phpunit/TextUI/TestRunner.php:425
PHP   6. PHPUnit_Framework_TestCase->run() phar:///Users/dunglas/workspace/phpunit.phar/phpunit/Framework/TestSuite.php:747
PHP   7. PHPUnit_Framework_TestResult->run() phar:///Users/dunglas/workspace/phpunit.phar/phpunit/Framework/TestCase.php:727
PHP   8. PHPUnit_Framework_TestCase->runBare() phar:///Users/dunglas/workspace/phpunit.phar/phpunit/Framework/TestResult.php:617
PHP   9. PHPUnit_Framework_TestCase->runTest() phar:///Users/dunglas/workspace/phpunit.phar/phpunit/Framework/TestCase.php:771
PHP  10. ReflectionMethod->invokeArgs() phar:///Users/dunglas/workspace/phpunit.phar/phpunit/Framework/TestCase.php:908
PHP  11. Dunglas\PhpDocToTypeHint\Tests\ConverterTest->testConvertFunction() phar:///Users/dunglas/workspace/phpunit.phar/phpunit/Framework/TestCase.php:908
PHP  12. phpDocumentor\Reflection\Php\ProjectFactory::createInstance() /Users/dunglas/workspace/phpdoc-to-type-hint/tests/ConverterTest.php:9
PHP  13. phpDocumentor\Reflection\DocBlockFactory::createInstance() /Users/dunglas/workspace/phpdoc-to-type-hint/vendor/phpdocumentor/reflection/src/phpDocumentor/Reflection/Php/ProjectFactory.php:54
PHP  14. spl_autoload_call() /Users/dunglas/workspace/phpdoc-to-type-hint/vendor/phpdocumentor/reflection/src/phpDocumentor/Reflection/Php/ProjectFactory.php:52
PHP  15. Composer\Autoload\ClassLoader->loadClass() /Users/dunglas/workspace/phpdoc-to-type-hint/vendor/phpdocumentor/reflection/src/phpDocumentor/Reflection/Php/ProjectFactory.php:52
PHP  16. Composer\Autoload\includeFile() /Users/dunglas/workspace/phpdoc-to-type-hint/vendor/composer/ClassLoader.php:301

Fatal error: Cannot use phpDocumentor\Reflection\Types\Context as Context because the name is already in use in /Users/dunglas/workspace/phpdoc-to-type-hint/vendor/phpdocumentor/reflection-docblock/src/DocBlock/StandardTagFactory.php on line 18

Call Stack:
    0.0454     645640   1. {main}() /Users/dunglas/workspace/phpunit.phar:0
    0.1077   11601624   2. PHPUnit_TextUI_Command::main() /Users/dunglas/workspace/phpunit.phar:509
    0.1077   11602248   3. PHPUnit_TextUI_Command->run() phar:///Users/dunglas/workspace/phpunit.phar/phpunit/TextUI/Command.php:105
    0.1806   11894472   4. PHPUnit_TextUI_TestRunner->doRun() phar:///Users/dunglas/workspace/phpunit.phar/phpunit/TextUI/Command.php:154
    0.2456   11906392   5. PHPUnit_Framework_TestSuite->run() phar:///Users/dunglas/workspace/phpunit.phar/phpunit/TextUI/TestRunner.php:425
    0.2512   11911736   6. PHPUnit_Framework_TestCase->run() phar:///Users/dunglas/workspace/phpunit.phar/phpunit/Framework/TestSuite.php:747
    0.2512   11913512   7. PHPUnit_Framework_TestResult->run() phar:///Users/dunglas/workspace/phpunit.phar/phpunit/Framework/TestCase.php:727
    0.2513   11916304   8. PHPUnit_Framework_TestCase->runBare() phar:///Users/dunglas/workspace/phpunit.phar/phpunit/Framework/TestResult.php:617
    0.2514   11934944   9. PHPUnit_Framework_TestCase->runTest() phar:///Users/dunglas/workspace/phpunit.phar/phpunit/Framework/TestCase.php:771
    0.2515   11935840  10. ReflectionMethod->invokeArgs() phar:///Users/dunglas/workspace/phpunit.phar/phpunit/Framework/TestCase.php:908
    0.2515   11935904  11. Dunglas\PhpDocToTypeHint\Tests\ConverterTest->testConvertFunction() phar:///Users/dunglas/workspace/phpunit.phar/phpunit/Framework/TestCase.php:908
    0.2762   11981352  12. phpDocumentor\Reflection\Php\ProjectFactory::createInstance() /Users/dunglas/workspace/phpdoc-to-type-hint/tests/ConverterTest.php:9
    0.3310   12635600  13. phpDocumentor\Reflection\DocBlockFactory::createInstance() /Users/dunglas/workspace/phpdoc-to-type-hint/vendor/phpdocumentor/reflection/src/phpDocumentor/Reflection/Php/ProjectFactory.php:54
    0.3361   12651232  14. spl_autoload_call() /Users/dunglas/workspace/phpdoc-to-type-hint/vendor/phpdocumentor/reflection/src/phpDocumentor/Reflection/Php/ProjectFactory.php:52
    0.3361   12651304  15. Composer\Autoload\ClassLoader->loadClass() /Users/dunglas/workspace/phpdoc-to-type-hint/vendor/phpdocumentor/reflection/src/phpDocumentor/Reflection/Php/ProjectFactory.php:52
    0.3362   12651496  16. Composer\Autoload\includeFile() /Users/dunglas/workspace/phpdoc-to-type-hint/vendor/composer/ClassLoader.php:301

phpdocumentor requirements error.

Hello, Mike.

Can you change version of phpdocumentor/reflection-docblock in requirements to 2.0.0a3 like in phpdocumentor/phpdocumentor package on to 2.0.* .

phpdocumentor/phpdocumentor requirements:

    ...
        "phpdocumentor/fileset": "1.0.0-beta2",
        "phpdocumentor/reflection": "0.1.*",
        "phpdocumentor/reflection-docblock": "2.0.0a3",
    ...

phpdocumentor/reflection-docblock requirements:

    "require": {
        "php": ">=5.3.3",
        "nikic/php-parser": "dev-master",
        "phpdocumentor/reflection-docblock": "2.0.0a2"
    },

Thank you.

Implode error for global namespace with bracket syntax

Discovered in WordPress/phpdoc-parser#80

If you have multiple namespaces in a file using the bracket syntax, and also declare global code like so:

<?php

namespace {

    /* global code here.. */
}

You'll get this error:

PHP Warning: implode(): Invalid arguments passed in .../phpdocumentor/reflection/src/phpDocumentor/Reflection/FileReflector.php on line 494

This is where the error is from:

       $this->context->setNamespace(implode('\\', $node->name->parts));

The namespace doesn't have a name, so $node->name is not an object as expected, and the second argument for implode() ends up being null.

Develop branch release timing

I do apologize if this should be obvious. When is the code in develop scheduled to become the next release?

If you know.

I'm working on an extension to display my own projects and how found myself writing something similar to what is already in develop. So, I'm curious what's stopping it from becoming the next release? (Would prefer to use an official release than to change my composer setup, you know?)

define() in global namespace generates invalid fqsen

If you create a define in the global namespace, the fqsen generated is \\NAME which fails the regex expression in Fqsen constructor.

define('SECOND', 1);

PHP Fatal error: Uncaught InvalidArgumentException: "\\SECOND" is not a valid Fqsen. in /cake/api/vendor/phpdocumentor/reflection-common/src/Fqsen.php:51
Stack trace:
#0 /cake/api/vendor/phpdocumentor/reflection/src/phpDocumentor/Reflection/Php/Factory/Define.php(118): phpDocumentor\Reflection\Fqsen->__construct('\\\\SECOND')
#1 /cake/api/vendor/phpdocumentor/reflection/src/phpDocumentor/Reflection/Php/Factory/Define.php(96): phpDocumentor\Reflection\Php\Factory\Define->determineFqsen(NULL, Object(PhpParser\Node\Arg))

Issue with multiple namespace blocks.

Hi,

I was trying to run just a stand-alone example for this project on 5.6 and I am encountering the following error:

PHP Fatal error:  Uncaught exception 'PhpParser\Error' with message 'No code may exist outside of namespace {} on line 268' in /Users/alexander.barker/projects/Reflection/vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php:427
Stack trace:
#0 /Users/alexander.barker/projects/Reflection/vendor/nikic/php-parser/lib/PhpParser/Parser/Php7.php(797): PhpParser\ParserAbstract->handleNamespaces(Array)
#1 /Users/alexander.barker/projects/Reflection/vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php(247): PhpParser\Parser\Php7->reduceRule1()
#2 /Users/alexander.barker/projects/Reflection/vendor/nikic/php-parser/lib/PhpParser/Parser/Multiple.php(59): PhpParser\ParserAbstract->parse('<?php\n\nnamespac...')
#3 /Users/alexander.barker/projects/Reflection/vendor/nikic/php-parser/lib/PhpParser/Parser/Multiple.php(30): PhpParser\Parser\Multiple->tryParse(Object(PhpParser\Parser\Php7), '<?php\n\n in /Users/alexander.barker/projects/Reflection/vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php on line 427

Fatal error: Uncaught exception 'PhpParser\Error' with message 'No code may exist outside of namespace {} on line 268' in /Users/alexander.barker/projects/Reflection/vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php on line 427

PhpParser\Error: No code may exist outside of namespace {} on line 268 in /Users/alexander.barker/projects/Reflection/vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php on line 427

Call Stack:
    0.0002     229936   1. {main}() /Users/alexander.barker/projects/Reflection/example.php:0
    0.0370    7519464   2. phpDocumentor\Reflection\Php\ProjectFactory->create() /Users/alexander.barker/projects/Reflection/example.php:29
    0.0384    7571560   3. phpDocumentor\Reflection\Php\Factory\AbstractFactory->create() /Users/alexander.barker/projects/Reflection/src/phpDocumentor/Reflection/Php/ProjectFactory.php:79
    0.0384    7571648   4. phpDocumentor\Reflection\Php\Factory\File->doCreate() /Users/alexander.barker/projects/Reflection/src/phpDocumentor/Reflection/Php/Factory/AbstractFactory.php:28
    0.0387    7577864   5. phpDocumentor\Reflection\Php\Factory\File->phpDocumentor\Reflection\Php\Factory\{closure}() /Users/alexander.barker/projects/Reflection/src/phpDocumentor/Reflection/Php/Factory/File.php:92
    0.0387    7578088   6. phpDocumentor\Reflection\Php\Factory\File->createFile() /Users/alexander.barker/projects/Reflection/src/phpDocumentor/Reflection/Php/Factory/File.php:60
    0.0389    7584584   7. phpDocumentor\Reflection\Php\NodesFactory->create() /Users/alexander.barker/projects/Reflection/src/phpDocumentor/Reflection/Php/Factory/File.php:103
    0.0389    7584760   8. PhpParser\Parser\Multiple->parse() /Users/alexander.barker/projects/Reflection/src/phpDocumentor/Reflection/Php/NodesFactory.php:79

It appears that the namespace node is getting set as a Nop and thus throwing an error for more than one because of !$stmt instanceof Node\Stmt\HaltCompiler. I am not familiar enough with this project or php-parser to further identify why this is the case or what the behavior should be, however, I don't suspect that this is desired behavior on the example.test.php file.

Inline Example Loses Opening Curly Brace

We have inline examples in a number of our class level doc blocks

The Reflector however is losing our opening curly brace in cases where there is no space ala {}

<?php

/**
 * Description
 *
 * <code>
 * function Foo( Bar $baz ) {}
 * </code>
 *
 */
class FooBaz {
}

Gives us

<code>
function Foo( Bar $baz ) }
</code>

when calling

 $classBlock = $class->getDocBlock()
echo (string)$classBlock->getDescription();

Invalid Fqsen with anonymous class

If I have an anonymous class containing a public method, I get the following exception

[InvalidArgumentException]                                                               
"Namespace::externalMethod()::internalMethod()" is not a valid Fqsen.

Probably methods of anonymous classes should not be processed

Add Locations in elements

All elements should contain a location. With name of the file and line.

  • Property
  • Method
  • Class
  • Interface
  • Trait
  • Constant

Fails to load file starting with two comments

Having trouble loading a file starting with consecutive two non-docblock comments:

Example file:

<?php
// Comment one
// Comment two

include 'vendor/autoload.php';

$projectFactory = \phpDocumentor\Reflection\Php\ProjectFactory::createInstance();
$project = $projectFactory->create('MyProject', [__FILE__]);

Result of php example.php:

Fatal error: Uncaught exception 'OutOfBoundsException' with message 'No matching factory found for PhpParser\Comment' in /home/mfonda/dev/php-method-search/vendor/phpdocumentor/reflection/src/phpDocumentor/Reflection/Php/ProjectFactoryStrategies.php on line 54

OutOfBoundsException: No matching factory found for PhpParser\Comment in /home/mfonda/dev/php-method-search/vendor/phpdocumentor/reflection/src/phpDocumentor/Reflection/Php/ProjectFactoryStrategies.php on line 54

Call Stack:
    0.0002     240120   1. {main}() /home/mfonda/dev/php-method-search/example.php:0
    0.0323    5731584   2. phpDocumentor\Reflection\Php\ProjectFactory->create() /home/mfonda/dev/php-method-search/example.php:8
    0.0332    5776816   3. phpDocumentor\Reflection\Php\Factory\File->create() /home/mfonda/dev/php-method-search/vendor/phpdocumentor/reflection/src/phpDocumentor/Reflection/Php/ProjectFactory.php:79
    0.0333    5783992   4. phpDocumentor\Reflection\Php\Factory\File->phpDocumentor\Reflection\Php\Factory\{closure}() /home/mfonda/dev/php-method-search/vendor/phpdocumentor/reflection/src/phpDocumentor/Reflection/Php/Factory/File.php:113
    0.0333    5784264   5. phpDocumentor\Reflection\Php\Factory\File->createFile() /home/mfonda/dev/php-method-search/vendor/phpdocumentor/reflection/src/phpDocumentor/Reflection/Php/Factory/File.php:72
    0.0384    6088504   6. phpDocumentor\Reflection\Php\Factory\File->createDocBlock() /home/mfonda/dev/php-method-search/vendor/phpdocumentor/reflection/src/phpDocumentor/Reflection/Php/Factory/File.php:125
    0.0392    6143248   7. phpDocumentor\Reflection\Php\ProjectFactoryStrategies->findMatching() /home/mfonda/dev/php-method-search/vendor/phpdocumentor/reflection/src/phpDocumentor/Reflection/Php/Factory/File.php:200

It seems this is only the case when the file starts with two consecutive non-docblock comments.

The following files all work just fine:

<?php
/** Comment one */
/** Comment two */
<?php
/** Comment one */
// Comment two
<?php
// Comment one
$x = 42;
// Comment two

FileReflector fail to parse single use statement

Parsed code example (test.php):

use common/models{
     Class1, Class2
}; 

Error: Syntax error, unexpected '{', expecting T_STRING on line 4

Parser:

$reflector = new FileReflector('test.php', true);
$reflector->process();

Constants - No way to determine type of value.

Working with the newest develop branch, calling getValue on a PHP Constant always returns the value as a string regardless of the constants given type.

This is a problem for me because I need to note the exact types of my given constants.

It would be very helpful for me if either getValue() gave the value in it's defined type or if there were some way to check it on the Constant object.

Constants with a namespace are not added to Namespace_

Only Class based Constants are currently recognized and added to the Namespace_.
Constants in a namespace are ignored:

namespace Example;

const NS_CONST = 1; //  accessible via \Example\NS_CONST

if ($namespace->getFqsen() . '::' . $constant->getName() !== (string) $constant->getFqsen()) {

Also Constants defined e.g. via define('GLOBAL_CONST', 1) in a namespace \Example are wrongly attributed to this namespace. FQSEN should be \GLOBAL_CONST.
Those Constants have to be explicitly defined with the current Namespace - e.g.:

namespace Example;

define('GLOBAL_CONST', 1); // only accessible via \GLOBAL_CONST or GLOBAL_CONST
define(__NAMESPACE__ . '\\NS_CONST', 1);

Cannot use Doctrine\Common\Collections\ArrayCollection as ArrayCollection because the name is already in use

Since I upgraded your library to v1.1.0:

Changelogs summary:

 - nikic/php-parser updated from v0.9.5 to v1.4.1
   See changes: https://github.com/nikic/PHP-Parser/compare/v0.9.5...v1.4.1
   Release notes: https://github.com/nikic/PHP-Parser/releases/tag/v1.4.1

 - phpdocumentor/reflection updated from 1.0.7 to 1.1.0
   See changes: https://github.com/phpDocumentor/Reflection/compare/1.0.7...1.1.0
   Release notes: https://github.com/phpDocumentor/Reflection/releases/tag/1.1.0

I have the following error with phpunit on my project:

$ phpunit tests/AppBundle/Entity/
PHPUnit 5.3.2 by Sebastian Bergmann and contributors.

.................E...............E...
Fatal error: Cannot use Doctrine\Common\Collections\ArrayCollection as ArrayCollection because the name is already in use in /code/src/AppBundle/Entity/IpGroup.php on line 5

Call Stack:
    0.0003     281168   1. {main}() /code/vendor/phpunit/phpunit/phpunit:0
    0.0108    1688608   2. PHPUnit_TextUI_Command::main() /code/vendor/phpunit/phpunit/phpunit:47
    0.0108    1689232   3. PHPUnit_TextUI_Command->run() /code/vendor/phpunit/phpunit/src/TextUI/Command.php:110
    0.0914    8805088   4. PHPUnit_TextUI_TestRunner->doRun() /code/vendor/phpunit/phpunit/src/TextUI/Command.php:159
    0.0972    9036880   5. PHPUnit_Framework_TestSuite->run() /code/vendor/phpunit/phpunit/src/TextUI/TestRunner.php:440
    0.6050   24512744   6. PHPUnit_Framework_TestSuite->run() /code/vendor/phpunit/phpunit/src/Framework/TestSuite.php:747
    0.6075   24516296   7. PHPUnit_Framework_TestCase->run() /code/vendor/phpunit/phpunit/src/Framework/TestSuite.php:747
    0.6076   24516856   8. PHPUnit_Framework_TestResult->run() /code/vendor/phpunit/phpunit/src/Framework/TestCase.php:801
    0.6076   24519168   9. PHPUnit_Framework_TestCase->runBare() /code/vendor/phpunit/phpunit/src/Framework/TestResult.php:685
    0.6080   24550656  10. PHPUnit_Framework_TestCase->runTest() /code/vendor/phpunit/phpunit/src/Framework/TestCase.php:845
    0.6080   24551472  11. ReflectionMethod->invokeArgs() /code/vendor/phpunit/phpunit/src/Framework/TestCase.php:985
    0.6081   24551864  12. Tests\AppBundle\Entity\AbstractEntityTest->testGetterSetter() /code/vendor/phpunit/phpunit/src/Framework/TestCase.php:985
    0.6306   24885576  13. Tests\AppBundle\Entity\AbstractEntityTest->makeValue() /code/tests/AppBundle/Entity/AbstractEntityTest.php:87
    0.6306   24885824  14. PHPUnit_Framework_MockObject_MockBuilder->getMock() /code/tests/AppBundle/Entity/AbstractEntityTest.php:236
    0.6306   24885824  15. PHPUnit_Framework_TestCase->getMock() /code/vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/MockBuilder.php:101
    0.6306   24885824  16. PHPUnit_Framework_MockObject_Generator->getMock() /code/vendor/phpunit/phpunit/src/Framework/TestCase.php:1426
    0.6306   24885824  17. PHPUnit_Framework_MockObject_Generator->generate() /code/vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Generator.php:229
    0.6306   24885928  18. PHPUnit_Framework_MockObject_Generator->generateMock() /code/vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Generator.php:546
    0.6307   24888888  19. class_exists() /code/vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Generator.php:705
    0.6307   24889184  20. spl_autoload_call() /code/vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Generator.php:705
    0.6307   24889232  21. Composer\Autoload\ClassLoader->loadClass() /code/vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Generator.php:705
    0.6307   24889360  22. Composer\Autoload\includeFile() /code/vendor/composer/ClassLoader.php:301

The related IpGroup class:

<?php

namespace AppBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * IpGroup
 *
 * @ORM\Table
 * @ORM\Entity
 */
class IpGroup
{
    /**
     * @var int
     *
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(type="string", length=100)
     * @Assert\NotBlank
     * @Assert\Length(max="100")
     */
    private $name;

    /**
     * @var string
     *
     * @ORM\Column(type="string", length=20)
     * @Assert\NotBlank
     * @Assert\Length(max="20")
     * @Assert\Regex("/^[a-z_]+$/", message="Only characters and underscores.")
     */
    private $code;

    /**
     * @var IpV4[]|ArrayCollection
     *
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\IpV4", mappedBy="group")
     */
    private $ipV4s;

    /**
     * @var IpV6Range[]|ArrayCollection
     *
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\IpV6Range", mappedBy="group")
     */
    private $ipV6Ranges;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->ipV4s = new ArrayCollection();
    }

    /**
     * Get id
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     *
     * @return IpGroup
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set code
     *
     * @param string $code
     *
     * @return IpGroup
     */
    public function setCode($code)
    {
        $this->code = $code;

        return $this;
    }

    /**
     * Get code
     *
     * @return string
     */
    public function getCode()
    {
        return $this->code;
    }

    /**
     * Add ips
     *
     * @param IpV4 $ip
     *
     * @return IpGroup
     */
    public function addIpV4(IpV4 $ip)
    {
        $this->ipV4s[] = $ip;

        return $this;
    }

    /**
     * Remove ips
     *
     * @param IpV4 $ip
     */
    public function removeIpV4(IpV4 $ip)
    {
        $this->ipV4s->removeElement($ip);
    }

    /**
     * Get ips
     *
     * @return IpV4[]|ArrayCollection
     */
    public function getIpV4s()
    {
        return $this->ipV4s;
    }

    /**
     * Add ipV6Range
     *
     * @param IpV6Range $ipV6Range
     *
     * @return IpGroup
     */
    public function addIpV6Range(IpV6Range $ipV6Range)
    {
        $this->ipV6Ranges[] = $ipV6Range;
        $ipV6Range->setGroup($this);

        return $this;
    }

    /**
     * Remove ipV6Range
     *
     * @param IpV6Range $ipV6Range
     */
    public function removeIpV6Range(IpV6Range $ipV6Range)
    {
        $this->ipV6Ranges->removeElement($ipV6Range);
    }

    /**
     * Get ipV6Ranges
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getIpV6Ranges()
    {
        return $this->ipV6Ranges;
    }
}

Rolling back to 1.0.7 solve my issue.

Drush8 conflicts with phpDocumentor / Reflection

If you installed phpDocumentor / Reflection, you're not able to install Drush8. The reason is a conflict with the nikic/php-parser Version.

phpdocumentor/phpdocumentor requires phpdocumentor/reflection (~1.0)
phpdocumentor/reflection requires nikic/php-parser (~0.9.4)

drush/drush requires psy/psysh (~0.6)
psy/psysh requires nikic/php-parser (^1.2.1|~2.0)

The newest official release of phpDocumentor / Reflection uses nikic/php-parser 1.0, which is still to old for Drush8.

It would be great if you could release a new version which uses a newer version of nikic/php-parser in order to make it run with Drush8.

Write usage manual

Currently the README.md doesn't contain any usage instructions. Can you please add some examples?

Allow to skip parsing errors

When an Exception is thrown during namespace building it should be possible to proceed with it instead of failing.

Example: A InvalidArgumentException is thrown because a phpdoc block cannot be parsed in a file.

Too restrictive composer.json version requirements for nikic/php-parser

Both the develop and master composer.json use the ^ to restrict nikic/php-parser to a single major version. This is problematic as php-parser is one major version ahead of develop and three major versions ahead of master. Does this package not work on newer versions?

The use-case for this ticket is that I am building a jenkins CI environment, and I'm using ramsey/jenkins-php to install the various tools I plan to use. It depends on phpdocumentor/phpdocumentor 2.8, which depends on phpdocumentor/reflection ^3.0, which depends on nikic/php-parser ^1.0.

When I try to install phpstan/phpstan-symfony, which depends on nikic/php-parser ^4.0, it fails because nikic/php-parser ^1.0 is already installed:

[root@localhost ~]# /usr/local/bin/composer global require phpstan/phpstan-symfony
Changed current directory to /root/.composer
Using version ^0.10.1 for phpstan/phpstan-symfony
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Installation request for phpstan/phpstan-symfony ^0.10.1 -> satisfiable by phpstan/phpstan-symfony[0.10.1].
    - Conclusion: remove nikic/php-parser v1.4.1
    - Conclusion: don't install nikic/php-parser v1.4.1
    - phpstan/phpstan-symfony 0.10.1 requires nikic/php-parser ^4.0 -> satisfiable by nikic/php-parser[v4.0.0, v4.0.1, v4.0.2, v4.0.3].
    - Can only install one of: nikic/php-parser[v4.0.0, v1.4.1].
    - Can only install one of: nikic/php-parser[v4.0.1, v1.4.1].
    - Can only install one of: nikic/php-parser[v4.0.2, v1.4.1].
    - Can only install one of: nikic/php-parser[v4.0.3, v1.4.1].
    - Installation request for nikic/php-parser (locked at v1.4.1) -> satisfiable by nikic/php-parser[v1.4.1].


Installation failed, reverting ./composer.json to its original content.

Would it not be more preferable to use a constraint such as >=1.0.0 (master) and >=3.0.0 (develop)?

At this juncture, I feel stuck between a rock and a hard place in having to decide between two equally needed tools for my CI environment.

As a side note, I will also be reaching out to phpstan/phpstan-symfony about their usage of the ^ version constraint as well.

Fatal error when file is unreadable

I get the following error when an unreadable file is encountered:

Class 'Exception\UnreadableFile' not found in /usr/share/php/phpDocumentor/vendor/phpdocumentor/reflection/src/phpDocumentor/Reflection/FileReflector.php on line 100

It's unclear to me where this exception is supposed to be loaded from (the unparsable exception, too), are they somehow missing from the source or is my PHP version too old (5.3.3)?

Also, it would be great if the exception message could contain the filename.

phpDocumentor\Reflection\Php\File not extendable

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.
     }
}

Final class declarations

Why are so many of the class declarations implemented as final?

I'd love to implement a version of the ProjectFactory as an example, that adds some middleware to the new project definition, but right now I can't. I can implement the interface, sure, but then I'd have to re-implement the entirety of the namespace logic to get a Namespace tree. I can't even wrap the class because the namespace processing is all protected.

Similarly, I'd like to use slightly modified Factory\Function_ and Factory\Method strategies, but would need to copy pasta much of the code because again they are final classes. Being able to extend these classes would be a huge benefit and reduce the amount of code I'd need to write considerably. Perhaps I'm missing something, but they seem constructed with sensible defaults and are itching to be extended for additional implementations. Any reason they are not?

ReturnType of "PhpParser\Node\Name\FullyQualified" - but no leading backslash leads to FQN added to current namespace

Something strange seems to happen here:

$object->getReturnType() returns a object of PhpParser\Node\Name\FullyQualified despite it's not fully qualified in the source. So far no big deal. But: the string conversion does not contain a leading backslash.

   protected function doCreate($object, StrategyContainer $strategies, ?Context $context = null)
    {
        $docBlock = $this->createDocBlock($strategies, $object->getDocComment(), $context);

        $returnType = null;
        if ($object->getReturnType() !== null) {
            $typeResolver = new TypeResolver();
            if ($object->getReturnType() instanceof NullableType) {
                $typeString = '?' . $object->getReturnType()->type;
            } else {
                $typeString = (string) $object->getReturnType();
            }

            $returnType = $typeResolver->resolve($typeString, $context);

The subsequent call of $typeResolver->resolve($typeString, $context); then leads to a concatination of the namespace of the file with the (not wellformed) FQN (e.g. \My\Current\Namespace\MyCurrent\Namespace\Class)

I did not tried it yet, but it might be enough to make sure that the string contains a leading backslash:

if (($object instanceof \PhpParser\Node\Name\FullyQualified) && ($typeString[0] !== '\\'  ) {
  $typeString = '\\' .$typeString;
}

Update:

Checking on instance of \PhpParser\Node\Name and $returnType->isFullyQualified() might be the even cleaner approach.

Class used traits not working in 5.0.0

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

Extracting WordPress hooks from source

Hey there,

I'm attempting to use this package to parse through a WordPress plugin, but I'm running into an issue where I can't seem to expand the possible nodes that get extracted.

So far, I've attempted the following:

Created a ProjectFactory and copy-pasted the default strategies, but replaced the NodesFactory with a custom one so I could add another visitor. In this visitor, I'm able to extract the extra nodes I want (i.e. WordPress hooks / filters), however this information seems to be lost as soon as I dump the data in the factory, meaning I can't access it as a separate piece of information.

To me, this feels like information gets filtered out further down the chain or something? Am I correct in my assumption? And is there any way to ensure these extra nodes that I extracted will be retained in the final result?

Php\File::getFunctions() is always empty

This is using 4.0.0-beta.

I am unable to find any global functions via File::getFunctions().

I added some logging to ElementNameResolver::enterNode() and there are Function_ nodes being passed in with the proper names. However, nothing seems to create Php\Function_ instances anywhere.

For example, in a 'basics.php' file, there is this definition.

    function stackTrace(array $options = []): void
    {
        if (!Configure::read('debug')) {
            return;
        }

        $options += ['start' => 0];
        $options['start']++;

        /** @var string $trace */
        $trace = Debugger::trace($options);
        echo $trace;
    }

Reflection fails with nikic/php-parser 1.0.0-beta1

Reflection fails with nikic/php-parser 1.0.0-beta1.
I know, composer.json states =0.9.4, but I had another package installed, which required =1.0.0-beta1.

phpdoc runs successful, but no Namespaces are generated.
Since no error was thrown, I had a hard time finding this, in case someone else stumbles upon this.

Had to remove the other package (php-compatinfo), and a downgrade to 0.9.4 resolved the issues.

Any chance to support 1.0.0-beta1?

Add support for `enums` in reflection

  • add enum class
  • add enum factory
  • add backed enum support
  • add implements interfaces support
  • add method implementations in enum
  • add trait support in enum
  • check type resolver support in typed properties
  • check type resolver support in method / function arguments
  • check type resolver support in return types
  • check support of default property values

Define statements that are expressions fail to parse

When you define a global constant as a define with the NAMESPACE magic constant (for example); this library will throw an error:

Notice: Undefined property: PhpParser\Node\Expr\BinaryOp\Concat::$value
strpos() expects parameter 1 to be string, null given

This is because this library assumes that the value of the Define node is always a string; while this is not necessarily true

Example case:

define(__NAMESPACE__ . '\\MY_CONSTANT', 123);

Remove composer.lock file

As per current dependencies, the project is quite broken.

I suggest dropping composer.lock so that the build process can expose that as soon as a breakage in the dependency versions happens

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.