mirror of
https://github.com/Vateron-Media/XC_VM.git
synced 2026-10-29 11:03:20 +01:00
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:
+1
-2
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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\\": "./"
|
||||
|
||||
Vendored
+119
@@ -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';
|
||||
Vendored
+119
@@ -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
@@ -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
@@ -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
@@ -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 (
|
||||
|
||||
Vendored
+64
-1
@@ -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"
|
||||
]
|
||||
}
|
||||
|
||||
Vendored
+11
-2
@@ -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(),
|
||||
|
||||
Vendored
+22
@@ -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.
|
||||
Vendored
+108
@@ -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>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<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
@@ -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
@@ -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
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
includes:
|
||||
- phar://phpstan.phar/conf/bleedingEdge.neon
|
||||
Vendored
+8
@@ -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';
|
||||
BIN
Binary file not shown.
+16
@@ -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-----
|
||||
Reference in New Issue
Block a user