Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] embrace PSR, option, pipe, phar #186

Closed
wants to merge 28 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
/conf/config.local.yml
/vendor
/.idea
/.phpcd/
/tests/tmp/
120 changes: 39 additions & 81 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,42 +108,15 @@ There's also **experimental** level 5 that currently enables:
* Union types (Foo|Bar will be a specified type with checks performed on it instead of mixed)
* Checking function and method argument types when calling them

## Configuration
## ~~Configuration~~

Config file is passed to the `phpstan` executable with `-c` option:

```
vendor/bin/phpstan analyse -l 4 -c phpstan.neon src tests
```

When using a custom project config file, you have to pass the `--level` (`-l`)
option to `analyse` command (default value does not apply here).

[NEON file format](https://ne-on.org/) is very similar to YAML.
All the following options are part of the `parameters` section.
Only option is supported.

### Autoloading

PHPStan uses Composer autoloader so the easiest way how to autoload classes
is through the `autoload`/`autoload-dev` sections in composer.json.

#### Specify paths to scan

If PHPStan complains about some nonexistent classes and you're sure the classes
exist in the codebase AND you don't want to use Composer autoloader for some reason,
you can specify directories to scan and concrete files to include using
`autoload_directories` and `autoload_files` array parameters:

```yaml
parameters:
autoload_directories:
- %rootDir%/../../../build
autoload_files:
- %rootDir%/../../../generated/routes/GeneratedRouteList.php
```

`%rootDir%` is expanded to the root directory where PHPStan resides.

#### Autoloading for global installation

PHPStan supports global installation using [`composer global`](https://getcomposer.org/doc/03-cli.md#global).
Expand All @@ -160,51 +133,34 @@ or you're running PHPStan from a different directory,
you can specify the path to the autoloader with the `--autoload-file|-a` option:

```bash
phpstan analyse --autoload-file=/path/to/autoload.php src tests
phpstan analyse --autoload-file=/path/to/autoload.php --autoload-file=/path/to/another.php src tests
```

### Exclude files from analysis

If your codebase contains some files that are broken on purpose
(e. g. to test behaviour of your application on files with invalid PHP code),
you can exclude them using the `excludes_analyse` array parameter. String at each line
is used as a pattern for the [`fnmatch`](https://secure.php.net/manual/en/function.fnmatch.php) function.
you can specify the ignoring path with the `--ignore-path|-P` option:
String at each line is used as a pattern for the [`fnmatch`](https://secure.php.net/manual/en/function.fnmatch.php) function.

```yaml
parameters:
excludes_analyse:
- %rootDir%/../../../tests/*/data/*
```bash
phpstan analyse --ignore-path='tests/*/data/*' src tests
```

### Include custom extensions

If your codebase contains php files with extensions other than the standard .php extension then you can add them
to the `fileExtensions` array parameter:

```yaml
parameters:
fileExtensions:
- php
- module
- inc
```
### ~~Include custom extensions~~
Only support check php file.

### Universal object crates
### Universal object crates [TODO]

Classes without predefined structure are common in PHP applications.
They are used as universal holders of data - any property can be set and read on them. Notable examples
include `stdClass`, `SimpleXMLElement` (these are enabled by default), objects with results of database queries etc.
Use `universalObjectCratesClasses` array parameter to let PHPStan know which classes
with these characteristics are used in your codebase:

```yaml
parameters:
universalObjectCratesClasses:
- Dibi\Row
- Ratchet\ConnectionInterface
```
This need another option.

### Add non-obviously assigned variables to scope
### Add non-obviously assigned variables to scope [TODO]

If you use the initial assignment variable after for-loop or while-loop, set `polluteScopeWithLoopInitialAssignments` boolean parameter to `true`.

Expand Down Expand Up @@ -295,44 +251,46 @@ parameters:
### Ignore error messages with regular expresions

If some issue in your code base is not easy to fix or just simply want to deal with it later,
you can exclude error messages from the analysis result with regular expressions:
you can specify the ignoring pattern with the `--ignore-error|-E` option:

```yaml
parameters:
ignoreErrors:
- '#Call to an undefined method [a-zA-Z0-9\\_]+::method\(\)#'
- '#Call to an undefined method [a-zA-Z0-9\\_]+::expects\(\)#'
- '#Access to an undefined property PHPUnit_Framework_MockObject_MockObject::\$[a-zA-Z0-9_]+#'
- '#Call to an undefined method PHPUnit_Framework_MockObject_MockObject::[a-zA-Z0-9_]+\(\)#'
```bash
phpstan analyse --ignore-error='Call to an undefined method [a-zA-Z0-9\\_]+::method\(\)' \
--ignore-error='Call to an undefined method [a-zA-Z0-9\\_]+::expects\(\)' \
--ignore-error='Access to an undefined property PHPUnit_Framework_MockObject_MockObject::\$[a-zA-Z0-9_]+' \
--ignore-error='Call to an undefined method PHPUnit_Framework_MockObject_MockObject::[a-zA-Z0-9_]+\(\)' \
src tests
```

If some of the patterns do not occur in the result anymore, PHPStan will let you know
and you will have to remove the pattern from the configuration. You can turn off
this behavior by setting `reportUnmatchedIgnoredErrors` to `false` in PHPStan configuration.
`reportUnmatchedIgnoredErrors` has been removed. The `--ignore-error` option will
never pollute the result list.

### Bootstrap file
### ~~Bootstrap file~~

If you need to initialize something in PHP runtime before PHPStan runs (like your own autoloader),
you can provide your own bootstrap file:
Use the `--autoload-path|-a` option instead.

```yaml
parameters:
bootstrap: %rootDir%/../../../phpstan-bootstrap.php
### Custom rules

You can use the `--level` option to use a preset rules to check your source. However,
if you want use all the level n rules but SomeBuiltInRule, you can specify the
`--ignore-rule|-R` option:

```bash
phpstan analyse --level=5 --rule='Methods\ReturnTypeRule' src tests
```

### Custom rules
**Please notice the leading slash, the builtin rule name should be relative name!**

Use `phpstan analyse --help` will get all bultin rule list.

PHPStan allows writing custom rules to check for specific situations in your own codebase. Your rule class
needs to implement the `PHPStan\Rules\Rule` interface and registered as a service in the configuration file:
needs to implement the `PHPStan\Rules\Rule` interface and specify the rule with the `--rule|-r` option:

```yaml
services:
-
class: MyApp\PHPStan\Rules\DefaultValueTypesAssignedToPropertiesRule
tags:
- phpstan.rules.rule
```bash
phpstan analyse --rule='\MyApp\PHPStan\Rules\DefaultValueTypesAssignedToPropertiesRule' src tests
```

**Please notice the leading slash, the custom rule name should be FQCN!**

For inspiration on how to implement a rule turn to [src/Rules](https://github.com/phpstan/phpstan/tree/master/src/Rules)
to see a lot of built-in rules.

Expand Down
13 changes: 6 additions & 7 deletions bin/phpstan
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,21 @@
<?php declare(strict_types=1);

use PHPStan\Command\AnalyseCommand;
use PHPStan\FileHelper;

gc_disable(); // performance boost

$autoloaderInWorkingDirectory = getcwd() . '/vendor/autoload.php';
if (is_file($autoloaderInWorkingDirectory)) {
require_once($autoloaderInWorkingDirectory);
require_once($autoloaderInWorkingDirectory);
}

if (!class_exists('PHPStan\Command\AnalyseCommand', true)) {
$composerAutoloadFile = __DIR__ . '/../vendor/autoload.php';
if (!is_file($composerAutoloadFile)) {
$composerAutoloadFile = __DIR__ . '/../../../autoload.php';
}
$composerAutoloadFile = __DIR__ . '/../vendor/autoload.php';
if (!is_file($composerAutoloadFile)) {
$composerAutoloadFile = __DIR__ . '/../../../autoload.php';
}

require_once($composerAutoloadFile);
require_once($composerAutoloadFile);
}

$application = new \Symfony\Component\Console\Application('PHPStan - PHP Static Analysis Tool');
Expand Down
27 changes: 10 additions & 17 deletions build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
<arg value="--standard=build/ruleset.xml"/>
<arg value="--extensions=php"/>
<arg value="--encoding=utf-8"/>
<arg value="--tab-width=4"/>
<arg value="--ignore=tests/*/data"/>
<arg value="--ignore=tests/*/traits"/>
<arg value="-sp"/>
Expand All @@ -67,7 +66,6 @@
<arg value="--standard=build/ruleset.xml"/>
<arg value="--extensions=php"/>
<arg value="--encoding=utf-8"/>
<arg value="--tab-width=4"/>
<arg value="--ignore=tests/*/data"/>
<arg value="-sp"/>
<arg path="src"/>
Expand All @@ -84,22 +82,11 @@
>
<arg value="-c"/>
<arg value="tests/phpunit.xml"/>
<arg path="tests"/>
<arg path="tests/PHPStan"/>
</exec>
</target>

<target name="phpstan">
<php expression="PHP_VERSION_ID &lt; 70100 ?'true':'false'" returnProperty="isPHP70" level="verbose" />
<php expression="\PHPStan\TestCase::isObsoletePhpParserVersion() ?'.old-php-parser':''" returnProperty="phpParserSuffix" level="verbose" />
<if>
<equals arg1="${isPHP70}" arg2="true" />
<then>
<property name="phpstan.config" value="build/phpstan.php7.0${phpParserSuffix}.neon"/>
</then>
<else>
<property name="phpstan.config" value="build/phpstan${phpParserSuffix}.neon"/>
</else>
</if>
<exec
executable="php"
logoutput="true"
Expand All @@ -108,12 +95,18 @@
>
<arg path="bin/phpstan"/>
<arg value="analyse"/>
<arg value="-c"/>
<arg path="${phpstan.config}"/>
<arg value="-l"/>
<arg value="5"/>
<arg value="--ignore-path"/>
<arg value="tests/*/data*"/>
<arg value="--ignore-path"/>
<arg value="tests/notAutoloaded"/>
<arg value="--ignore-path"/>
<arg value="tests/PHPStan/Analyser/traits"/>
<arg value="--ignore-error"/>
<arg value="PHPUnit_Framework_MockObject_MockObject"/>
<arg path="src"/>
<arg path="tests"/>
<arg path="tests/PHPStan"/>
</exec>
</target>

Expand Down
5 changes: 0 additions & 5 deletions build/ignore-old-php-parser-errors.neon

This file was deleted.

13 changes: 0 additions & 13 deletions build/phpstan.neon

This file was deleted.

3 changes: 0 additions & 3 deletions build/phpstan.old-php-parser.neon

This file was deleted.

9 changes: 0 additions & 9 deletions build/phpstan.php7.0.neon

This file was deleted.

3 changes: 0 additions & 3 deletions build/phpstan.php7.0.old-php-parser.neon

This file was deleted.

28 changes: 4 additions & 24 deletions build/ruleset.xml
Original file line number Diff line number Diff line change
@@ -1,34 +1,14 @@
<?xml version="1.0"?>
<ruleset name="PHPStan">
<rule ref="vendor/consistence/coding-standard/Consistence/ruleset.xml">
<exclude name="Squiz.Functions.GlobalFunction.Found"/>
</rule>
<rule ref="vendor/slevomat/coding-standard/SlevomatCodingStandard/ruleset.xml">
<exclude name="SlevomatCodingStandard.Classes.ClassConstantVisibility.MissingConstantVisibility"/>
<exclude name="SlevomatCodingStandard.Files.TypeNameMatchesFileName"/>
<exclude name="SlevomatCodingStandard.Namespaces.FullyQualifiedClassNameAfterKeyword"/>
<exclude name="SlevomatCodingStandard.Namespaces.UseOnlyWhitelistedNamespaces"/>
<exclude name="SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly"/>
<exclude name="SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingTraversableParameterTypeHintSpecification"/>
<exclude name="SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingTraversableReturnTypeHintSpecification"/>
<exclude name="SlevomatCodingStandard.Namespaces.FullyQualifiedClassNameInAnnotation.NonFullyQualifiedClassName"/>
<exclude name="SlevomatCodingStandard.TypeHints.NullableTypeForNullDefaultValue"/>
</rule>
<rule ref="vendor/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/ruleset.xml"/>
<rule ref="Squiz.PHP.InnerFunctions.NotAllowed">
<exclude-pattern>tests/TestCase.php</exclude-pattern>
<exclude-pattern>tests/PHPStan/Analyser/NodeScopeResolverTest.php</exclude-pattern>
</rule>
<rule ref="SlevomatCodingStandard.TypeHints.TypeHintDeclaration">
<rule ref="Generic.Files.LineLength">
<properties>
<property name="usefulAnnotations" type="array" value="
@dataProvider,
@requires
"/>
<property name="enableNullableTypeHints" type="false" />
<property name="enableVoidTypeHint" type="false" />
<property name="lineLimit" value="512"/>
<property name="absoluteLineLimit" value="0"/>
</properties>
</rule>
<rule ref="Generic.Strings.UnnecessaryStringConcat.Found">
<exclude-pattern>tests/PHPStan/Analyser/NodeScopeResolverTest.php</exclude-pattern>
</rule>
</ruleset>
12 changes: 4 additions & 8 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,18 @@
},
"require": {
"php": "~7.0",
"nette/bootstrap": "^2.4 || ^3.0",
"nette/caching": "^2.4 || ^3.0",
"nette/di": "^2.4 || ^3.0",
"nette/robot-loader": "^2.4.2 || ^3.0",
"nette/utils": "^2.4 || ^3.0",
"nikic/php-parser": "^2.1 || ^3.0.2",
"symfony/console": "~2.7 || ~3.0",
"symfony/finder": "~2.7 || ~3.0"
"symfony/finder": "~2.7 || ~3.0",
"php-di/php-di": "^5.4",
"tedivm/stash": "^0.14.1"
},
"require-dev": {
"consistence/coding-standard": "~0.13.0",
"jakub-onderka/php-parallel-lint": "^0.9",
"satooshi/php-coveralls": "^1.0",
"phing/phing": "^2.16.0",
"phpunit/phpunit": "^6.0.7",
"slevomat/coding-standard": "dev-2.0-dev#2b8e2b0992f31205e4c1d2fb5c39af05274c7c4d"
"squizlabs/php_codesniffer": "^2.8"
},
"autoload": {
"psr-4": {"PHPStan\\": "src/"}
Expand Down