Giter VIP home page Giter VIP logo

composerrequirechecker's Introduction

ComposerRequireChecker

A CLI tool to analyze composer dependencies and verify that no unknown symbols are used in the sources of a package. This will prevent you from using "soft" dependencies that are not defined within your composer.json require section.

current version

What's it about?

"Soft" (or transitive) dependencies are code that you did not explicitly define to be there but use it nonetheless. The opposite is a "hard" (or direct) dependency.

Your code most certainly uses external dependencies. Imagine that you found a library to access a remote API. You require thatvendor/api-lib for your software and use it in your code. This library is a hard dependency.

Then you see that another remote API is available, but no library exists. The use case is simple, so you look around and find that guzzlehttp/guzzle (or any other HTTP client library) is already installed, and you use it right away to fetch some info. Guzzle just became a soft dependency.

Then someday, when you update your dependencies, your access to the second API breaks. Why? Turns out that the reason guzzlehttp/guzzle was installed is that it is a dependency of thatvendor/api-lib you included, and their developers decided to update from an earlier major version to the latest and greatest, simply stating in their changelog: "Version 3.1.0 uses the latest major version of Guzzle - no breaking changes expected."

And you think: What about my broken code?

ComposerRequireChecker parses your code and your composer.json-file to see whether your code uses symbols that are not declared as a required library, i.e. that are soft dependencies. If you rely on components that are already installed but didn't explicitly request them, this tool will complain about them and you should require them explicitly, making them hard dependencies. This will prevent unexpected updates.

In the situation above you wouldn't get the latest update of thatvendor/api-lib, but your code would continue to work if you also required guzzlehttp/guzzle before the update.

The tool will also check for usage of PHP functions that are only available if an extension is installed, and will complain if that extension isn't explicitly required.

Installation / Usage

ComposerRequireChecker is not supposed to be installed as part of your project dependencies.

PHAR file [preferred]

Please check the releases for available PHAR files. Download the latest release and run it like this:

php composer-require-checker.phar check /path/to/your/project/composer.json

PHIVE

If you already use PHIVE to install and manage your project’s tooling, then you should be able to simply install ComposerRequireChecker like this:

phive install composer-require-checker

Composer - global command

This package can be easily globally installed by using Composer:

composer global require maglnet/composer-require-checker

If you haven't already setup your composer installation to support global requirements, please refer to the Composer CLI - global If this is already done, run it like this:

composer-require-checker check composer.json

The composer.json here refers to the root Composer manifest of your project.

A note about Xdebug

If your PHP is including Xdebug when running ComposerRequireChecker, you may experience additional issues like exceeding the Xdebug-related max-nesting-level - and on top, Xdebug slows PHP down.

It is recommended to run ComposerRequireChecker without Xdebug.

If you cannot provide a PHP instance without Xdebug yourself, try setting an environment variable like this for just the command: XDEBUG_MODE=off php composer-require-checker.

Configuration

ComposerRequireChecker is configured to whitelist some symbols per default. Have a look at the config file example to see which configuration options are available.

You can now adjust this file, as needed, and tell composer-require-checker to use it for its configuration. If you want to use the default whitelist, you may remove this section and only adjust the sections you would like to change.

Note that if you want to add something on top of a section, you'll have to copy the whole section's content. This tool intentionally only reads one configuration file. If you pass only your new settings, you'll get error reports about the PHP core extensions and internal symbols like true or false being undefined.

bin/composer-require-checker check --config-file=path/to/config.json /path/to/your/project/composer.json

By default, it uses composer-require-checker.json if the file exists.

Scan Additional Files

To scan files, that are not part of your autoload definition you may add glob patterns to the config file's scan-files section.

The following example configuration file would also scan the file bin/console and all files with .php extension within your bin/ folder:

composer-require-checker.json:

{
    "scan-files" : ["bin/console", "bin/*.php"]
}

If you don't like copying the tool's default settings, consider adding these paths to the Composer autoloading section of your project instead.

Usage

ComposerRequireChecker runs on an existing directory structure. It does not change your code and does not even install your composer dependencies. That is a task that is entirely up to you, allowing you to change/improve things after a scan to see if it fixes the issue.

So the usual workflow would be

  1. Clone your repo
  2. composer install your dependencies
  3. composer-require-checker check your code

Dealing with custom installer plugins

ComposerRequireChecker only fetches its knowledge of where files are from your project's composer.json. It does not use Composer itself to understand custom directory structures.

If your project requires making use of any install plugins to put files in directories that are not vendor/ or defined via the vendor-dir config setting in composer.json, ComposerRequireChecker will fail to detect the required code correctly.

As a workaround, you can install your dependencies without plugins just for the scan:

  1. Clone your repo
  2. composer install --no-plugins will put all code into the vendor folder
  3. composer-require-checker check your code
  4. composer install dependencies once again in the correct location

License

This package is made available under the MIT LICENSE.

Credits

This package was initially designed by Marco Pivetta and Matthias Glaub.
And of course all Contributors.

composerrequirechecker's People

Contributors

a-menshchikov avatar danielbadura avatar dependabot-preview[bot] avatar dependabot[bot] avatar dkreuer avatar duncan3dc avatar fezfez avatar fredden avatar github-actions[bot] avatar guillaume-perreal avatar heiglandreas avatar keradus avatar lctrs avatar localheinz avatar maglnet avatar martinssipenko avatar midnightdesign avatar ocramius avatar pamil avatar pavarnos avatar ptondereau avatar renovate[bot] avatar rieschl avatar simpod avatar spacepossum avatar svenrtbg avatar villfa avatar vincentlanglet avatar weirdan avatar xepozz 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  avatar

composerrequirechecker's Issues

Useless dependencies option

It would be a great addition to be able to list useless dependencies. I mean an required dependency with no symbol usage at all.

Of course, it should be optional and the configuration file should accept packages to ignore.

Some packages could just provide configuration file or whatever not related to PHP directly, but used. This case would be a false positive.

Missing symbol false positive for internal code

I added the following class on my src-dev folder:

<?php

declare(strict_types=1);

namespace Dev\TestCase;

use Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage as BaseSessionStorage;

final class MockFileSessionStorage extends BaseSessionStorage
{
    /**
     * {@inheritdoc}
     *
     * @see https://github.com/symfony/symfony/issues/13450
     */
    public function setId($id): void
    {
        if ($this->id !== $id) {
            parent::setId($id);
        }
    }
}

And my composer.json extract:

"autoload-dev": {
    "psr-4": {
        "Dev\\": "src-dev/",
        "Tests\\": "tests/"
    },
    "files": [
        "src/env_dev.php"
    ]
},

The cli detects Dev\TestCase\MockFileSessionStorage as an unknow symbol. I don't understand why at all, maybe a bug?

Note: I also have two traits on this folder with same namespace and it seems ok for the cli tool.

Checker doesn't see php-core-extensions section from config file

Hi,
I'm running Composer Require Checker on a codebase, like this:

php temp/composer-require-checker-1.0.0.phar check --config-file /Users/ondrej/Development/telfa/composer-require-checker.json composer.json

The composer-require-checker.json looks like this:

{
	"symbol-whitelist": [
		"null",
		"true",
		"false",
		"static",
		"self",
		"parent",
		"array",
		"string",
		"int",
		"float",
		"bool",
		"iterable",
		"callable",
		"void",
		"object"
	],
	"php-core-extensions": [
		"Core",
		"date",
		"pcre",
		"Phar",
		"Reflection",
		"SPL",
		"standard"
	]
}

The problem is that it still reports PHP core extensions:

ComposerRequireChecker 1.0.0
The following unknown symbols were found:
+-----------------------+--------------------+
| unknown symbol        | guessed dependency |
+-----------------------+--------------------+
| Exception             | ext-Core           |
| filter_var            | ext-filter         |
| FILTER_VALIDATE_EMAIL | ext-filter         |
| SplObjectStorage      | ext-SPL            |
| var_dump              | ext-standard       |
| count                 | ext-standard       |
| DateTimeImmutable     | ext-date           |
| base64_encode         | ext-standard       |
| DATE_ISO8601          | ext-date           |
| var_export            | ext-standard       |
| date_get_last_errors  | ext-date           |
| preg_match            | ext-pcre           |
+-----------------------+--------------------+

It does not ignore the first part of the config file because the keywords are no longer reported.

Parser error - how to debug it?

Hi,
I'm experiencing this parse error in phpstan/playground project. Here it can be seen in this pull request: https://github.com/phpstan/playground/pull/13

ComposerRequireChecker 1.1.0

In ParserAbstract.php line 313:

  Syntax error, unexpected ';', expecting T_VARIABLE or '{' or '$' on line 4


check [--config-file CONFIG-FILE] [--ignore-parse-errors] [--] [<composer-json>]

I have no idea if it comes from the require checker itself or if I have a parse error somewhere in my dependencies.

composer-require-checker check not picking up phpmailer

With & without optimize-autoloader being set to true in composer.json, composer-require-checker check ./composer.json lists PHPMailer\PHPMailer\PHPMailer as an "unknown symbol", which is a little odd as I've got other packages loaded with psr-4 that drop off the list when I pull them in with composer require :s

How to declare SAPI specific functions like fastcgi_finish_request

How should a SAPI specific functions like fastcgi_finish_request be declared in composer.json?
Is it worth to add this function to a global whitelist?

$ php composer-require-checker.phar    
ComposerRequireChecker 0.2.1-dev
The following unknown symbols were found:
+---------------------------------------------------+--------------------+
| unknown symbol                                    | guessed dependency |
+---------------------------------------------------+--------------------+
| fastcgi_finish_request                            |                    |
+---------------------------------------------------+--------------------+

Option to exclude check from some file

Ref: Report #55 (comment)

It would be great to be able to specify a file where some symbol check will be ignored.

We can simply provide a list of file to totally exclude:

{
  "exclude-files" : [
    "config/bundles.php",
    "dummy/other/magic_file.php",
  ]
}

Or also provide the namespace to ignore on each file:

{
  "exclude-files" : [
    "config/bundles.php": [
        "Some\\Namespace\\To\\Ignore",
    ],
    "dummy/other/magic_file.php",
  ]
}

As the original issue was about dev dependencies, the best would be also to specified when to also use dev dependencies while checking a file:

{
  "check-dev-files" : [
    "config/bundles.php",
    "dummy/other/magic_file.php",
  ]
}

Note: The option name can/must be improved, it is just an illustration for now.

Configuration options to include packages from require-dev and suggests

It seems that currently only packages used directly in require section are considered.
There are multiple cases when packages are optional dependency and as such are only present in suggest (and possibly also require-dev) section. These are currently reported as missing dependency, although they are not hard dependency.

Segfault When Running Against Repo that includes Faker

Here is some strace output:

fstat(8, {st_mode=S_IFREG|0644, st_size=1009973, ...}) = 0
lseek(8, 0, SEEK_CUR)                   = 0
fstat(8, {st_mode=S_IFREG|0644, st_size=1009973, ...}) = 0
read(8, "<?php\n\nnamespace Faker\\Provider\\"..., 8192) = 8192
read(8, "    *       *       *       *   "..., 8192) = 8192
read(8, "zijn. Gij weet\nniet wat een uil "..., 8192) = 8192
read(8, "d, ik heb zes duiten verdiend, s"..., 8192) = 8192
read(8, "in de vaart, doch in de beurzen\n"..., 8192) = 8192
read(8, "heelt er toch, man? vroeg zij. G"..., 8192) = 8192
read(8, "ten\nopgebrand waren, toen die va"..., 8192) = 8192
read(8, " ezel weer thuis kwam met een za"..., 8192) = 8192
read(8, "an de markt was een schoone lijn"..., 8192) = 8192
read(8, "en ledigen\nkorf, en gansch ineen"..., 8192) = 8192
read(8, "hing\neen walm van verkoold haar."..., 8192) = 8192
read(8, " haar aan zich zedig te kleeden "..., 8192) = 8192
read(8, "at er, gansch Vlaanderenland\ndoo"..., 8192) = 8192
read(8, "deed het\ndicht. Klaas en Soetkin"..., 8192) = 8192
read(8, "hij ging Uilenspiegel als\nketter"..., 8192) = 8192
read(8, "antwoordde, dat\nde broeders van "..., 8192) = 8192
read(8, "broeder van de Goede Tronie, roe"..., 8192) = 8192
read(8, "an hekserij en verklaarde, dat\nz"..., 8192) = 8192
read(8, "lden uit om die bogen te betalen"..., 8192) = 8192
read(8, "ltering, ziet; dan neemt zij\nijl"..., 8192) = 8192
read(8, " Karel de stede\nzou komen bezoek"..., 8192) = 8192
read(8, " paling en karpers.\n\nUilenspiege"..., 8192) = 8192
read(8, "n. Teederlijk zag de vorstinne h"..., 8192) = 8192
read(8, "wiegelende schuitjes en naar de\n"..., 8192) = 8192
read(8, "soms den verkeerden man. Hebt gi"..., 8192) = 8192
read(8, "n een iegelijk, en inzonderheid "..., 8192) = 8192
read(8, "l vol vet, in denwelken\nmen olie"..., 8192) = 8192
read(8, " halven dag. En 'k heb\ntienduize"..., 8192) = 8192
read(8, " ezel?\n\nUilenspiegel antwoordde:"..., 8192) = 8192
read(8, "ellenden\nblik in zijne sluwe, wr"..., 8192) = 8192
read(8, " altijd op hunne vrijheden, keur"..., 8192) = 8192
read(8, "el, met een paar gulden zou ik\ne"..., 8192) = 8192
read(8, "lakjes\nop den weg lieten vallen,"..., 8192) = 8192
read(8, "d naar den stal.\n\nDaar streek hi"..., 8192) = 8192
read(8, "e gezellen de hand niet geleend."..., 8192) = 8192
read(8, "ang en hoorde Klaas met den\nvree"..., 8192) = 8192
read(8, "roppelen uit te halen en lokte e"..., 8192) = 8192
read(8, "iegel en sprak:\n\n--Mijn zoon, di"..., 8192) = 8192
read(8, ",\nmoet gij het zeggen, opdat wij"..., 8192) = 8192
read(8, "iden zwaar zijn, zult gij, zoo g"..., 8192) = 8192
read(8, "e\nprivileges, aan Zijne Koninkli"..., 8192) = 8192
read(8, "en, alle ellenden geproefd heeft"..., 8192) = 8192
read(8, "Hij schreeuwt als een nachtuil o"..., 8192) = 8192
read(8, "t doet mij meer genoegen\nvoor u "..., 8192) = 8192
read(8, "jne een grijsachtig vocht, dat z"..., 8192) = 8192
read(8, "tonden en eene menigte geesten i"..., 8192) = 8192
read(8, " een stuk\nverkenslever, en hij v"..., 8192) = 8192
read(8, " op een lam een arent,\n    Viel "..., 8192) = 8192
read(8, "t, of ik uw lief gelaat ooit wed"..., 8192) = 8192
read(8, "n \"geuzen\" geheeten en genaamd t"..., 8192) = 8192
read(8, "oesting,\nde oorlog en de val van"..., 8192) = 8192
read(8, "arheid.\n\nJong en poezele kwezelk"..., 8192) = 8192
read(8, "Leve de geus!\" En er blijft\ngeen"..., 8192) = 8192
read(8, "? vroeg een stadsserjant.\n\n--Ik "..., 8192) = 8192
read(8, "t hij het\nvijandelijke leger zal"..., 8192) = 8192
read(8, "andaag kost hij u geen duit, spr"..., 8192) = 8192
read(8, " en vleesch moeten geven. En ald"..., 8192) = 8192
read(8, "emd en\nzijn armen, waren vettig "..., 8192) = 8192
read(8, "e rampspoed is gekomen voor den\n"..., 8192) = 8192
read(8, "e genoemd zijn, tot de straffen "..., 8192) = 8192
read(8, "e wijnkannetjes, tweemaal voor z"..., 8192) = 8192
read(8, "eerdig uitziet,\ndaar hij altijd "..., 8192) = 8192
read(8, " vier zware\nkanonnen, en met vee"..., 8192) = 8192
read(8, "ood Uilenspiegel het graf te ver"..., 8192) = 8192
read(8, " vuurroer en schoot naar de zwar"..., 8192) = 8192
read(8, "onderbussen, de\nsakers, de klein"..., 8192) = 8192
read(8, "degen voerden, gaven fluitend he"..., 8192) = 8192
read(8, "p een van de peerden\nder soldate"..., 8192) = 8192
read(8, "iep:\n\n--Vaarwel, heer, dat de li"..., 8192) = 8192
read(8, "n.\n\n--Zegent mij dan ten minste,"..., 8192) = 8192
read(8, "g, zoo smakelijk en zoo fijn van"..., 8192) = 8192
read(8, " hun\nde minste moeilijkheid aan."..., 8192) = 8192
read(8, "vermogen niets tegen twee mannen"..., 8192) = 8192
read(8, "plimenten van mijnen baas en hij"..., 8192) = 8192
read(8, "vrije mannen, en gij zult ook an"..., 8192) = 8192
read(8, "den zij aan heure rokken gebonde"..., 8192) = 8192
read(8, "et\ndikke, bloedroode lippen, en "..., 8192) = 8192
read(8, "n gezien, die op ezelen reden; s"..., 8192) = 8192
read(8, "mager peerd van de eene naar de "..., 8192) = 8192
read(8, "chept door den hertog\nvan Lothar"..., 8192) = 8192
read(8, "het droog\nwas, beschilderde hij "..., 8192) = 8192
read(8, "r God niet verschijnen,\nbeladen "..., 8192) = 8192
read(8, "wapend\nmet zweerden, met bussen,"..., 8192) = 8192
read(8, "n al te talrijk, sprak de oude m"..., 8192) = 8192
read(8, "\303\263r zij naar\n't galgeveld trekke"..., 8192) = 8192
read(8, "rinken! zeiden de serjanten.\n\n--"..., 8192) = 8192
read(8, "ak:\n\n--Gij zijt hier allen in on"..., 8192) = 8192
read(8, "Damme en in de omstreken,\nafschu"..., 8192) = 8192
read(8, ".\n\n--Maar reeds heeft hij weer m"..., 8192) = 8192
read(8, "enspiegel tot den zwerver:\n\n--Wa"..., 8192) = 8192
read(8, "j het waarschijnlijk is,\ndie het"..., 8192) = 8192
read(8, "s. Zij\nook scheen waanzinnig; zi"..., 8192) = 8192
read(8, "isschers vreezen den\nweerwolf me"..., 8192) = 8192
read(8, "vangene uit de val\nverlost, en t"..., 8192) = 8192
read(8, "wafelijzer met wreede tanden te "..., 8192) = 8192
read(8, " als de\nhond aan zijn been houdt"..., 8192) = 8192
read(8, "onder mijne\noogen? En als zij mi"..., 8192) = 8192
read(8, "t ik uw\nglanzend gelaat zie. Doe"..., 8192) = 8192
read(8, "de wateren vergiftigden, monnike"..., 8192) = 8192
read(8, "zij, zoo heur zwarte bruidegom h"..., 8192) = 8192
read(8, "deken van Heist! Hoeft een oprec"..., 8192) = 8192
read(8, "op dewelke de rechters\nwaren gez"..., 8192) = 8192
read(8, "ppen, belladonna en datura.\n\n..."..., 8192) = 8192
read(8, "hij\nmikt, en, als in boter, een "..., 8192) = 8192
read(8, "e hij overhad voor zich en voor "..., 8192) = 8192
read(8, "d was om de straf te volbrengen."..., 8192) = 8192
read(8, "den armen Lamme, die, getrouwd z"..., 8192) = 8192
read(8, "menschen. Zij leven van de klein"..., 8192) = 8192
read(8, " maanden, wederstaan wij met dui"..., 8192) = 8192
read(8, " Wie heeft de zijden en\nlakensch"..., 8192) = 8192
read(8, "ijn gezwollen voeten en zijn loo"..., 8192) = 8192
read(8, "ls bij hoopen naast de affuiten "..., 8192) = 8192
read(8, ". Wie zal hun den nek omwringen?"..., 8192) = 8192
read(8, "et\nvreemdelingen. Bijt, hertog, "..., 8192) = 8192
read(8, " op uwe wond.\n\nToen Lamme zijne "..., 8192) = 8192
read(8, " krijgen\ngeld om de soldaten te "..., 8192) = 8192
read(8, "ver. Ja, op die goede en brave s"..., 8192) = 8192
read(8, " kunt: hoe meer gij eet,\nhoe lie"..., 8192) = 8192
read(8, "l weegt hij? Driehonderd veertie"..., 8192) = 8192
read(8, "ulden per maand: Broer Cornelis "..., 8192) = 8192
read(8, "e sprong op van geluk en riep bl"..., 8192) = 8192
read(8, "den moordenaar\nmet drie kogels i"..., 8192) = 8192
read(8, " Lelie, vloo, de geheimenis,\n   "..., 8192) = 8192
read(8, " tranen en snikken.\n\nDe burgemee"..., 8192) = 2357
read(8, "", 8192)                       = 0
read(8, "", 8192)                       = 0
close(8)                                = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x7fff1d5c9f70} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)

File location doesn't work

Using something like this in composer.json doesn't work:

    "autoload": {
        "psr-4": {
            "GeckoPackages\\PHPUnit\\": "src\\PHPUnit"
        }
    },

This does:

"autoload": {
        "psr-4": {
            "GeckoPackages\\PHPUnit\\": "src/PHPUnit/"
        }
    },

What is also a bit tricky is that the tool ends with;

[12:07 PM]-[possum@zoo1]-[/home/possum/work/GeckoPHPUnit]-[git 2.0] 
$ ./vendor/bin/composer-require-checker check composer.json --config-file=/home/possum/work/GeckoPHPUnit/.composer-require-checker.json -vvv
ComposerRequireChecker v2.1-4-g74c9d72-dev
There were no unknown symbols found.

Might be better to do a sanity check if there were any symbols found at all and if not exit with an error that the configuration is off?

Meta stuff for debugging:

[12:07 PM]-[possum@zoo1]-[/home/possum/work/GeckoPHPUnit]-[git 2.0] 
$ php -v
PHP 7.1.7-1+ubuntu16.04.1+deb.sury.org+1 (cli) (built: Jul  7 2017 09:41:45) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies
    with Zend OPcache v7.1.7-1+ubuntu16.04.1+deb.sury.org+1, Copyright (c) 1999-2017, by Zend Technologies
    with Xdebug v2.5.5, Copyright (c) 2002-2017, by Derick Rethans
[12:07 PM]-[possum@zoo1]-[/home/possum/work/GeckoPHPUnit]-[git 2.0] 
$ composer -V
Composer version 1.4.2 2017-05-17 08:17:52

There is also a minor thingy about locating the passed configuration file when the tool is installed in /usr/local/bin/ but run from other cws dir.

I'll hope to prep. some fixes for this the upcoming days :)

Defined constants in a namespaced file are not registered

I have the following file defining constants:

<?php

namespace Foo;

define('BAR', 'baz');

This code works in PHP and uses the built-in define function.

However, these lines:

if ($node->name->hasAttribute('namespacedName')
&& $node->name->getAttribute('namespacedName') instanceof Node\Name\FullyQualified
&& $node->name->getAttribute('namespacedName')->toString() !== 'define'
) {
return;
}

make the checker ignore this pattern and the code needs to change to:

<?php

namespace Foo;

\define('BAR', 'baz');

for the constant to be recognised.

The review comments in #59 (comment) are fair and I think the case where the define() function is defined in a namespace needs to tackled, but the check should be different to allow for the more common case of not defining a define() function in a namespace, but just using the built-in one without a leading slash.

Invalid version reported when installed without .git

Install like so:

composer require --prefer-dist --dev maglnet/composer-require-checker

(--prefer-dist is the default, but just to make sure...)

Observe:

$ ./vendor/bin/composer-require-checker check composer.json
ComposerRequireChecker v3.0.1-15-ge5fafe9-dev
...

But that's exactly my package's last version:

$ git describe --tags --dirty=-dev --always
v3.0.1-15-1beef234-dev

One way to tackle this problem is to use Git's export-subst trick for, say Cli/Application.php.

Quick demo.

Configure extra files to check

In the bin/console file of a Symfony project, a used symbol that is part of require-dev in the composer.json file is not reported by composer-require-checker. If I understand correctly, this is because bin/console is not part of an autoload directory (src/) and thus not checked at all. But the console will still crash after running composer install --no-dev.

Is there a way to make the tool check the file anyway?

Dev dependencies are reported as false positives

We have dev dependencies like behat/behat and phpstan/phpstan and then we use them in our code only in local environment. These dependencies are correctly added to require-dev, but the checker report them as missing.

Violations
Behat\Behat\Context\Context
Clippings\Test\FixturesLoader
Behat\Gherkin\Node\TableNode
Behat\MinkExtension\Context\RawMinkContext
Behatch\Context\BaseContext
Behatch\HttpCall\HttpCallResultPool
Behatch\Json\JsonInspector
Behat\Gherkin\Node\PyStringNode
Behatch\Json\Json
Behat\Behat\Context\Initializer\ContextInitializer
Behat\Behat\Context\Argument\ArgumentResolver
Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException
Behat\Testwork\ServiceContainer\Extension
Behat\Testwork\ServiceContainer\ExtensionManager
Symfony\Component\DependencyInjection\ContainerBuilder
Symfony\Component\DependencyInjection\Definition
Symfony\Component\DependencyInjection\Reference
Behat\Behat\Context\ServiceContainer\ContextExtension
{
    "require-dev": {
        "behat/behat": "^3.4",
        "behat/gherkin": "^4.5",
        "behat/mink": "^1.7",
        "behat/mink-browserkit-driver": "^1.3",
        "behat/mink-goutte-driver": "^1.2",
        "phpstan/phpstan": "^0.8.4",
        "phpstan/phpstan-doctrine": "^0.8",
        "behatch/contexts": "^2.7",
		"treehouselabs/behat-common": "^0.2.1"
 	}
}

PHP Fatal error with symfony/framework-bundle and traits

I have got this error with master.

composer-require-checker check composer.json 
ComposerRequireChecker 0.1.6-27-ga1b1407
PHP Fatal error:  Uncaught TypeError: Argument 1 passed to ComposerRequireChecker\NodeVisitor\UsedSymbolCollector::recordUsageOf() must be an instance of PhpParser\Node\Name, null given, called in /home/user/.composer/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/NodeVisitor/UsedSymbolCollector.php on line 153 and defined in /home/user/.composer/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/NodeVisitor/UsedSymbolCollector.php:166
Stack trace:
#0 /home/user/.composer/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/NodeVisitor/UsedSymbolCollector.php(153): ComposerRequireChecker\NodeVisitor\UsedSymbolCollector->recordUsageOf(NULL)
#1 /home/user/.composer/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/NodeVisitor/UsedSymbolCollector.php(50): ComposerRequireChecker\NodeVisitor\UsedSymbolCollector->recordTraitUsage(Object(PhpParser\Node\Stmt\TraitUse))
#2 /home/user/.composer/vendor/nikic in /home/user/.composer/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/NodeVisitor/UsedSymbolCollector.php on line 166

PHP Version:

php -v
PHP 7.1.11-1+ubuntu17.10.1+deb.sury.org+1 (cli) (built: Oct 27 2017 13:50:57) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies
    with Zend OPcache v7.1.11-1+ubuntu17.10.1+deb.sury.org+1, Copyright (c) 1999-2017, by Zend Technologies

I Added a var_dump just before the error, this gives me this:

object(PhpParser\Node\Stmt\TraitUseAdaptation\Alias)#5785 (5) {
  ["newModifier"]=>
  int(1)
  ["newName"]=>
  NULL
  ["trait"]=>
  NULL
  ["method"]=>
  string(11) "generateUrl"
  ["attributes":protected]=>
  array(2) {
    ["startLine"]=>
    int(536)
    ["endLine"]=>
    int(536)
  }
}

Can be reproduced with the following composer.json (just do composer install and run composer-require-checker on it):

{
    "require": {
        "symfony/framework-bundle": "^3.3"
    },
    "autoload": {
        "psr-4": { "\\MyNS\\": "./" }
    }
}

Extensions provided by dependencies

Extensions provided by dependencies aren't handled correctly.

Concrete example: My project requires "ext-mongo": "*" and "alcaeus/mongo-php-adapter": "^1.0". alcaeus/mongo-php-adapter provides ext-mongo, but the checker still complains about it being an unknown extension.

How should I go about implementing a fix? Should DefinedExtensionsResolver not return provided extensions in the first place? Should it return them, but then we filter them somewhere else? Should LocateDefinedSymbolsFromExtensions take an array of provided extensions as a second (optional) argument?

Provide a "severity" for each import usage

Currently, used symbols are all at the same level.

There are though some symbols that may be "soft" dependencies (rare cases) and may be flagged differently.

Therefore, this suggestion may eventually be discarded after some discussion/suggestions.

Some examples:

often used in polyfills, minor issue:

if (class_exists(Foo::class)) { ... }

often used to do duck typing against running systems with unknown dependencies: warning (because the API is not guaranteed to work/be stable)

if ($instance instanceof Foo) { ... }

bad one: we are not duck-typing here, so strictness is necessary:

function foo(Foo $foo) { ... }

Hope this helps :-)

Internal Symbols are shown as unknown

I've just checked a component that shows DateTime, DateTimeZone, Countable, RecursiveIterator or InvalidArgumentException as unknown.

The Symbols are declared in the files via a use-Statement.

Unable to read config.json

While trying to apply #37:

sullivan@b6636163567b:/code$ composer-require-checker check --config-file config.json --ignore-parse-errors -vvv
ComposerRequireChecker 0.2.0

In JsonLoader.php line 25:
                                                           
  [ComposerRequireChecker\Exception\NotReadableException]  
  unable to read config.json                               
                                                           

Exception trace:
 ComposerRequireChecker\JsonLoader->__construct() at phar:///usr/bin/composer-require-checker/src/ComposerRequireChecker/Cli/CheckCommand.php:122
 ComposerRequireChecker\Cli\CheckCommand->getCheckOptions() at phar:///usr/bin/composer-require-checker/src/ComposerRequireChecker/Cli/CheckCommand.php:64
 ComposerRequireChecker\Cli\CheckCommand->execute() at phar:///usr/bin/composer-require-checker/vendor/symfony/console/Command/Command.php:252
 Symfony\Component\Console\Command\Command->run() at phar:///usr/bin/composer-require-checker/vendor/symfony/console/Application.php:865
 Symfony\Component\Console\Application->doRunCommand() at phar:///usr/bin/composer-require-checker/vendor/symfony/console/Application.php:241
 Symfony\Component\Console\Application->doRun() at phar:///usr/bin/composer-require-checker/vendor/symfony/console/Application.php:143
 Symfony\Component\Console\Application->run() at phar:///usr/bin/composer-require-checker/bin/composer-require-checker.php:32
 include() at /usr/bin/composer-require-checker:10

check [--config-file CONFIG-FILE] [--ignore-parse-errors] [--] [<composer-json>]

sullivan@b6636163567b:/code$ ll config.json 
-rw-rw-r-- 1 sullivan sullivan 63 Feb 27 16:27 config.json
sullivan@b6636163567b:/code$ cat config.json 
{
  "symbol-whitelist" : [
    "Composer\\Script\\Event"
  ]
}

Maximum function nesting level of '256' reached

Sometimes the maximum nesting level is reached. Would it be a good idea to add an option to exclude dependencies from analysis? In my case it would be PhpParser.

    0.0035     390800   1. {main}() ~/.composer/vendor/maglnet/composer-require-checker/bin/composer-require-checker:0
    0.0039     395784   2. include('~/.composer/vendor/maglnet/composer-require-checker/bin/composer-require-checker.php') ~/.composer/vendor/maglnet/composer-require-checker/bin/composer-require-checker:3
    0.0261    1217128   3. ComposerRequireChecker\Cli\Application->run() ~/.composer/vendor/maglnet/composer-require-checker/bin/composer-require-checker.php:32
    0.0376    1460984   4. ComposerRequireChecker\Cli\Application->doRun() ~/.composer/vendor/symfony/console/Application.php:145
    0.0377    1460984   5. ComposerRequireChecker\Cli\Application->doRunCommand() ~/.composer/vendor/symfony/console/Application.php:262
    0.0377    1460984   6. ComposerRequireChecker\Cli\CheckCommand->run() ~/.composer/vendor/symfony/console/Application.php:886
    0.0382    1466136   7. ComposerRequireChecker\Cli\CheckCommand->execute() ~/.composer/vendor/symfony/console/Command/Command.php:251
    0.1237    4753840   8. ComposerRequireChecker\DefinedSymbolsLocator\LocateDefinedSymbolsFromASTRoots->__invoke() ~/.composer/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/Cli/CheckCommand.php:73
   59.2263   11738576   9. PhpParser\NodeTraverser->traverse() ~/.composer/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/DefinedSymbolsLocator/LocateDefinedSymbolsFromASTRoots.php:28
   59.2263   11729200  10. PhpParser\NodeTraverser->traverseArray() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:85
   59.2263   11729624  11. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:200
   59.2263   11729768  12. PhpParser\NodeTraverser->traverseArray() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:108
   59.2266   11733552  13. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:200
   59.2267   11734192  14. PhpParser\NodeTraverser->traverseArray() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:108
   59.2267   11734616  15. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:200
   59.2267   11734840  16. PhpParser\NodeTraverser->traverseArray() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:108
   59.2269   11735992  17. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:200
   59.2269   11736016  18. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2269   11736040  19. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2269   11736064  20. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2270   11736088  21. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2270   11736112  22. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2270   11736136  23. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2270   11736160  24. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2270   11736184  25. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2270   11736208  26. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2270   11736232  27. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2270   11736256  28. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2270   11736280  29. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2270   11736304  30. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2271   11736328  31. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2271   11736352  32. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2271   11736376  33. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2271   11736400  34. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2271   11736424  35. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2271   11736448  36. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2271   11736472  37. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2271   11736496  38. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2271   11736520  39. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2271   11736544  40. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2272   11736568  41. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2272   11736592  42. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2272   11736616  43. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2272   11736640  44. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2272   11736664  45. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2272   11736688  46. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2272   11736712  47. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2272   11736736  48. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2272   11736760  49. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2272   11736784  50. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2272   11736808  51. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2273   11736832  52. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2273   11736856  53. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2273   11736880  54. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2273   11736904  55. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2273   11736928  56. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2273   11736952  57. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2273   11736976  58. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2273   11737000  59. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2273   11737024  60. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2273   11737048  61. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2274   11737072  62. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2274   11737096  63. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2274   11737120  64. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2274   11737144  65. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2274   11737168  66. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2274   11737192  67. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2274   11737216  68. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2274   11737240  69. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2274   11737264  70. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2274   11737288  71. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2275   11737312  72. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2275   11737336  73. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2275   11737360  74. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2275   11737384  75. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2275   11737408  76. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2275   11737432  77. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2275   11737456  78. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2275   11737480  79. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2275   11737504  80. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2275   11737528  81. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2275   11737552  82. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2276   11737576  83. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2276   11737600  84. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2276   11737624  85. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2276   11737648  86. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2276   11737672  87. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2276   11737696  88. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2276   11737720  89. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2276   11737744  90. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2276   11737768  91. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2276   11737792  92. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2277   11737816  93. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2277   11737840  94. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2277   11737864  95. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2277   11737888  96. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2277   11737912  97. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2277   11737936  98. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2277   11737960  99. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2277   11737984 100. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2277   11738008 101. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2277   11738032 102. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2277   11738056 103. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2278   11738080 104. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2278   11738104 105. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2278   11738128 106. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2278   11738152 107. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2278   11738176 108. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2278   11738200 109. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2278   11738224 110. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2278   11738248 111. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2278   11738272 112. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2278   11738296 113. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2279   11738320 114. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2279   11738344 115. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2279   11738368 116. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2279   11738392 117. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2279   11738416 118. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2279   11738440 119. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2279   11738464 120. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2279   11738488 121. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2279   11738512 122. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2280   11738536 123. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2280   11738560 124. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2280   11738584 125. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2280   11738608 126. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2280   11738632 127. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2280   11738656 128. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2280   11738680 129. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2280   11738704 130. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2280   11738728 131. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2280   11738752 132. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2281   11738776 133. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2281   11738800 134. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2281   11738824 135. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2281   11738848 136. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2281   11738872 137. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2281   11738896 138. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2281   11738920 139. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2281   11738944 140. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2281   11738968 141. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2281   11738992 142. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2282   11739016 143. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2282   11739040 144. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2282   11739064 145. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2282   11739088 146. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2282   11739112 147. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2282   11739136 148. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2282   11739160 149. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2282   11739184 150. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2283   11739208 151. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2283   11739232 152. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2283   11739256 153. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2283   11739280 154. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2283   11739304 155. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2283   11739328 156. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2283   11739352 157. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2283   11739376 158. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2283   11739400 159. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2284   11739424 160. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2284   11739448 161. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2284   11739472 162. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2284   11739496 163. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2284   11739520 164. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2284   11739544 165. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2284   11739568 166. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2284   11739592 167. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2284   11739616 168. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2284   11739640 169. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2285   11739664 170. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2285   11739688 171. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2285   11739712 172. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2285   11739736 173. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2285   11739760 174. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2285   11739784 175. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2285   11739808 176. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2285   11739832 177. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2285   11739856 178. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2286   11739880 179. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2286   11739904 180. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2286   11739928 181. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2286   11739952 182. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2286   11739976 183. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2286   11740000 184. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2286   11740024 185. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2286   11740048 186. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2286   11740072 187. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2286   11740096 188. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2287   11740120 189. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2287   11740144 190. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2287   11740168 191. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2287   11740192 192. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2287   11740216 193. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2287   11740240 194. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2287   11740264 195. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2288   11740288 196. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2288   11740312 197. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2288   11740336 198. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2288   11740360 199. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2288   11740384 200. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2288   11740408 201. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2288   11740432 202. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2288   11740456 203. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2289   11740480 204. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2289   11740504 205. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2289   11740528 206. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2289   11740552 207. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2289   11740576 208. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2289   11740600 209. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2289   11740624 210. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2289   11740648 211. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2289   11740672 212. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2290   11740696 213. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2290   11740720 214. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2290   11740744 215. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2290   11740768 216. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2290   11740792 217. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2290   11740816 218. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2290   11740840 219. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2290   11740864 220. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2290   11740888 221. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2291   11740912 222. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2291   11740936 223. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2291   11740960 224. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2291   11740984 225. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2291   11741008 226. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2291   11741032 227. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2291   11741056 228. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2291   11741080 229. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2291   11741104 230. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2292   11741128 231. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2292   11741152 232. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2292   11741176 233. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2292   11741200 234. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2292   11741224 235. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2292   11741248 236. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2292   11741272 237. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2292   11741296 238. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2292   11741320 239. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2293   11741344 240. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2293   11741368 241. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2293   11741392 242. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2293   11741416 243. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2293   11741440 244. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2293   11741464 245. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2293   11741488 246. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2293   11741512 247. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2294   11741536 248. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2294   11741560 249. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2294   11741584 250. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2294   11741608 251. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2294   11741632 252. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2294   11741656 253. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2294   11741680 254. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2294   11741704 255. PhpParser\NodeTraverser->traverseNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:134
   59.2294   11741728 256. ComposerRequireChecker\NodeVisitor\DefinedSymbolCollector->enterNode() ~/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:115```

Slightly related https://github.com/maglnet/ComposerRequireChecker/issues/53

Optional dependencies

Some packages provides adapters/bridges for well-known other tools/framework (e.g. adapters for Doctrine/Propel/... ). However, only one of these corresponding dependencies should be installed, and it is selected by the end developer in the root project, so it must not appear in the "require" section of composer.json, but is generally in the "require-dev" section for testing purpose.

Could it be possible to show only a warning for symbols that are provided through require-dev ?

Return exit code to shell

By returning the exit code from the command this tool can be used in automation.

The last line of bin/composer-require-checker.php should be changed to:

return $application->run();

This will result in the following:

$ ./vendor/bin/composer-require-checker; echo $? 
ComposerRequireChecker xxxx
The following unknown symbols were found:
+--------------------+--------------------+
| unknown symbol     | guessed dependency |
+--------------------+--------------------+
| The\Unknown\Symbol |                    |
+--------------------+--------------------+
1

and

ComposerRequireChecker xxxx
There were no unknown symbols found.
0

Do you want me to provide a PR?

Unable to work with packages that don't export composer.json

The wikimedia/ip-set package is set to not export composer.json.

This causes the tool to ignore the package when it's installed by dist and then report the symbols as unknown.

I had a look through Composer and found that all the composer.json files are combined and stored in vendor/composer/installed.json. Before diving into it I thought I'd check what you thought about using this as the source of the composer.json data, rather than relying on a physical composer.json file in each vendor directory, or perhaps as fallback option if composer.json doesn't exist

Prevent vendor directory from being parsed

This could be a duplicate of #54
I'll open a separate issue though in order to avoid cluttering or take over that issue

When running composer-require-checker -vvv
I'm greeted with the following output after a few seconds:

ComposerRequireChecker unknown-development
Collecting defined vendor symbols...
In ParserAbstract.php line 315:

  [PhpParser\Error]
  Syntax error, unexpected ';', expecting T_VARIABLE or '{' or '$' on line 4


Exception trace:
 () at /home/vagrant/.composer/vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php:315
 PhpParser\ParserAbstract->doParse() at /home/vagrant/.composer/vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php:158
 PhpParser\ParserAbstract->parse() at /home/vagrant/.composer/vendor/nikic/php-parser/lib/PhpParser/Parser/Multiple.php:51
 PhpParser\Parser\Multiple->tryParse() at /home/vagrant/.composer/vendor/nikic/php-parser/lib/PhpParser/Parser/Multiple.php:32
 PhpParser\Parser\Multiple->parse() at /home/vagrant/.composer/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/ASTLocator/LocateASTFromFiles.php:35
 ComposerRequireChecker\ASTLocator\LocateASTFromFiles->__invoke() at /home/vagrant/.composer/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/DefinedSymbolsLocator/LocateDefinedSymbolsFromASTRoots.php:27
 ComposerRequireChecker\DefinedSymbolsLocator\LocateDefinedSymbolsFromASTRoots->__invoke() at /home/vagrant/.composer/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/Cli/CheckCommand.php:79
 ComposerRequireChecker\Cli\CheckCommand->execute() at /home/vagrant/.composer/vendor/symfony/console/Command/Command.php:255
 Symfony\Component\Console\Command\Command->run() at /home/vagrant/.composer/vendor/symfony/console/Application.php:908
 Symfony\Component\Console\Application->doRunCommand() at /home/vagrant/.composer/vendor/symfony/console/Application.php:269
 Symfony\Component\Console\Application->doRun() at /home/vagrant/.composer/vendor/symfony/console/Application.php:145
 Symfony\Component\Console\Application->run() at /home/vagrant/.composer/vendor/maglnet/composer-require-checker/bin/composer-require-checker.php:32
 include() at /home/vagrant/.composer/vendor/maglnet/composer-require-checker/bin/composer-require-checker:3

check [--config-file CONFIG-FILE] [--ignore-parse-errors] [--] [<composer-json>]

From the looks of it, it seems the error originates from the nikic/php-parser package. Unfortunately, the error doesn't tell which file is invalid. Given the fact that my code doesn't contain any syntax errors and the nikic/php-parser package due to it's wide adoption probably won't contain any obvious syntax errors as well, I figured the parser checks the vendor directory.

After running $ find . -name *.php -exec php -l {} \; in my vendor directory and ignoring all syntactically valid files, I'm left with the following output:

PHP Parse error:  syntax error, unexpected ';', expecting variable (T_VARIABLE) or '{' or '$' in ./vendor/jakub-onderka/php-parallel-lint/tests/examples/example-03/example.php on line 4

Parse error: syntax error, unexpected ';', expecting variable (T_VARIABLE) or '{' or '$' in ./vendor/jakub-onderka/php-parallel-lint/tests/examples/example-03/example.php on line 4
Errors parsing ./vendor/jakub-onderka/php-parallel-lint/tests/examples/example-03/example.php
PHP Parse error:  syntax error, unexpected 'echo' (T_ECHO) in ./vendor/jakub-onderka/php-parallel-lint/tests/examples/example-04/dir1/dir2/index.php on line 3

Parse error: syntax error, unexpected 'echo' (T_ECHO) in ./vendor/jakub-onderka/php-parallel-lint/tests/examples/example-04/dir1/dir2/index.php on line 3
Errors parsing ./vendor/jakub-onderka/php-parallel-lint/tests/examples/example-04/dir1/dir2/index.php
PHP Deprecated:  Methods with the same name as their class will not be constructors in a future version of PHP; MockeryTest_OldStyleConstructor has a deprecated constructor in ./vendor/mockery/mockery/tests/PHP56/MockingOldStyleConstructorTest.php on line 39

Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; MockeryTest_OldStyleConstructor has a deprecated constructor in ./vendor/mockery/mockery/tests/PHP56/MockingOldStyleConstructorTest.php on line 39
PHP Fatal error:  Cannot use Riak\Object as Object because 'Object' is a special class name in ./vendor/doctrine/cache/lib/Doctrine/Common/Cache/RiakCache.php on line 8

Fatal error: Cannot use Riak\Object as Object because 'Object' is a special class name in ./vendor/doctrine/cache/lib/Doctrine/Common/Cache/RiakCache.php on line 8
Errors parsing ./vendor/doctrine/cache/lib/Doctrine/Common/Cache/RiakCache.php
PHP Deprecated:  Methods with the same name as their class will not be constructors in a future version of PHP; Foo has a deprecated constructor in ./vendor/phpunit/php-token-stream/tests/_fixture/source.php on line 5

Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; Foo has a deprecated constructor in ./vendor/phpunit/php-token-stream/tests/_fixture/source.php on line 5
PHP Parse error:  syntax error, unexpected '{', expecting identifier (T_STRING) in ./vendor/phpunit/php-code-coverage/tests/_files/Crash.php on line 2

Parse error: syntax error, unexpected '{', expecting identifier (T_STRING) in ./vendor/phpunit/php-code-coverage/tests/_files/Crash.php on line 2
Errors parsing ./vendor/phpunit/php-code-coverage/tests/_files/Crash.php
PHP Parse error:  syntax error, unexpected '}', expecting ';' in ./vendor/sirbrillig/phpcs-variable-analysis/VariableAnalysis/Tests/CodeAnalysis/fixtures/FunctionWithClosureFixture.php on line 60

Parse error: syntax error, unexpected '}', expecting ';' in ./vendor/sirbrillig/phpcs-variable-analysis/VariableAnalysis/Tests/CodeAnalysis/fixtures/FunctionWithClosureFixture.php on line 60
Errors parsing ./vendor/sirbrillig/phpcs-variable-analysis/VariableAnalysis/Tests/CodeAnalysis/fixtures/FunctionWithClosureFixture.php
PHP Parse error:  syntax error, unexpected '$foo' (T_VARIABLE) in ./vendor/sirbrillig/phpcs-variable-analysis/VariableAnalysis/Tests/CodeAnalysis/fixtures/UnusedAfterUsedFixture.php on line 24

Parse error: syntax error, unexpected '$foo' (T_VARIABLE) in ./vendor/sirbrillig/phpcs-variable-analysis/VariableAnalysis/Tests/CodeAnalysis/fixtures/UnusedAfterUsedFixture.php on line 24
Errors parsing ./vendor/sirbrillig/phpcs-variable-analysis/VariableAnalysis/Tests/CodeAnalysis/fixtures/UnusedAfterUsedFixture.php
PHP Fatal error:  Cannot use "self" when no class scope is active in ./vendor/sirbrillig/phpcs-variable-analysis/VariableAnalysis/Tests/CodeAnalysis/fixtures/FunctionsOutsideClassFixture.php on line 8

Fatal error: Cannot use "self" when no class scope is active in ./vendor/sirbrillig/phpcs-variable-analysis/VariableAnalysis/Tests/CodeAnalysis/fixtures/FunctionsOutsideClassFixture.php on line 8
Errors parsing ./vendor/sirbrillig/phpcs-variable-analysis/VariableAnalysis/Tests/CodeAnalysis/fixtures/FunctionsOutsideClassFixture.php

As I suspected, the vendor directory contains syntactically invalid files. Upon manually 'fixing' the first two errors in the vendor directory, a rerun of composer-require-checker -vvv got me the next error in line:

ComposerRequireChecker unknown-development
Collecting defined vendor symbols...
In ParserAbstract.php line 315:

  [PhpParser\Error]
  Syntax error, unexpected T_ECHO on line 3


Exception trace:
 () at /home/vagrant/.composer/vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php:315
 PhpParser\ParserAbstract->doParse() at /home/vagrant/.composer/vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php:158
 PhpParser\ParserAbstract->parse() at /home/vagrant/.composer/vendor/nikic/php-parser/lib/PhpParser/Parser/Multiple.php:51
 PhpParser\Parser\Multiple->tryParse() at /home/vagrant/.composer/vendor/nikic/php-parser/lib/PhpParser/Parser/Multiple.php:32
 PhpParser\Parser\Multiple->parse() at /home/vagrant/.composer/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/ASTLocator/LocateASTFromFiles.php:35
 ComposerRequireChecker\ASTLocator\LocateASTFromFiles->__invoke() at /home/vagrant/.composer/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/DefinedSymbolsLocator/LocateDefinedSymbolsFromASTRoots.php:27
 ComposerRequireChecker\DefinedSymbolsLocator\LocateDefinedSymbolsFromASTRoots->__invoke() at /home/vagrant/.composer/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/Cli/CheckCommand.php:79
 ComposerRequireChecker\Cli\CheckCommand->execute() at /home/vagrant/.composer/vendor/symfony/console/Command/Command.php:255
 Symfony\Component\Console\Command\Command->run() at /home/vagrant/.composer/vendor/symfony/console/Application.php:908
 Symfony\Component\Console\Application->doRunCommand() at /home/vagrant/.composer/vendor/symfony/console/Application.php:269
 Symfony\Component\Console\Application->doRun() at /home/vagrant/.composer/vendor/symfony/console/Application.php:145
 Symfony\Component\Console\Application->run() at /home/vagrant/.composer/vendor/maglnet/composer-require-checker/bin/composer-require-checker.php:32
 include() at /home/vagrant/.composer/vendor/maglnet/composer-require-checker/bin/composer-require-checker:3

check [--config-file CONFIG-FILE] [--ignore-parse-errors] [--] [<composer-json>]

Which confirms my initial theory. Unfortunately... there's little for me to do here.
The third party packages are there to stay and most of these syntax errors originate from test files of the packages themselves. Hence they should contain syntax errors.

I did run composer-require-checker -vvv --ignore-parse-errors as well
Which got me (after 5 minute of waiting) an insane list of 'soft' dependencies of which 99.9% isn't referred to in my code. Given the fact that all the files in the vendor directory are parsed, I presume all files in there are checked against my first party composer.json

Now, given release note 2.0.0 states use installed.json instead of composer.json, the vendor directory should obviously exist. Removing it gives me The composer dependencies have not been installed, run composer install/update first.

A few questions:

  1. Is it possible to show the violating file. it would make debugging a whole lot easier (this might be more of a request for nikic/php-parser)
  2. Why is the full vendor directory being parsed?
  3. Is there a way to prevent files or whole directories from being parsed (vendor?)

Function exists checks are not passing the checker

I have code similar to:

if (function_exists('xdebug_get_function_stack')) {
	$trace = array_slice(array_reverse(xdebug_get_function_stack()), 4);
}

So running this with XDebug extension would get the trace differently, but it could work without XDebug. There could be other conditional uses of a function or a class, especially for backwards-compatibility.

However, the checker complains about these function uses as the parses doesn't detect the function_exists condition.

Which dependency for Composer\Script\Event ?

I have a package that provides a script handler for Composer. It depends on Composer\Script\Event, which will be provided by Composer when it will be executed. As I do not want that every user of this package pulls the entire Composer sources, composer/composer is not listed in the dependencies. Yet ComposerRequireChecker complains about it.

Is there any solution to this ?

provide docker image

It could be really nice if a Docker image was provided, so that one could use a command like

docker run -v $(pwd):/app compoesrrequirechecker

to run the executable

Support for metapackages (type: metapackage, type:symfony-pack)

Composer has a concept of metapackage package type which allows a package to declare multiple dependencies, but the user only requires the metapackage.

Symfony takes advantage of this with packs, for example orm-pack or profiler-pack and users are encouraged to install those instead of regular packages since Symfony 4 and introduction of Symfony Flex.

This obviously means any deps declared by the pack is marked by the tool as invalid, even though the pack's specific purpose is to be a transitive dependency.

I propose to include support for such packages and mark all their direct dependencies as if they were "unpacked".

Since not all packages marked with type: metapackage will follow the same strict versioning discipline as Symfony packs, it might make sense to leave it up to the end user which package types to trust like this, example

# no metapackages
bin/crc 

# trust both type: metapackage and type: symfony-pack
bin/crc --include-metapackage

# trust only type: symfony-pack
bin/crc --include-metapackage=symfony-pack

Or similar.

/cc @alcaeus @tgalopin

DefinedSymbolCollector - Breaks on anonymous classes

$ cd /var/www/my_project
$ php composer-require-checker check composer.json 
ComposerRequireChecker 0.1.4

                                                                                                                                                     
  [UnexpectedValueException]                                                                                                                         
  Given node of type "PhpParser\Node\Stmt\Class_" (defined at line 129)does not have an assigned "namespacedName" property: did you pass it through  
   a name resolver visitor?                                                                                                                          
                                                                                                                                                     

check [--config-file CONFIG-FILE] [--] [<composer-json>]

not sure how to proceed?

This seems to cause the exception; from composer.json

  "autoload": {
    "psr-4": {
      "ProjectName\\": "src"
    }
  },

Report dependency class as unknown, even if it's in vendor folder

Hi !
I would be grateful for any hints on that !
Symfony\Component\Finder\Finder is reported as unknown, even if it's properly installed as dependency

ker@dus:~/github/FriendsOfPHP/PHP-CS-Fixer$ composer update -q

ker@dus:~/github/FriendsOfPHP/PHP-CS-Fixer$ php composer-require-checker.phar check | grep Finder
| Symfony\Component\Finder\Finder                                     |                    |
| Symfony\Component\Finder\SplFileInfo                                |                    |
| Symfony\Component\Process\PhpExecutableFinder                       |                    |

ker@dus:~/github/FriendsOfPHP/PHP-CS-Fixer$ cat vendor/symfony/finder/Finder.php | grep -P "(?:class|namespace) "
namespace Symfony\Component\Finder;
class Finder implements \IteratorAggregate, \Countable

False positive when using class_alias function

When using function class_alias there is false positive result for alias.

Example:

git clone [email protected]:PHP-CS-Fixer/phpunit-constraint-isidenticalstring.git
cd phpunit-constraint-isidenticalstring
composer u
composer u -d dev-tools
dev-tools/vendor/bin/composer-require-checker check

and the result will be:

The following unknown symbols were found:
+----------------------------------------------------------------------------+--------------------+
| unknown symbol                                                             | guessed dependency |
+----------------------------------------------------------------------------+--------------------+
| PhpCsFixer\PhpunitConstraintIsIdenticalString\Constraint\IsIdenticalString |                    |
+----------------------------------------------------------------------------+--------------------+

and it is only used as an alias in class_alias function.

Add config-file for PHP-symbols

Currently the internal symbol-table of the running PHP-binary is used to check for PHP-symbols that might be required. What happens when you required f.e. ext-ldap and run the checker using a PHP-binary that hasn't ext-ldap available? It will surely result in a false-positive.

I still need to check what happens but I'll report back.

Solution would be to have a config-file that contains all symbols that might be available in a PHP-build. This file could be created from the PHP-source code. That file would only contain the PHP-src and ex folders. PECL should not be included!

ParserAbstract ERROR by Swaggehub generated library

I have a problem:
Tested with ComposerRequireChecker 1.0.0 & ComposerRequireChecker 1.1.0
php composer-require-checker.phar check -vvv

In ParserAbstract.php line 313:

  [PhpParser\Error]
  Syntax error, unexpected T_IMPLEMENTS, expecting T_STRING on line 43


Exception trace:
 PhpParser\ParserAbstract->doParse() at phar:///srv/.../composer-require-checker.phar/vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php:156
 PhpParser\ParserAbstract->parse() at phar:///.../composer-require-checker.phar/vendor/nikic/php-parser/lib/PhpParser/Parser/Multiple.php:51
 PhpParser\Parser\Multiple->tryParse() at phar:///.../composer-require-checker.phar/vendor/nikic/php-parser/lib/PhpParser/Parser/Multiple.php:32
 PhpParser\Parser\Multiple->parse() at phar:///..../composer-require-checker.phar/src/ComposerRequireChecker/ASTLocator/LocateASTFromFiles.php:35
 ComposerRequireChecker\ASTLocator\LocateASTFromFiles->__invoke() at phar:///.../composer-require-checker.phar/src/ComposerRequireChecker/DefinedSymbolsLocator/LocateDefinedSymbolsFromASTRoots.php:27
 ComposerRequireChecker\DefinedSymbolsLocator\LocateDefinedSymbolsFromASTRoots->__invoke() at phar:///srv/.../composer-require-checker.phar/src/ComposerRequireChecker/Cli/CheckCommand.php:76
 ComposerRequireChecker\Cli\CheckCommand->execute() at phar:///.../composer-require-checker.phar/vendor/symfony/console/Command/Command.php:251
 Symfony\Component\Console\Command\Command->run() at phar:///srv/.../composer-require-checker.phar/vendor/symfony/console/Application.php:886
 Symfony\Component\Console\Application->doRunCommand() at phar:///srv/.../composer-require-checker.phar/vendor/symfony/console/Application.php:262
 Symfony\Component\Console\Application->doRun() at phar:///srv/.../composer-require-checker.phar/vendor/symfony/console/Application.php:145
 Symfony\Component\Console\Application->run() at phar:///srv/.../composer-require-checker.phar/bin/composer-require-checker.php:32
 include() at ..../composer-require-checker.phar:10

I have the message with generated library from swaggehub. But, the problem have not every library from swaggehub
here is composer.json:

{
    "name": "any/name",
    "version": "1.0",
    "description": "",
    "keywords": [
        "swagger",
        "php",
        "sdk",
        "api"
    ],
    "homepage": "http://swagger.io",
    "license": "proprietary",
    "authors": [
        {
            "name": "Swagger and contributors",
            "homepage": "https://github.com/swagger-api/swagger-codegen"
        }
    ],
    "require": {
        "php": ">=5.5",
        "ext-curl": "*",
        "ext-json": "*",
        "ext-mbstring": "*",
        "guzzlehttp/guzzle": "^6.2"
    },
    "require-dev": {
        "phpunit/phpunit": "^4.8",
        "squizlabs/php_codesniffer": "~2.6",
        "friendsofphp/php-cs-fixer": "~1.12"
    },
    "autoload": {
        "psr-4": { "...\\V1\\" : "src/" }
    },
    "autoload-dev": {
        "psr-4": { "...\\V1\\" : "test/" }
    }
}

Exception because of invalid php (xml) file in symfony/dependency-injection

# vendor/bin/composer-require-checker -vvv
ComposerRequireChecker b58b51e-dev

                                               
  [PhpParser\Error]                            
  Syntax error, unexpected T_STRING on line 1  
                                               

Exception trace:
 () at /app/vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php:293
 PhpParser\ParserAbstract->parse() at /app/vendor/nikic/php-parser/lib/PhpParser/Parser/Multiple.php:50
 PhpParser\Parser\Multiple->tryParse() at /app/vendor/nikic/php-parser/lib/PhpParser/Parser/Multiple.php:31
 PhpParser\Parser\Multiple->parse() at /app/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/ASTLocator/LocateASTFromFiles.php:28
 ComposerRequireChecker\ASTLocator\LocateASTFromFiles->__invoke() at /app/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/DefinedSymbolsLocator/LocateDefinedSymbolsFromASTRoots.php:28
 ComposerRequireChecker\DefinedSymbolsLocator\LocateDefinedSymbolsFromASTRoots->__invoke() at /app/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/Cli/CheckCommand.php:72
 ComposerRequireChecker\Cli\CheckCommand->execute() at /app/vendor/symfony/console/Command/Command.php:262
 Symfony\Component\Console\Command\Command->run() at /app/vendor/symfony/console/Application.php:888
 Symfony\Component\Console\Application->doRunCommand() at /app/vendor/symfony/console/Application.php:224
 Symfony\Component\Console\Application->doRun() at /app/vendor/symfony/console/Application.php:125
 Symfony\Component\Console\Application->run() at /app/vendor/maglnet/composer-require-checker/bin/composer-require-checker.php:32
 include() at /app/vendor/maglnet/composer-require-checker/bin/composer-require-checker:3

check [--config-file CONFIG-FILE] [--] [<composer-json>]

That happened when try to parse invalid php file in symfony/dependency-injection
Only if symfony/dependency-injection specified in my composer.json file

phar file lacks shebang

βž” wget https://github.com/maglnet/ComposerRequireChecker/releases/download/0.1.5/composer-require-checker.phar
βž” chmod a+rx composer-require-checker.phar
βž” ./composer-require-checker.phar
./composer-require-checker.phar: line 1: ?php: No such file or directory
./composer-require-checker.phar: line 3: =: command not found
./composer-require-checker.phar: line 5: syntax error near unexpected token `'phar','
./composer-require-checker.phar: line 5: `if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) {'
βž” head -n 1 composer-require-checker.phar
<?php

please add:

#!/usr/bin/env php

that should be most portable.

Accept extensions defined in `config.platform`

Composer would accept config.platform versions when resolving dependencies even if they are not present on a local installation. Could the require checker use that and do not report missing extensions when they are defined in config.platform?
This of course assumes the versions you define in config.platform are really present on your production environment.

Links:

json decoding is not handling nicely

output of json_decode is not handled, thus in case of any json-violation, we got following error:

Type error: Argument 1 passed to ComposerRequireChecker\Cli\Options::__construct() must be of the type array, null given, called in ...

Please make a new release ;)

Hi, recently you have merged PR that allows for Sf v4, yet there is no release with it.
Please, could you create one?

Report guess dependencies from installed modules

I got the following output:

+-----------------------------------------+--------------------+
| unknown symbol                          | guessed dependency |
+-----------------------------------------+--------------------+
| mindplay\implant\AssetPackage           |                    |
| trim                                    | ext-standard       |
| preg_replace                            | ext-pcre           |
| RuntimeException                        | ext-SPL            |
| implode                                 | ext-standard       |
| array_map                               | ext-standard       |
| array_keys                              | ext-standard       |
| Kodus\Session\SessionModel              |                    |
| count                                   | ext-standard       |
| Psr\Http\Message\ServerRequestInterface |                    |
| Psr\Http\Message\ResponseInterface      |                    |
| Zend\Diactoros\Response                 |                    |
| mindplay\kisstpl\SimpleViewFinder       |                    |
| call_user_func                          | ext-standard       |
| Zend\Diactoros\Stream                   |                    |
| Codeception\Module                      |                    |
| Codeception\Lib\ModuleContainer         |                    |
| Kodus\Test\FunctionalSupport            |                    |
| Codeception\TestInterface               |                    |
| array_merge                             | ext-standard       |
+-----------------------------------------+--------------------+

All of the dependencies with no guessed dependency, in this example, could have been guessed - they're all installed. Reporting them ought to be fairly easy?

Bonus points for reporting the suggested version constraint πŸ˜ƒ

Extra bonus points and cookies πŸͺ for an option to automatically update your composer.json with suggested version constraints! πŸ‘€

Syntax error, unexpected T_STRING

$ composer-require-checker -vv


Warning: preg_match(): Compilation failed: nothing to repeat at offset 1 in phar:///usr/bin/composer-require-checker/src/ComposerRequireChecker/FileLocator/LocateAllFilesByExtension.php on line 29

Warning: preg_match(): Compilation failed: nothing to repeat at offset 1 in phar:///usr/bin/composer-require-checker/src/ComposerRequireChecker/FileLocator/LocateAllFilesByExtension.php on line 29

Warning: preg_match(): Compilation failed: nothing to repeat at offset 1 in phar:///usr/bin/composer-require-checker/src/ComposerRequireChecker/FileLocator/LocateAllFilesByExtension.php on line 29

Warning: preg_match(): Compilation failed: nothing to repeat at offset 1 in phar:///usr/bin/composer-require-checker/src/ComposerRequireChecker/FileLocator/LocateAllFilesByExtension.php on line 29

Warning: preg_match(): Compilation failed: nothing to repeat at offset 1 in phar:///usr/bin/composer-require-checker/src/ComposerRequireChecker/FileLocator/LocateAllFilesByExtension.php on line 29

Warning: preg_match(): Compilation failed: nothing to repeat at offset 1 in phar:///usr/bin/composer-require-checker/src/ComposerRequireChecker/FileLocator/LocateAllFilesByExtension.php on line 29

# And many more Warning like that.

In ParserAbstract.php line 293:
                                               
  [PhpParser\Error]                            
  Syntax error, unexpected T_STRING on line 1  
                                               

Exception trace:
 PhpParser\ParserAbstract->parse() at phar:///usr/bin/composer-require-checker/vendor/nikic/php-parser/lib/PhpParser/Parser/Multiple.php:50
 PhpParser\Parser\Multiple->tryParse() at phar:///usr/bin/composer-require-checker/vendor/nikic/php-parser/lib/PhpParser/Parser/Multiple.php:31
 PhpParser\Parser\Multiple->parse() at phar:///usr/bin/composer-require-checker/src/ComposerRequireChecker/ASTLocator/LocateASTFromFiles.php:35
 ComposerRequireChecker\ASTLocator\LocateASTFromFiles->__invoke() at phar:///usr/bin/composer-require-checker/src/ComposerRequireChecker/DefinedSymbolsLocator/LocateDefinedSymbolsFromASTRoots.php:27
 ComposerRequireChecker\DefinedSymbolsLocator\LocateDefinedSymbolsFromASTRoots->__invoke() at phar:///usr/bin/composer-require-checker/src/ComposerRequireChecker/Cli/CheckCommand.php:73
 ComposerRequireChecker\Cli\CheckCommand->execute() at phar:///usr/bin/composer-require-checker/vendor/symfony/console/Command/Command.php:252
 Symfony\Component\Console\Command\Command->run() at phar:///usr/bin/composer-require-checker/vendor/symfony/console/Application.php:865
 Symfony\Component\Console\Application->doRunCommand() at phar:///usr/bin/composer-require-checker/vendor/symfony/console/Application.php:241
 Symfony\Component\Console\Application->doRun() at phar:///usr/bin/composer-require-checker/vendor/symfony/console/Application.php:143
 Symfony\Component\Console\Application->run() at phar:///usr/bin/composer-require-checker/bin/composer-require-checker.php:32
 include() at /usr/bin/composer-require-checker:10

check [--config-file CONFIG-FILE] [--ignore-parse-errors] [--] [<composer-json>]

Using --ignore-parse-errors works but keep the lot of warning messages.

It would be great to see which files causes this error.

False positives on some bundle and classes

Command result (extract):

+--------------------------------------------------------------------------+--------------------+
| unknown symbol                                                           | guessed dependency |
+--------------------------------------------------------------------------+--------------------+
| Nelmio\ApiDocBundle\NelmioApiDocBundle                                   |                    |
| Gregwar\ImageBundle\GregwarImageBundle                                   |                    |
| Ornicar\GravatarBundle\OrnicarGravatarBundle                             |                    |
| A2lix\TranslationFormBundle\A2lixTranslationFormBundle                   |                    |
| Browscap\BrowscapBundle\BrowscapBundle                                   |                    |
| EightPoints\Bundle\GuzzleBundle\GuzzleBundle                             |                    |
| SLLH\IsoCodesValidator\Bridge\Symfony\Bundle\SLLHIsoCodesValidatorBundle |                    |
| Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle                      |                    |
| Sonata\EasyExtendsBundle\SonataEasyExtendsBundle                         |                    |
| Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle                    |                    |
| JMS\TranslationBundle\JMSTranslationBundle                               |                    |
| Joli\GifExceptionBundle\GifExceptionBundle                               |                    |
| DAMA\DoctrineTestBundle\DAMADoctrineTestBundle                           |                    |
| Liip\FunctionalTestBundle\LiipFunctionalTestBundle                       |                    |
| A2lix\TranslationFormBundle\Form\Type\TranslationsType                   |                    |
| KERNEL_ROOT_DIR                                                          |                    |
| Ornicar\GravatarBundle\GravatarApi                                       |                    |
| Swift_Mailer                                                             |                    |
| Swift_Attachment                                                         |                    |
| Swift_Message                                                            |                    |
| SLLH\IsoCodesValidator\Constraints\CreditCard                            |                    |
| Composer\Script\Event                                                    |                    |
+--------------------------------------------------------------------------+--------------------+

But the corresponding bundles are required on the root composer.json file:

{
        "php": "^7.1",
        "ext-PDO": "^7.1",
        "ext-dom": "20031129",
        "ext-filter": "^7.1",
        "ext-hash": "^1.0",
        "ext-intl": "^1.0.2",
        "ext-json": "^1.5",
        "ext-openssl": "^7.1",
        "a2lix/translation-form-bundle": "^2.1",
        "algatux/influxdb-bundle": "^2.1",
        "behat/transliterator": "^1.2",
        "browscap/browscap-bundle": "^1.0",
        "browscap/browscap-php": "^2.1",
        "cebe/markdown": "^1.1",
        "digitick/sepa-xml": "^1.0",
        "doctrine/annotations": "^1.6",
        "doctrine/cache": "^1.7",
        "doctrine/collections": "^1.5",
        "doctrine/common": "^2.8",
        "doctrine/dbal": "^2.6",
        "doctrine/doctrine-bundle": "^1.6",
        "doctrine/doctrine-cache-bundle": "^1.3",
        "doctrine/doctrine-migrations-bundle": "^1.0",
        "doctrine/inflector": "^1.3",
        "doctrine/orm": "^2.6",
        "dompdf/dompdf": "^0.8",
        "egulias/email-validator": "^2.1",
        "eightpoints/guzzle-bundle": "^6.1",
        "emojione/emojione": "^3.1.2",
        "fabpot/goutte": "^3.0",
        "friendsofsymfony/jsrouting-bundle": "^1.5",
        "friendsofsymfony/oauth-server-bundle": "^1.4",
        "friendsofsymfony/oauth2-php": "^1.2",
        "friendsofsymfony/rest-bundle": "^2.0",
        "friendsofsymfony/user-bundle": "^2.0",
        "fzaninotto/faker": "^1.7",
        "giggsey/libphonenumber-for-php": "^8.9",
        "greg0ire/enum": "^3.1",
        "gregwar/image-bundle": "^2.1",
        "guzzlehttp/guzzle": "^6.0",
        "hackzilla/password-generator": "^1.4",
        "hackzilla/password-generator-bundle": "^2.0",
        "hautelook/alice-bundle": "^1.0",
        "incenteev/composer-parameter-handler": "^2.0",
        "influxdb/influxdb-php": "^1.14",
        "inlinestyle/inlinestyle": "^1.2",
        "internations/solr-utils": "^0.8",
        "jms/serializer": "^1.11",
        "jms/serializer-bundle": "^2.1",
        "jms/translation-bundle": "^1.4",
        "knplabs/doctrine-behaviors": "^1.4",
        "knplabs/knp-markdown-bundle": "^1.3",
        "knplabs/knp-menu": "^2.3",
        "knplabs/knp-menu-bundle": "^2.0",
        "knplabs/knp-paginator-bundle": "^2.4.3",
        "kriswallsmith/spork": "^0.3",
        "lexik/jwt-authentication-bundle": "^2.4",
        "lstrojny/fxmlrpc": "^0.14.0",
        "misd/phone-number-bundle": "^1.2",
        "monolog/monolog": "^1.23",
        "mtdowling/cron-expression": "^1.1",
        "nelmio/alice": "^2.0",
        "nelmio/api-doc-bundle": "dev-nexy as 2.10",
        "nexylan/cloudflare": "dev-master",
        "nexylan/cloudflare-host-gw": "^0.1",
        "nexylan/gandi-sdk": "^0.3",
        "nexylan/graylog-sdk": "^0.1",
        "nexylan/nexycrypt": "^0.2",
        "nexylan/paybox-direct": "^0.3.4",
        "nexylan/slack": "^1.7",
        "nexylan/slack-bundle": "^1.1",
        "ornicar/gravatar-bundle": "^1.2",
        "ovh/ovh": "^2.0",
        "patchwork/utf8": "^1.3",
        "php-http/guzzle6-adapter": "^1.1",
        "php-http/httplug-bundle": "^1.7",
        "predis/predis": "^1.0",
        "psr/http-message": "^1.0",
        "psr/log": "^1.0",
        "rollerworks/password-strength-bundle": "^2.0",
        "rollerworks/password-strength-validator": "^1.0",
        "sensio/distribution-bundle": "^5.0",
        "sensio/framework-extra-bundle": "^5.0.1",
        "simplethings/entity-audit-bundle": "^1.0.1",
        "sllh/iso-codes-validator": "^3.1",
        "snc/redis-bundle": "^2.0,>2.0.2",
        "sonata-project/admin-bundle": "^3.3",
        "sonata-project/block-bundle": "^3.12",
        "sonata-project/core-bundle": "^3.9",
        "sonata-project/doctrine-extensions": "^1.0",
        "sonata-project/doctrine-orm-admin-bundle": "^3.0.3",
        "sonata-project/intl-bundle": "^2.2",
        "stof/doctrine-extensions-bundle": "^1.1",
        "swiftmailer/swiftmailer": "^6.0",
        "symfony/dotenv": "^4.0",
        "symfony/monolog-bundle": "^3.0",
        "symfony/phpunit-bridge": "^3.1",
        "symfony/swiftmailer-bundle": "^3.0",
        "symfony/symfony": "^3.4",
        "tilleuls/ovh-bundle": "^1.0",
        "twig/extensions": "^1.0",
        "twig/twig": "^2.4",
        "webmozart/assert": "^1.2"
    },
    "require-dev": {
        "behat/mink-browserkit-driver": "^1.3",
        "behat/mink-extension": "^2.0",
        "behat/mink-selenium2-driver": "^1.2",
        "behat/symfony2-extension": "^2.0",
        "dama/doctrine-test-bundle": "^4.0",
        "doctrine/doctrine-fixtures-bundle": "^2.4",
        "jolicode/gif-exception-bundle": "^1.4",
        "knplabs/friendly-contexts": "^0.8",
        "liip/functional-test-bundle": "^1.9",
        "lookyman/phpstan-symfony": "^0.4.1",
        "phpdocumentor/reflection-docblock": "^3.2.3",
        "phpstan/phpstan-doctrine": "^0.9.1",
        "phpstan/phpstan-phpunit": "^0.9.3",
        "phpstan/phpstan-shim": "^0.9.1",
        "phpstan/phpstan-strict-rules": "^0.9.0",
        "phpunit/phpunit": "^6.4",
        "sensio/generator-bundle": "^3.1",
        "sonata-project/easy-extends-bundle": "^2.5",
        "symfony/web-server-bundle": "^3.3"
    }

xdebug max nesting level issue

With a quite big PHP project:

sullivan@7a64e1e9f7f3:/code$ php composer-require-checker.phar 
ComposerRequireChecker 0.2.0

Fatal error: Uncaught Error: Maximum function nesting level of '256' reached, aborting! in phar:///code/composer-require-checker.phar/src/ComposerRequireChecker/NodeVisitor/DefinedSymbolCollector.php on line 49

Error: Maximum function nesting level of '256' reached, aborting! in phar:///code/composer-require-checker.phar/src/ComposerRequireChecker/NodeVisitor/DefinedSymbolCollector.php on line 49

This max nesting level should be increased via ini_get or xdebug should be disabled at runtime if you don't need it.

Some ideas for further optimization

Some of these might already be in the pipeline.

  • Show where the symbols have been found (file, line)
  • Show what exotic PHP-Extensions should be required (like mbstring or intl or ldap) -> #9

Hard error don't show which file was tried to be analyzed

Tried it the first time today, was greeted with this (already added -vvv to get a stacktrace):

$ vendor/bin/composer-require-checker -vvv
ComposerRequireChecker 0c658da3e-dev
Collecting defined vendor symbols...
In ParserAbstract.php line 315:

  [PhpParser\Error]
  Syntax error, unexpected ';', expecting T_VARIABLE or '{' or '$' on line 4


Exception trace:
 () at /vagrant/project/vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php:315
 PhpParser\ParserAbstract->doParse() at /vagrant/project/vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php:158
 PhpParser\ParserAbstract->parse() at /vagrant/project/vendor/nikic/php-parser/lib/PhpParser/Parser/Multiple.php:51
 PhpParser\Parser\Multiple->tryParse() at /vagrant/project/vendor/nikic/php-parser/lib/PhpParser/Parser/Multiple.php:32
 PhpParser\Parser\Multiple->parse() at /vagrant/project/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/ASTLocator/LocateASTFromFiles.php:35
 ComposerRequireChecker\ASTLocator\LocateASTFromFiles->__invoke() at /vagrant/project/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/DefinedSymbolsLocator/LocateDefinedSymbolsFromASTRoots.php:27
 ComposerRequireChecker\DefinedSymbolsLocator\LocateDefinedSymbolsFromASTRoots->__invoke() at /vagrant/project/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/Cli/CheckCommand.php:79
 ComposerRequireChecker\Cli\CheckCommand->execute() at /vagrant/project/vendor/symfony/console/Command/Command.php:255
 Symfony\Component\Console\Command\Command->run() at /vagrant/project/vendor/symfony/console/Application.php:921
 Symfony\Component\Console\Application->doRunCommand() at /vagrant/project/vendor/symfony/console/Application.php:273
 Symfony\Component\Console\Application->doRun() at /vagrant/project/vendor/symfony/console/Application.php:149
 Symfony\Component\Console\Application->run() at /vagrant/project/vendor/maglnet/composer-require-checker/bin/composer-require-checker.php:32
 include() at /vagrant/project/vendor/maglnet/composer-require-checker/bin/composer-require-checker:3

check [--config-file CONFIG-FILE] [--ignore-parse-errors] [--] [<composer-json>]

After I changed \ComposerRequireChecker\ASTLocator\LocateASTFromFiles::__invoke to this:

    public function __invoke(Traversable $files): Traversable
    {
        foreach ($files as $file) {
            echo "$file\n";
            yield $this->parser->parse(file_get_contents($file), $this->errorHandler);
        }
    }

I was able to locate the file in question => it's another vendor file:

…
/vagrant/project/vendor/guzzlehttp/guzzle/src/Client.php
/vagrant/project/vendor/jakub-onderka/php-parallel-lint/./bin/skip-linting.php
/vagrant/project/vendor/jakub-onderka/php-parallel-lint/./tests/examples/example-03/example.php

In ParserAbstract.php line 315:

  [PhpParser\Error]
  Syntax error, unexpected ';', expecting T_VARIABLE or '{' or '$' on line 4

That's a linter project whose tests contain invalid code.

Nevertheless, two suggestions:

  • don't make me have to use -vvv to get a stacktrace
  • report the file which has an error

zend-opcache conflict

Hi. Thanks so much for ComposerRequireChecker. I spent the day with it on a medium sized project and it found quite a few things to fix. great tool!

One small problem:

if i specify

require: {
        "ext-zend-opcache": "*",
}

in my composer.json then composer update works as expected but i get an error Extension zend-opcache does not exist from require checker.

if i specify

require: {
        "ext-Zend Opcache": "*",
}

in composer.json, then composer update fails with The requested PHP extension ext-zend opcache should be required as ext-zend-opcache. but require checker is happy

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.