chore(deps): install PHPStan via Composer, drop downloaded PHAR

The downloaded phpstan.phar could not resolve namespaced third-party
packages now living in src/vendor/ (M3uParser, PhpM3u8), failing CI with
class.notFound on StreamService::parseM3U.

- add phpstan/phpstan 2.1.17 as a Composer dev dependency (committed to
  src/vendor/); the vendor/bin/phpstan binary auto-loads
  src/vendor/autoload.php, so vendor symbols resolve
- Makefile: drop the phpstan-install PHAR download; run src/vendor/bin/phpstan
- remove the stale Core/Parsing/M3uParser excludePath from phpstan.dist.neon
- drop the obsolete tools/phpstan/phpstan.phar gitignore entry

make phpstan: No errors (278 files).
This commit is contained in:
Divarion-D
2026-06-25 19:58:38 +03:00
parent 6582b911cb
commit 045b8f6bd0
20 changed files with 987 additions and 23 deletions
+1 -2
View File
@@ -12,7 +12,6 @@ tests/.cache/
# committed and shipped (the deploy path has no Composer). Do not add it here.
.claude/
# Static analysis (PHPStan)
tools/phpstan/phpstan.phar
# Static analysis (PHPStan) — binary ships via committed src/vendor/ (Composer)
.phpstan.cache/
src/composer.lock
+7 -15
View File
@@ -82,32 +82,24 @@ EXCLUDE_ARGS := $(addprefix --exclude=,$(EXCLUDES))
.PHONY: new lb main lb_copy_files main_copy_files set_permissions create_archive \
lb_archive_move main_archive_move main_install_archive clean \
delete_files_list lb_delete_files_list generate_deleted_files syntax_check \
phpstan phpstan-install phpstan-baseline
phpstan phpstan-baseline
# ─── Syntax check ───────────────────────────────────────────────
syntax_check:
@bash ./tools/php_syntax_check.sh
# ─── Static analysis (PHPStan) ──────────────────────────────────
PHPSTAN := tools/phpstan/phpstan.phar
PHPSTAN_VERSION := 2.1.17
# Download the PHPStan PHAR once (no Composer required).
phpstan-install:
@if [ ! -f "$(PHPSTAN)" ]; then \
echo "==> Downloading PHPStan $(PHPSTAN_VERSION)"; \
curl -fSL "https://github.com/phpstan/phpstan/releases/download/$(PHPSTAN_VERSION)/phpstan.phar" -o "$(PHPSTAN)"; \
chmod +x "$(PHPSTAN)"; \
else \
echo "==> PHPStan already present: $(PHPSTAN)"; \
fi
# PHPStan ships as a committed Composer dev dependency (src/vendor/). The
# binary auto-loads src/vendor/autoload.php, so it resolves namespaced
# third-party packages (M3uParser, PhpM3u8). No download, no `composer install`.
PHPSTAN := src/vendor/bin/phpstan
# Run the analysis using phpstan.dist.neon.
phpstan: phpstan-install
phpstan:
@php "$(PHPSTAN)" analyse --memory-limit=2G
# Freeze all current errors into phpstan-baseline.neon (run after a level bump).
phpstan-baseline: phpstan-install
phpstan-baseline:
@php "$(PHPSTAN)" analyse --memory-limit=2G --generate-baseline=phpstan-baseline.neon
# ─── Generate deleted_files.txt from git diff ───────────────────
+3 -3
View File
@@ -47,10 +47,10 @@ parameters:
- src/*/tmp/*
- src/tmp/*
- src/backups/*
# Composer autoloader glue (committed + shipped, generated code).
# Composer autoloader glue + third-party packages (committed +
# shipped). Symbols resolve via src/vendor/autoload.php, which the
# Composer-installed phpstan binary loads automatically.
- src/vendor/*
# Vendored third-party library shipped inside Core
- src/Core/Parsing/M3uParser/*
# View templates: included into a controller's scope, so their
# variables ($rSettings, $language, ...) are injected by the caller.
# PHPStan analyses files standalone and would flag every such var as
+3
View File
@@ -8,6 +8,9 @@
"gemorroj/m3u-parser": "6.0.1",
"chrisyue/php-m3u8": "^4"
},
"require-dev": {
"phpstan/phpstan": "2.1.17"
},
"autoload": {
"psr-4": {
"XcVm\\": "./"
+119
View File
@@ -0,0 +1,119 @@
#!/usr/bin/env php
<?php
/**
* Proxy PHP file generated by Composer
*
* This file includes the referenced bin path (../phpstan/phpstan/phpstan)
* using a stream wrapper to prevent the shebang from being output on PHP<8
*
* @generated
*/
namespace Composer;
$GLOBALS['_composer_bin_dir'] = __DIR__;
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
if (PHP_VERSION_ID < 80000) {
if (!class_exists('Composer\BinProxyWrapper')) {
/**
* @internal
*/
final class BinProxyWrapper
{
private $handle;
private $position;
private $realpath;
public function stream_open($path, $mode, $options, &$opened_path)
{
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
$opened_path = substr($path, 17);
$this->realpath = realpath($opened_path) ?: $opened_path;
$opened_path = $this->realpath;
$this->handle = fopen($this->realpath, $mode);
$this->position = 0;
return (bool) $this->handle;
}
public function stream_read($count)
{
$data = fread($this->handle, $count);
if ($this->position === 0) {
$data = preg_replace('{^#!.*\r?\n}', '', $data);
}
$this->position += strlen($data);
return $data;
}
public function stream_cast($castAs)
{
return $this->handle;
}
public function stream_close()
{
fclose($this->handle);
}
public function stream_lock($operation)
{
return $operation ? flock($this->handle, $operation) : true;
}
public function stream_seek($offset, $whence)
{
if (0 === fseek($this->handle, $offset, $whence)) {
$this->position = ftell($this->handle);
return true;
}
return false;
}
public function stream_tell()
{
return $this->position;
}
public function stream_eof()
{
return feof($this->handle);
}
public function stream_stat()
{
return array();
}
public function stream_set_option($option, $arg1, $arg2)
{
return true;
}
public function url_stat($path, $flags)
{
$path = substr($path, 17);
if (file_exists($path)) {
return stat($path);
}
return false;
}
}
}
if (
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
) {
return include("phpvfscomposer://" . __DIR__ . '/..'.'/phpstan/phpstan/phpstan');
}
}
return include __DIR__ . '/..'.'/phpstan/phpstan/phpstan';
+119
View File
@@ -0,0 +1,119 @@
#!/usr/bin/env php
<?php
/**
* Proxy PHP file generated by Composer
*
* This file includes the referenced bin path (../phpstan/phpstan/phpstan.phar)
* using a stream wrapper to prevent the shebang from being output on PHP<8
*
* @generated
*/
namespace Composer;
$GLOBALS['_composer_bin_dir'] = __DIR__;
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
if (PHP_VERSION_ID < 80000) {
if (!class_exists('Composer\BinProxyWrapper')) {
/**
* @internal
*/
final class BinProxyWrapper
{
private $handle;
private $position;
private $realpath;
public function stream_open($path, $mode, $options, &$opened_path)
{
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
$opened_path = substr($path, 17);
$this->realpath = realpath($opened_path) ?: $opened_path;
$opened_path = $this->realpath;
$this->handle = fopen($this->realpath, $mode);
$this->position = 0;
return (bool) $this->handle;
}
public function stream_read($count)
{
$data = fread($this->handle, $count);
if ($this->position === 0) {
$data = preg_replace('{^#!.*\r?\n}', '', $data);
}
$this->position += strlen($data);
return $data;
}
public function stream_cast($castAs)
{
return $this->handle;
}
public function stream_close()
{
fclose($this->handle);
}
public function stream_lock($operation)
{
return $operation ? flock($this->handle, $operation) : true;
}
public function stream_seek($offset, $whence)
{
if (0 === fseek($this->handle, $offset, $whence)) {
$this->position = ftell($this->handle);
return true;
}
return false;
}
public function stream_tell()
{
return $this->position;
}
public function stream_eof()
{
return feof($this->handle);
}
public function stream_stat()
{
return array();
}
public function stream_set_option($option, $arg1, $arg2)
{
return true;
}
public function url_stat($path, $flags)
{
$path = substr($path, 17);
if (file_exists($path)) {
return stat($path);
}
return false;
}
}
}
if (
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
) {
return include("phpvfscomposer://" . __DIR__ . '/..'.'/phpstan/phpstan/phpstan.phar');
}
}
return include __DIR__ . '/..'.'/phpstan/phpstan/phpstan.phar';
+10
View File
@@ -0,0 +1,10 @@
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'9b38cf48e83f5d8f60375221cd213eee' => $vendorDir . '/phpstan/phpstan/bootstrap.php',
);
+12
View File
@@ -33,6 +33,18 @@ class ComposerAutoloaderInit80ff86aa3df258be188ff24c30fbd1e8
$loader->register(true);
$filesToLoad = \Composer\Autoload\ComposerStaticInit80ff86aa3df258be188ff24c30fbd1e8::$files;
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
require $file;
}
}, null, null);
foreach ($filesToLoad as $fileIdentifier => $file) {
$requireFile($fileIdentifier, $file);
}
return $loader;
}
}
+4
View File
@@ -6,6 +6,10 @@ namespace Composer\Autoload;
class ComposerStaticInit80ff86aa3df258be188ff24c30fbd1e8
{
public static $files = array (
'9b38cf48e83f5d8f60375221cd213eee' => __DIR__ . '/..' . '/phpstan/phpstan/bootstrap.php',
);
public static $prefixLengthsPsr4 = array (
'X' =>
array (
+64 -1
View File
@@ -105,8 +105,71 @@
"source": "https://github.com/Gemorroj/M3uParser/tree/6.0.1"
},
"install-path": "../gemorroj/m3u-parser"
},
{
"name": "phpstan/phpstan",
"version": "2.1.17",
"version_normalized": "2.1.17.0",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "89b5ef665716fa2a52ecd2633f21007a6a349053"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/89b5ef665716fa2a52ecd2633f21007a6a349053",
"reference": "89b5ef665716fa2a52ecd2633f21007a6a349053",
"shasum": ""
},
"require": {
"php": "^7.4|^8.0"
},
"conflict": {
"phpstan/phpstan-shim": "*"
},
"time": "2025-05-21T20:55:28+00:00",
"bin": [
"phpstan",
"phpstan.phar"
],
"type": "library",
"installation-source": "dist",
"autoload": {
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "PHPStan - PHP Static Analysis Tool",
"keywords": [
"dev",
"static analysis"
],
"support": {
"docs": "https://phpstan.org/user-guide/getting-started",
"forum": "https://github.com/phpstan/phpstan/discussions",
"issues": "https://github.com/phpstan/phpstan/issues",
"security": "https://github.com/phpstan/phpstan/security/policy",
"source": "https://github.com/phpstan/phpstan-src"
},
"funding": [
{
"url": "https://github.com/ondrejmirtes",
"type": "github"
},
{
"url": "https://github.com/phpstan",
"type": "github"
}
],
"install-path": "../phpstan/phpstan"
}
],
"dev": true,
"dev-package-names": []
"dev-package-names": [
"phpstan/phpstan"
]
}
+11 -2
View File
@@ -3,7 +3,7 @@
'name' => 'vateron-media/xc-vm',
'pretty_version' => 'dev-main',
'version' => 'dev-main',
'reference' => '605b59d435526586b2b27756fb5644e1f7a2fe34',
'reference' => 'cf3901e0854eb1d20f6d8b2341f7613e93eb1beb',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -28,10 +28,19 @@
'aliases' => array(),
'dev_requirement' => false,
),
'phpstan/phpstan' => array(
'pretty_version' => '2.1.17',
'version' => '2.1.17.0',
'reference' => '89b5ef665716fa2a52ecd2633f21007a6a349053',
'type' => 'library',
'install_path' => __DIR__ . '/../phpstan/phpstan',
'aliases' => array(),
'dev_requirement' => true,
),
'vateron-media/xc-vm' => array(
'pretty_version' => 'dev-main',
'version' => 'dev-main',
'reference' => '605b59d435526586b2b27756fb5644e1f7a2fe34',
'reference' => 'cf3901e0854eb1d20f6d8b2341f7613e93eb1beb',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
+22
View File
@@ -0,0 +1,22 @@
MIT License
Copyright (c) 2016 Ondřej Mirtes
Copyright (c) 2025 PHPStan s.r.o.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+108
View File
@@ -0,0 +1,108 @@
<h1 align="center">PHPStan - PHP Static Analysis Tool</h1>
<p align="center">
<img src="https://i.imgur.com/WaRKPlC.png" alt="PHPStan" width="300" height="300">
</p>
<p align="center">
<a href="https://github.com/phpstan/phpstan/actions"><img src="https://github.com/phpstan/phpstan/workflows/Tests/badge.svg" alt="Build Status"></a>
<a href="https://packagist.org/packages/phpstan/phpstan"><img src="https://poser.pugx.org/phpstan/phpstan/v/stable" alt="Latest Stable Version"></a>
<a href="https://packagist.org/packages/phpstan/phpstan/stats"><img src="https://poser.pugx.org/phpstan/phpstan/downloads" alt="Total Downloads"></a>
<a href="https://choosealicense.com/licenses/mit/"><img src="https://poser.pugx.org/phpstan/phpstan/license" alt="License"></a>
<a href="https://phpstan.org/"><img src="https://img.shields.io/badge/PHPStan-enabled-brightgreen.svg?style=flat" alt="PHPStan Enabled"></a>
</p>
------
PHPStan focuses on finding errors in your code without actually running it. It catches whole classes of bugs
even before you write tests for the code. It moves PHP closer to compiled languages in the sense that the correctness of each line of the code
can be checked before you run the actual line.
**[Read more about PHPStan »](https://phpstan.org/)**
**[Try out PHPStan on the on-line playground! »](https://phpstan.org/try)**
## Sponsors
<a href="https://coders.thecodingmachine.com/phpstan"><img src="website/src/images/sponsor/tcm.png" alt="TheCodingMachine" width="247" height="64"></a>
&nbsp;&nbsp;&nbsp;
<a href="https://packagist.com/?utm_source=phpstan&utm_medium=readme&utm_campaign=sponsorlogo"><img src="website/src/images/sponsor/packagist.png" alt="Private Packagist" width="283" height="64"></a>
<br>
<a href="https://www.cdn77.com/"><img src="website/src/images/sponsor/cdn77.png" alt="CDN77" width="283" height="64"></a>
&nbsp;&nbsp;&nbsp;
<a href="https://blackfire.io/docs/introduction?utm_source=phpstan&utm_medium=github_readme&utm_campaign=logo"><img src="website/src/images/sponsor/blackfire.png" alt="Blackfire.io" width="254" height="64"></a>
<br>
<a href="https://www.iodigital.com/"><img src="website/src/images/sponsor/io.png" alt="iO" width="254" height="65"></a>
&nbsp;&nbsp;&nbsp;
<a href="https://www.fame.fi/"><img src="website/src/images/sponsor/fame.png" alt="Fame Helsinki" width="283" height="64"></a>
<br>
<a href="https://www.startupjobs.cz/startup/shipmonk"><img src="website/src/images/sponsor/shipmonk.jpg" alt="ShipMonk" width="290" height="64"></a>
&nbsp;&nbsp;&nbsp;
<a href="https://togetter.com/"><img src="website/src/images/sponsor/togetter.png" alt="Togetter" width="283" height="64"></a>
<br>
<a href="https://join.rightcapital.com/?utm_source=phpstan&utm_medium=github&utm_campaign=sponsorship"><img src="website/src/images/sponsor/rightcapital.png" alt="RightCapital" width="283" height="64"></a>
&nbsp;&nbsp;&nbsp;
<a href="https://www.contentkingapp.com/?ref=php-developer&utm_source=phpstan&utm_medium=referral&utm_campaign=sponsorship"><img src="website/src/images/sponsor/contentking.png" alt="ContentKing" width="283" height="64"></a>
<br>
<a href="https://zol.fr?utm_source=phpstan"><img src="website/src/images/sponsor/zol.png" alt="ZOL" width="283" height="64"></a>
&nbsp;&nbsp;&nbsp;
<a href="https://www.edgenext.com/"><img src="website/src/images/sponsor/edgenext.png" alt="EdgeNext" width="283" height="64"></a>
<br>
<a href="https://www.shopware.com/en/"><img src="website/src/images/sponsor/shopware.png" alt="Shopware" width="284" height="64"></a>
&nbsp;&nbsp;&nbsp;
<a href="https://craftcms.com/"><img src="website/src/images/sponsor/craftcms.png" alt="Craft CMS" width="283" height="64"></a>
<br>
<a href="https://www.worksome.com/"><img src="website/src/images/sponsor/worksome.png" alt="Worksome" width="283" height="64"></a>
&nbsp;&nbsp;&nbsp;
<a href="https://www.campoint.net/"><img src="website/src/images/sponsor/campoint.png" alt="campoint AG" width="283" height="64"></a>
<br>
<a href="https://www.crisp.nl/"><img src="website/src/images/sponsor/crisp.png" alt="Crisp.nl" width="283" height="64"></a>
&nbsp;&nbsp;&nbsp;
<a href="https://inviqa.com/"><img src="website/src/images/sponsor/inviqa.png" alt="Inviqa" width="254" height="65"></a>
<br>
<a href="https://www.shoptet.cz/"><img src="website/src/images/sponsor/shoptet.png" alt="Shoptet" width="283" height="64"></a>
&nbsp;&nbsp;&nbsp;
<a href="https://route4me.com/"><img src="website/src/images/sponsor/route4me.png" alt="Route4Me: Route Optimizer and Route Planner Software" width="283" height="64"></a>
<br>
<a href="https://werkenbijbelsimpel.nl/en/about-us/"><img src="website/src/images/sponsor/belsimpel.png" alt="Belsimpel" width="284" height="64"></a>
&nbsp;&nbsp;&nbsp;
<a href="https://jobs.ticketswap.com/"><img src="website/src/images/sponsor/ticketswap.png" alt="TicketSwap" width="269" height="64"></a>
[**You can now sponsor my open-source work on PHPStan through GitHub Sponsors.**](https://github.com/sponsors/ondrejmirtes)
Does GitHub already have your 💳? Do you use PHPStan to find 🐛 before they reach production? [Send a couple of 💸 a month my way too.](https://github.com/sponsors/ondrejmirtes) Thank you!
One-time donations [through Revolut.me](https://revolut.me/ondrejmirtes) are also accepted. To request an invoice, [contact me](mailto:ondrej@mirtes.cz) through e-mail.
## Documentation
All the documentation lives on the [phpstan.org website](https://phpstan.org/):
* [Getting Started & User Guide](https://phpstan.org/user-guide/getting-started)
* [Config Reference](https://phpstan.org/config-reference)
* [PHPDocs Basics](https://phpstan.org/writing-php-code/phpdocs-basics) & [PHPDoc Types](https://phpstan.org/writing-php-code/phpdoc-types)
* [Extension Library](https://phpstan.org/user-guide/extension-library)
* [Developing Extensions](https://phpstan.org/developing-extensions/extension-types)
* [API Reference](https://apiref.phpstan.org/)
## PHPStan Pro
PHPStan Pro is a paid add-on on top of open-source PHPStan Static Analysis Tool with these premium features:
* Web UI for browsing found errors, you can click and open your editor of choice on the offending line.
* Continuous analysis (watch mode): scans changed files in the background, refreshes the UI automatically.
Try it on PHPStan 0.12.45 or later by running it with the `--pro` option. You can create an account either by following the on-screen instructions, or by visiting [account.phpstan.com](https://account.phpstan.com/).
After 30-day free trial period it costs 7 EUR for individuals monthly, 70 EUR for teams (up to 25 members). By paying for PHPStan Pro, you're supporting the development of open-source PHPStan.
You can read more about it on [PHPStan's website](https://phpstan.org/blog/introducing-phpstan-pro).
## Code of Conduct
This project adheres to a [Contributor Code of Conduct](https://github.com/phpstan/phpstan/blob/master/CODE_OF_CONDUCT.md). By participating in this project and its community, you are expected to uphold this code.
## Contributing
Any contributions are welcome. PHPStan's source code open to pull requests lives at [`phpstan/phpstan-src`](https://github.com/phpstan/phpstan-src).
+338
View File
@@ -0,0 +1,338 @@
Upgrading from PHPStan 1.x to 2.0
=================================
## PHP version requirements
PHPStan now requires PHP 7.4 or newer to run.
## Upgrading guide for end users
The best way to get ready for upgrade to PHPStan 2.0 is to update to the **latest PHPStan 1.12 release**
and enable [**Bleeding Edge**](https://phpstan.org/blog/what-is-bleeding-edge). This will enable the new rules and behaviours that 2.0 turns on for all users.
Also make sure to install and enable [`phpstan/phpstan-deprecation-rules`](https://github.com/phpstan/phpstan-deprecation-rules).
Once you get to a green build with no deprecations showed on latest PHPStan 1.12.x with Bleeding Edge enabled, you can update all your related PHPStan dependencies to 2.0 in `composer.json`:
```json
"require-dev": {
"phpstan/phpstan": "^2.0",
"phpstan/phpstan-deprecation-rules": "^2.0",
"phpstan/phpstan-doctrine": "^2.0",
"phpstan/phpstan-nette": "^2.0",
"phpstan/phpstan-phpunit": "^2.0",
"phpstan/phpstan-strict-rules": "^2.0",
"phpstan/phpstan-symfony": "^2.0",
"phpstan/phpstan-webmozart-assert": "^2.0",
...
}
```
Don't forget to update [3rd party PHPStan extensions](https://phpstan.org/user-guide/extension-library) as well.
After changing your `composer.json`, run `composer update 'phpstan/*' -W`.
It's up to you whether you go through the new reported errors or if you just put them all to the [baseline](https://phpstan.org/user-guide/baseline) ;) Everyone who's on PHPStan 1.12 should be able to upgrade to PHPStan 2.0.
### Noteworthy changes to code analysis
* [**Enhancements in handling parameters passed by reference**](https://phpstan.org/blog/enhancements-in-handling-parameters-passed-by-reference)
* [**Validate inline PHPDoc `@var` tag type**](https://phpstan.org/blog/phpstan-1-10-comes-with-lie-detector#validate-inline-phpdoc-%40var-tag-type)
* [**List type enforced**](https://phpstan.org/blog/phpstan-1-9-0-with-phpdoc-asserts-list-type#list-type)
* **Always `true` conditions always reported**: previously reported only with phpstan-strict-rules, this is now always reported.
### Removed option `checkMissingIterableValueType`
It's strongly recommended to add the missing array typehints.
If you want to continue ignoring missing typehints from arrays, add `missingType.iterableValue` error identifier to your `ignoreErrors`:
```neon
parameters:
ignoreErrors:
-
identifier: missingType.iterableValue
```
### Removed option `checkGenericClassInNonGenericObjectType`
It's strongly recommended to add the missing generic typehints.
If you want to continue ignoring missing typehints from generics, add `missingType.generics` error identifier to your `ignoreErrors`:
```neon
parameters:
ignoreErrors:
-
identifier: missingType.generics
```
### Removed `checkAlwaysTrue*` options
These options have been removed because PHPStan now always behaves as if these were set to `true`:
* `checkAlwaysTrueCheckTypeFunctionCall`
* `checkAlwaysTrueInstanceof`
* `checkAlwaysTrueStrictComparison`
* `checkAlwaysTrueLooseComparison`
### Removed option `excludes_analyse`
It has been replaced with [`excludePaths`](https://phpstan.org/user-guide/ignoring-errors#excluding-whole-files).
### Paths in `excludePaths` and `ignoreErrors` have to be a valid file path or a fnmatch pattern
If you are excluding a file path that might not exist but you still want to have it in `excludePaths`, append `(?)`:
```neon
parameters:
excludePaths:
- tests/*/data/*
- src/broken
- node_modules (?) # optional path, might not exist
```
If you have the same situation in `ignoreErrors` (ignoring an error in a path that might not exist), use `reportUnmatchedIgnoredErrors: false`.
```neon
parameters:
reportUnmatchedIgnoredErrors: false
```
Appending `(?)` in `ignoreErrors` is not supported.
### Changes in 1st party PHPStan extensions
* [phpstan-doctrine](https://github.com/phpstan/phpstan-doctrine)
* Removed config parameter `searchOtherMethodsForQueryBuilderBeginning` (extension now behaves as when this was set to `true`)
* Removed config parameter `queryBuilderFastAlgorithm` (extension now behaves as when this was set to `false`)
* [phpstan-symfony](https://github.com/phpstan/phpstan-symfony)
* Removed legacy options with `_` in the name
* `container_xml_path` -> use `containerXmlPath`
* `constant_hassers` -> use `constantHassers`
* `console_application_loader` -> use `consoleApplicationLoader`
### Minor backward compatibility breaks
* Removed unused config parameter `cache.nodesByFileCountMax`
* Removed unused config parameter `memoryLimitFile`
* Removed unused feature toggle `disableRuntimeReflectionProvider`
* Removed unused config parameter `staticReflectionClassNamePatterns`
* Remove `fixerTmpDir` config parameter, use `pro.tmpDir` instead
* Remove `tempResultCachePath` config parameter, use `resultCachePath` instead
* `additionalConfigFiles` config parameter must be a list
## Upgrading guide for extension developers
> [!NOTE]
> Please switch to PHPStan 2.0 in a new major version of your extension. It's not feasible to try to support both PHPStan 1.x and PHPStan 2.x with the same extension code.
>
> You can definitely get closer to supporting PHPStan 2.0 without increasing major version by solving reported deprecations and other issues by analysing your extension code with PHPStan & phpstan-deprecation-rules & Bleeding Edge, but the final leap and solving backward incompatibilities should be done by requiring `"phpstan/phpstan": "^2.0"` in your `composer.json`, and releasing a new major version.
### PHPStan now uses nikic/php-parser v5
See [UPGRADING](https://github.com/nikic/PHP-Parser/blob/master/UPGRADE-5.0.md) guide for PHP-Parser.
The most notable change is how `throw` statement is represented. Previously, `throw` statements like `throw $e;` were represented using the `Stmt\Throw_` class, while uses inside other expressions (such as `$x ?? throw $e`) used the `Expr\Throw_` class.
Now, `throw $e;` is represented as a `Stmt\Expression` that contains an `Expr\Throw_`. The
`Stmt\Throw_` class has been removed.
### PHPStan now uses phpstan/phpdoc-parser v2
See [UPGRADING](https://github.com/phpstan/phpdoc-parser/blob/2.0.x/UPGRADING.md) guide for phpstan/phpdoc-parser.
### Returning plain strings as errors no longer supported, use RuleErrorBuilder
Identifiers are also required in custom rules.
Learn more: [Using RuleErrorBuilder to enrich reported errors in custom rules](https://phpstan.org/blog/using-rule-error-builder)
**Before**:
```php
return ['My error'];
```
**After**:
```php
return [
RuleErrorBuilder::message('My error')
->identifier('my.error')
->build(),
];
```
### Deprecate various `instanceof *Type` in favour of new methods on `Type` interface
Learn more: [Why Is instanceof *Type Wrong and Getting Deprecated?](https://phpstan.org/blog/why-is-instanceof-type-wrong-and-getting-deprecated)
### Removed deprecated `ParametersAcceptorSelector::selectSingle()`
Use [`ParametersAcceptorSelector::selectFromArgs()`](https://apiref.phpstan.org/2.0.x/PHPStan.Reflection.ParametersAcceptorSelector.html#_selectFromArgs) instead. It should be used in most places where `selectSingle()` was previously used, like dynamic return type extensions.
**Before**:
```php
$defaultReturnType = ParametersAcceptorSelector::selectSingle($functionReflection->getVariants())->getReturnType();
```
**After**:
```php
$defaultReturnType = ParametersAcceptorSelector::selectFromArgs(
$scope,
$functionCall->getArgs(),
$functionReflection->getVariants()
)->getReturnType();
```
If you're analysing function or method body itself and you're using one of the following methods, ask for `getParameters()` and `getReturnType()` directly on the reflection object:
* [InClassMethodNode::getMethodReflection()](https://apiref.phpstan.org/2.0.x/PHPStan.Node.InClassMethodNode.html)
* [InFunctionNode::getFunctionReflection()](https://apiref.phpstan.org/2.0.x/PHPStan.Node.InFunctionNode.html)
* [FunctionReturnStatementsNode::getFunctionReflection()](https://apiref.phpstan.org/2.0.x/PHPStan.Node.FunctionReturnStatementsNode.html)
* [MethodReturnStatementsNode::getMethodReflection()](https://apiref.phpstan.org/2.0.x/PHPStan.Node.MethodReturnStatementsNode.html)
* [Scope::getFunction()](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.Scope.html#_getFunction)
**Before**:
```php
$function = $node->getFunctionReflection();
$returnType = ParametersAcceptorSelector::selectSingle($function->getVariants())->getReturnType();
```
**After**:
```php
$returnType = $node->getFunctionReflection()->getReturnType();
```
### Changed `TypeSpecifier::create()` and `SpecifiedTypes` constructor parameters
[`PHPStan\Analyser\TypeSpecifier::create()`](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.TypeSpecifier.html#_create) now accepts (all parameters are required):
* `Expr $expr`
* `Type $type`
* `TypeSpecifierContext $context`
* `Scope $scope`
If you want to change `$overwrite` or `$rootExpr` (previous parameters also used to be accepted by this method), call `setAlwaysOverwriteTypes()` and `setRootExpr()` on [`SpecifiedTypes`](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.SpecifiedTypes.html) (object returned by `TypeSpecifier::create()`). These methods return a new object (SpecifiedTypes is immutable).
[`SpecifiedTypes`](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.SpecifiedTypes.html) constructor now accepts:
* `array $sureTypes`
* `array $sureNotTypes`
If you want to change `$overwrite` or `$rootExpr` (previous parameters also used to be accepted by the constructor), call `setAlwaysOverwriteTypes()` and `setRootExpr()`. These methods return a new object (SpecifiedTypes is immutable).
### `ConstantArrayType` no longer extends `ArrayType`
`Type::getArrays()` now returns `list<ArrayType|ConstantArrayType>`.
Using `$type instanceof ArrayType` is [being deprecated anyway](https://phpstan.org/blog/why-is-instanceof-type-wrong-and-getting-deprecated) so the impact of this change should be minimal.
### Changed `TypeSpecifier::specifyTypesInCondition()`
This method no longer accepts `Expr $rootExpr`. If you want to change it, call `setRootExpr()` on [`SpecifiedTypes`](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.SpecifiedTypes.html) (object returned by `TypeSpecifier::specifyTypesInCondition()`). `setRootExpr()` method returns a new object (SpecifiedTypes is immutable).
### Node attributes `parent`, `previous`, `next` are no longer available
Learn more: https://phpstan.org/blog/preprocessing-ast-for-custom-rules
### Removed config parameter `scopeClass`
As a replacement you can implement [`PHPStan\Type\ExpressionTypeResolverExtension`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.ExpressionTypeResolverExtension.html) interface instead and register it as a service.
### Removed `PHPStan\Broker\Broker`
Use [`PHPStan\Reflection\ReflectionProvider`](https://apiref.phpstan.org/2.0.x/PHPStan.Reflection.ReflectionProvider.html) instead.
`BrokerAwareExtension` was also removed. Ask for `ReflectionProvider` in the extension constructor instead.
Instead of `PHPStanTestCase::createBroker()`, call `PHPStanTestCase::createReflectionProvider()`.
### List type is enabled for everyone
Removed static methods from `AccessoryArrayListType` class:
* `isListTypeEnabled()`
* `setListTypeEnabled()`
* `intersectWith()`
Instead of `AccessoryArrayListType::intersectWith($type)`, do `TypeCombinator::intersect($type, new AccessoryArrayListType())`.
### Minor backward compatibility breaks
* Classes that were previously `@final` were made `final`
* Parameter `$callableParameters` of [`MutatingScope::enterAnonymousFunction()`](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.MutatingScope.html#_enterAnonymousFunction) and [`enterArrowFunction()`](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.MutatingScope.html#_enterArrowFunction) made required
* Parameter `StatementContext $context` of [`NodeScopeResolver::processStmtNodes()`](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.NodeScopeResolver.html#_processStmtNodes) made required
* ClassPropertiesNode - remove `$extensions` parameter from [`getUninitializedProperties()`](https://apiref.phpstan.org/2.0.x/PHPStan.Node.ClassPropertiesNode.html#_getUninitializedProperties)
* `Type::getSmallerType()`, `Type::getSmallerOrEqualType()`, `Type::getGreaterType()`, `Type::getGreaterOrEqualType()`, `Type::isSmallerThan()`, `Type::isSmallerThanOrEqual()` now require [`PhpVersion`](https://apiref.phpstan.org/2.0.x/PHPStan.Php.PhpVersion.html) as argument.
* `CompoundType::isGreaterThan()`, `CompoundType::isGreaterThanOrEqual()` now require [`PhpVersion`](https://apiref.phpstan.org/2.0.x/PHPStan.Php.PhpVersion.html) as argument.
* Removed `ReflectionProvider::supportsAnonymousClasses()` (all reflection providers support anonymous classes)
* Remove `ArrayType::generalizeKeys()`
* Remove `ArrayType::count()`, use `Type::getArraySize()` instead
* Remove `ArrayType::castToArrayKeyType()`, `Type::toArrayKey()` instead
* Remove `UnionType::pickTypes()`, use `pickFromTypes()` instead
* Remove `RegexArrayShapeMatcher::matchType()`, use `matchExpr()` instead
* Remove unused `PHPStanTestCase::$useStaticReflectionProvider`
* Remove `PHPStanTestCase::getReflectors()`, use `getReflector()` instead
* Remove `ClassReflection::getFileNameWithPhpDocs()`, use `getFileName()` instead
* Remove `AnalysisResult::getInternalErrors()`, use `getInternalErrorObjects()` instead
* Remove `ConstantReflection::getValue()`, use `getValueExpr()` instead. To get `Type` from `Expr`, use `Scope::getType()` or `InitializerExprTypeResolver::getType()`
* Remove `PropertyTag::getType()`, use `getReadableType()` / `getWritableType()` instead
* Remove `GenericTypeVariableResolver`, use [`Type::getTemplateType()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getTemplateType) instead
* Rename `Type::isClassStringType()` to `Type::isClassString()`
* Remove `Scope::isSpecified()`, use `hasExpressionType()` instead
* Remove `ConstantArrayType::isEmpty()`, use `isIterableAtLeastOnce()->no()` instead
* Remove `ConstantArrayType::getNextAutoIndex()`
* Removed methods from `ConstantArrayType` - `getFirst*Type` and `getLast*Type`
* Use `getFirstIterable*Type` and `getLastIterable*Type` instead
* Remove `ConstantArrayType::generalizeToArray()`
* Remove `ConstantArrayType::findTypeAndMethodName()`, use `findTypeAndMethodNames()` instead
* Remove `ConstantArrayType::removeLast()`, use [`Type::popArray()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_popArray) instead
* Remove `ConstantArrayType::removeFirst()`, use [`Type::shiftArray()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_shiftArray) instead
* Remove `ConstantArrayType::reverse()`, use [`Type::reverseArray()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_reverseArray) instead
* Remove `ConstantArrayType::chunk()`, use [`Type::chunkArray()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_chunkArray) instead
* Remove `ConstantArrayType::slice()`, use [`Type::sliceArray()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_sliceArray) instead
* Made `TypeUtils` thinner by removing methods:
* Remove `TypeUtils::getArrays()` and `getAnyArrays()`, use [`Type::getArrays()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getArrays) instead
* Remove `TypeUtils::getConstantArrays()` and `getOldConstantArrays()`, use [`Type::getConstantArrays()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getConstantArrays) instead
* Remove `TypeUtils::getConstantStrings()`, use [`Type::getConstantStrings()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getConstantStrings) instead
* Remove `TypeUtils::getConstantTypes()` and `getAnyConstantTypes()`, use [`Type::isConstantValue()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_isConstantValue) or [`Type::generalize()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_generalize)
* Remove `TypeUtils::generalizeType()`, use [`Type::generalize()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_generalize) instead
* Remove `TypeUtils::getDirectClassNames()`, use [`Type::getObjectClassNames()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getObjectClassNames) instead
* Remove `TypeUtils::getConstantScalars()`, use [`Type::isConstantScalarValue()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_isConstantScalarValue) or [`Type::getConstantScalarTypes()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getConstantScalarTypes) instead
* Remove `TypeUtils::getEnumCaseObjects()`, use [`Type::getEnumCases()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getEnumCases) instead
* Remove `TypeUtils::containsCallable()`, use [`Type::isCallable()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_isCallable) instead
* Removed `Scope::doNotTreatPhpDocTypesAsCertain()`, use `getNativeType()` instead
* Parameter `$isList` in `ConstantArrayType` constructor can only be `TrinaryLogic`, no longer `bool`
* Parameter `$nextAutoIndexes` in `ConstantArrayType` constructor can only be `non-empty-list<int>`, no longer `int`
* Remove `ConstantType` interface, use [`Type::isConstantValue()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_isConstantValue) instead
* `acceptsNamedArguments()` in `FunctionReflection`, `ExtendedMethodReflection` and `CallableParametersAcceptor` interfaces returns `TrinaryLogic` instead of `bool`
* Remove `FunctionReflection::isFinal()`
* [`Type::getProperty()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getProperty) now returns [`ExtendedPropertyReflection`](https://apiref.phpstan.org/2.0.x/PHPStan.Reflection.ExtendedPropertyReflection.html)
* Remove `__set_state()` on objects that should not be serialized in cache
* Parameter `$selfClass` of [`TypehintHelper::decideTypeFromReflection()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.TypehintHelper.html#_decideTypeFromReflection) no longer accepts `string`
* `LevelsTestCase::dataTopics()` data provider made static
* `PHPStan\Node\Printer\Printer` no longer autowired as `PhpParser\PrettyPrinter\Standard`, use `PHPStan\Node\Printer\Printer` in the typehint
* Remove `Type::acceptsWithReason()`, `Type:accepts()` return type changed from `TrinaryLogic` to [`AcceptsResult`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.AcceptsResult.html)
* Remove `CompoundType::isAcceptedWithReasonBy()`, `CompoundType::isAcceptedBy()` return type changed from `TrinaryLogic` to [`AcceptsResult`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.AcceptsResult.html)
Remove `Type::isSuperTypeOfWithReason()`, `Type:isSuperTypeOf()` return type changed from `TrinaryLogic` to [`IsSuperTypeOfResult`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.IsSuperTypeOfResult.html)
* Remove `CompoundType::isSubTypeOfWithReasonBy()`, `CompoundType::isSubTypeOf()` return type changed from `TrinaryLogic` to [`IsSuperTypeOfResult`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.IsSuperTypeOfResult.html)
* Remove `TemplateType::isValidVarianceWithReason()`, changed `TemplateType::isValidVariance()` return type to [`IsSuperTypeOfResult`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.IsSuperTypeOfResult.html)
* `RuleLevelHelper::accepts()` return type changed from `bool` to [`RuleLevelHelperAcceptsResult`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.AcceptsResult.html)
* Changes around `ClassConstantReflection`
* Class `ClassConstantReflection` removed from BC promise, renamed to `RealClassConstantReflection`
* Interface `ConstantReflection` renamed to `ClassConstantReflection`
* Added more methods around PHPDoc types and native types to the (new) `ClassConstantReflection`
* Interface `GlobalConstantReflection` renamed to `ConstantReflection`
* Renamed interfaces and classes from `*WithPhpDocs` to `Extended*`
* `ParametersAcceptorWithPhpDocs` -> `ExtendedParametersAcceptor`
* `ParameterReflectionWithPhpDocs` -> `ExtendedParameterReflection`
* `FunctionVariantWithPhpDocs` -> `ExtendedFunctionVariant`
* `ClassPropertyNode::getNativeType()` return type changed from AST node to `Type|null`
* Class `PHPStan\Node\ClassMethod` (accessible from `ClassMethodsNode`) is no longer an AST node
* Call `PHPStan\Node\ClassMethod::getNode()` to access the original AST node
+114
View File
@@ -0,0 +1,114 @@
<?php declare(strict_types = 1);
namespace PHPStan;
use Composer\Autoload\ClassLoader;
use function class_exists;
use const PHP_VERSION_ID;
final class PharAutoloader
{
/** @var ClassLoader */
private static $composerAutoloader;
/** @var bool */
private static $polyfillsLoaded = false;
final public static function loadClass(string $class): void {
if (!extension_loaded('phar') || defined('__PHPSTAN_RUNNING__')) {
return;
}
if (strpos($class, '_PHPStan_') === 0) {
if (!in_array('phar', stream_get_wrappers(), true)) {
throw new \Exception('Phar wrapper is not registered. Please review your php.ini settings.');
}
if (self::$composerAutoloader === null) {
self::$composerAutoloader = require 'phar://' . __DIR__ . '/phpstan.phar/vendor/autoload.php';
require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/jetbrains/phpstorm-stubs/PhpStormStubsMap.php';
require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/react/async/src/functions_include.php';
require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/react/promise/src/functions_include.php';
}
self::$composerAutoloader->loadClass($class);
return;
}
if (strpos($class, 'PHPStan\\') !== 0 || strpos($class, 'PHPStan\\PhpDocParser\\') === 0) {
return;
}
if (!in_array('phar', stream_get_wrappers(), true)) {
throw new \Exception('Phar wrapper is not registered. Please review your php.ini settings.');
}
if (!self::$polyfillsLoaded) {
self::$polyfillsLoaded = true;
if (
PHP_VERSION_ID < 80000
&& empty($GLOBALS['__composer_autoload_files']['a4a119a56e50fbb293281d9a48007e0e'])
&& !class_exists(\Symfony\Polyfill\Php80\Php80::class, false)
) {
$GLOBALS['__composer_autoload_files']['a4a119a56e50fbb293281d9a48007e0e'] = true;
require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-php80/Php80.php';
require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-php80/bootstrap.php';
}
if (
empty($GLOBALS['__composer_autoload_files']['0e6d7bf4a5811bfa5cf40c5ccd6fae6a'])
&& !class_exists(\Symfony\Polyfill\Mbstring\Mbstring::class, false)
) {
$GLOBALS['__composer_autoload_files']['0e6d7bf4a5811bfa5cf40c5ccd6fae6a'] = true;
require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-mbstring/Mbstring.php';
require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-mbstring/bootstrap.php';
}
if (
empty($GLOBALS['__composer_autoload_files']['e69f7f6ee287b969198c3c9d6777bd38'])
&& !class_exists(\Symfony\Polyfill\Intl\Normalizer\Normalizer::class, false)
) {
$GLOBALS['__composer_autoload_files']['e69f7f6ee287b969198c3c9d6777bd38'] = true;
require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-intl-normalizer/Normalizer.php';
require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-intl-normalizer/bootstrap.php';
}
if (
!extension_loaded('intl')
&& empty($GLOBALS['__composer_autoload_files']['8825ede83f2f289127722d4e842cf7e8'])
&& !class_exists(\Symfony\Polyfill\Intl\Grapheme\Grapheme::class, false)
) {
$GLOBALS['__composer_autoload_files']['8825ede83f2f289127722d4e842cf7e8'] = true;
require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-intl-grapheme/Grapheme.php';
require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-intl-grapheme/bootstrap.php';
}
if (
PHP_VERSION_ID < 80100
&& empty ($GLOBALS['__composer_autoload_files']['23c18046f52bef3eea034657bafda50f'])
&& !class_exists(\Symfony\Polyfill\Php81\Php81::class, false)
) {
$GLOBALS['__composer_autoload_files']['23c18046f52bef3eea034657bafda50f'] = true;
require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-php81/Php81.php';
require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-php81/bootstrap.php';
}
}
$filename = str_replace('\\', DIRECTORY_SEPARATOR, $class);
if (strpos($class, 'PHPStan\\BetterReflection\\') === 0) {
$filename = substr($filename, strlen('PHPStan\\BetterReflection\\'));
$filepath = 'phar://' . __DIR__ . '/phpstan.phar/vendor/ondrejmirtes/better-reflection/src/' . $filename . '.php';
} else {
$filename = substr($filename, strlen('PHPStan\\'));
$filepath = 'phar://' . __DIR__ . '/phpstan.phar/src/' . $filename . '.php';
}
if (!file_exists($filepath)) {
return;
}
require $filepath;
}
}
spl_autoload_register([PharAutoloader::class, 'loadClass']);
+26
View File
@@ -0,0 +1,26 @@
{
"name": "phpstan/phpstan",
"description": "PHPStan - PHP Static Analysis Tool",
"license": ["MIT"],
"keywords": ["dev", "static analysis"],
"require": {
"php": "^7.4|^8.0"
},
"conflict": {
"phpstan/phpstan-shim": "*"
},
"bin": [
"phpstan",
"phpstan.phar"
],
"autoload": {
"files": ["bootstrap.php"]
},
"support": {
"issues": "https://github.com/phpstan/phpstan/issues",
"forum": "https://github.com/phpstan/phpstan/discussions",
"source": "https://github.com/phpstan/phpstan-src",
"docs": "https://phpstan.org/user-guide/getting-started",
"security": "https://github.com/phpstan/phpstan/security/policy"
}
}
+2
View File
@@ -0,0 +1,2 @@
includes:
- phar://phpstan.phar/conf/bleedingEdge.neon
+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/env php
<?php
declare (strict_types=1);
Phar::loadPhar(__DIR__ . '/phpstan.phar', 'phpstan.phar');
require 'phar://phpstan.phar/bin/phpstan';
Binary file not shown.
+16
View File
@@ -0,0 +1,16 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEynwsejDI6OEnSoR2UcZzBf/C5cAFAmguPZUACgkQUcZzBf/C
5cAEvA//ZhuFf/BKaChoEylgToqYpo7SXpIR0UBkEKCTw5TYgFQC1vTBcIL6tbFC
mHiemXmbkFeCGPVnaThFPf4yav5A5NH62VXMXv74F3g+pvB2Z7pHMRjBTleiP6Mr
isnynMK1+/oN69dAeRnxuoJ2ohYLgChbVcfkpSPjz0AqLyFkrgRmWop2BnW4oI6T
dSWIJjO1N465FHESbrm7d/MlpturoC3jADMibpafeOeAN4PerElJrOocGKZctkS2
gVRQAPud3s8Rud3GL9sMcfqnlbNCx4iar/30W15XOOL8OxWBocVIrvYLXjpqKMJx
3GQL1Y3g9NNjjQK3i8cMX2XmpIVXT7GNq1dYr5MyJ6uMtQDR61qEUf7GlMBfvzT0
0SwuyqHcuIQV9KO10u/IBcJ0mdUQm4oDBSiUQk1dKawRVcExx8j5v1OfjzEpfPYj
jdTEtvVcB2TudeKAnQ8hHf6vhCLQtxDHUV03KrkFaF5PsWG3eQwCbWczjJLEE+Th
xQLVtD0iLGU+nivRZg37xqSvgS2nBnilAxrnrVDXU5xYcVqMz2e8mw6aDNYQADDX
P7Znr5rw1rUwDw82vLdssLdt06H2P9F9ZuOi+bxh9+o4BHpXy08TzPAt64is3mKn
pLH0SmR5AUwxCGMVLLKHlxPe/E3xcIQDIik8NvcqFW5FeaYUeek=
=7S+6
-----END PGP SIGNATURE-----