Compare commits

..

4 Commits

Author SHA1 Message Date
Clemens Schwaighofer
4f2ac2ed1b Change Logging class / method name and Debug Support for backtrace
Debug Support:
getCallerClass now returns level 1 class from the trace like the
getCallerMethod. There is also a new getCallerClassMethod that returns
namespace\class->method (or :: for static).

getCallerTopLevelClass works like getCallerClass did before and returns
the TOP level (first entry on the call stack that has a set class name)

Logging:
Do not use the Support getCallerClass/Method/File but call it inside
and use level 2 in trace to get the data we need For the last call
before debug call
Also update the strack trace for the debug call to use ->/:: for method
type
2023-08-22 13:28:59 +09:00
Clemens Schwaighofer
5b8e4e4e3e Core composer packages update 2023-08-22 13:04:19 +09:00
Clemens Schwaighofer
53192da571 www folder composer updates 2023-08-22 13:04:01 +09:00
Clemens Schwaighofer
f29e915068 class_test fixes for phpstan checks 2023-08-02 16:32:11 +09:00
279 changed files with 5377 additions and 4182 deletions

View File

@@ -562,10 +562,10 @@ final class CoreLibsDebugSupportTest extends TestCase
} }
/** /**
* Undocumented function * test the lowest one (one above base)
* *
* @cover ::getCallerClass * @cover ::getCallerClass
* @testWith ["PHPUnit\\TextUI\\Command"] * @testWith ["tests\\CoreLibsDebugSupportTest"]
* @testdox getCallerClass check if it returns $expected [$_dataName] * @testdox getCallerClass check if it returns $expected [$_dataName]
* *
* @return void * @return void
@@ -578,6 +578,40 @@ final class CoreLibsDebugSupportTest extends TestCase
); );
} }
/**
* test highest return (top level)
*
* @cover ::getCallerTopLevelClass
* @testWith ["PHPUnit\\TextUI\\Command"]
* @testdox getCallerTopLevelClass check if it returns $expected [$_dataName]
*
* @return void
*/
public function testGetCallerTopLevelClass(string $expected): void
{
$this->assertEquals(
$expected,
Support::getCallerTopLevelClass()
);
}
/**
* test highest return (top level)
*
* @cover ::getCallerClassMethod
* @testWith ["tests\\CoreLibsDebugSupportTest->testGetCallerClassMethod"]
* @testdox getCallerClassMethod check if it returns $expected [$_dataName]
*
* @return void
*/
public function testGetCallerClassMethod(string $expected): void
{
$this->assertEquals(
$expected,
Support::getCallerClassMethod()
);
}
/** /**
* Undocumented function * Undocumented function
* *

View File

@@ -22,7 +22,7 @@ final class CoreLibsLoggingLoggingTest extends TestCase
. "\[[\w\.]+(:\d+)?\]\s{1}" // host:port . "\[[\w\.]+(:\d+)?\]\s{1}" // host:port
. "\[[\w\-\.\/]+:\d+\]\s{1}" // folder/file . "\[[\w\-\.\/]+:\d+\]\s{1}" // folder/file
. "\[\w+\]\s{1}" // run id . "\[\w+\]\s{1}" // run id
. "{[\w\\\\]+(::\w+)?}\s{1}"; // class . "{[\w\\\\]+((::|->)\w+)?}\s{1}"; // class
public static function tearDownAfterClass(): void public static function tearDownAfterClass(): void
{ {

75
composer.lock generated
View File

@@ -786,16 +786,16 @@
}, },
{ {
"name": "nikic/php-parser", "name": "nikic/php-parser",
"version": "v4.16.0", "version": "v4.17.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nikic/PHP-Parser.git", "url": "https://github.com/nikic/PHP-Parser.git",
"reference": "19526a33fb561ef417e822e85f08a00db4059c17" "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/19526a33fb561ef417e822e85f08a00db4059c17", "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
"reference": "19526a33fb561ef417e822e85f08a00db4059c17", "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -836,9 +836,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/nikic/PHP-Parser/issues", "issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.16.0" "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1"
}, },
"time": "2023-06-25T14:52:30+00:00" "time": "2023-08-13T19:53:39+00:00"
}, },
{ {
"name": "phan/phan", "name": "phan/phan",
@@ -1031,16 +1031,16 @@
}, },
{ {
"name": "phpdocumentor/type-resolver", "name": "phpdocumentor/type-resolver",
"version": "1.7.2", "version": "1.7.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git", "url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "b2fe4d22a5426f38e014855322200b97b5362c0d" "reference": "3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b2fe4d22a5426f38e014855322200b97b5362c0d", "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419",
"reference": "b2fe4d22a5426f38e014855322200b97b5362c0d", "reference": "3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1083,9 +1083,9 @@
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": { "support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues", "issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.2" "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.3"
}, },
"time": "2023-05-30T18:13:47+00:00" "time": "2023-08-12T11:01:26+00:00"
}, },
{ {
"name": "phpstan/extension-installer", "name": "phpstan/extension-installer",
@@ -1133,16 +1133,16 @@
}, },
{ {
"name": "phpstan/phpdoc-parser", "name": "phpstan/phpdoc-parser",
"version": "1.23.0", "version": "1.23.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git", "url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "a2b24135c35852b348894320d47b3902a94bc494" "reference": "846ae76eef31c6d7790fac9bc399ecee45160b26"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/a2b24135c35852b348894320d47b3902a94bc494", "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/846ae76eef31c6d7790fac9bc399ecee45160b26",
"reference": "a2b24135c35852b348894320d47b3902a94bc494", "reference": "846ae76eef31c6d7790fac9bc399ecee45160b26",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1174,22 +1174,22 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types", "description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": { "support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues", "issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.23.0" "source": "https://github.com/phpstan/phpdoc-parser/tree/1.23.1"
}, },
"time": "2023-07-23T22:17:56+00:00" "time": "2023-08-03T16:32:59+00:00"
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "1.10.26", "version": "1.10.29",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "5d660cbb7e1b89253a47147ae44044f49832351f" "reference": "ee5d8f2d3977fb09e55603eee6fb53bdd76ee9c1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/5d660cbb7e1b89253a47147ae44044f49832351f", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ee5d8f2d3977fb09e55603eee6fb53bdd76ee9c1",
"reference": "5d660cbb7e1b89253a47147ae44044f49832351f", "reference": "ee5d8f2d3977fb09e55603eee6fb53bdd76ee9c1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1238,25 +1238,25 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-07-19T12:44:37+00:00" "time": "2023-08-14T13:24:11+00:00"
}, },
{ {
"name": "phpstan/phpstan-deprecation-rules", "name": "phpstan/phpstan-deprecation-rules",
"version": "1.1.3", "version": "1.1.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan-deprecation-rules.git", "url": "https://github.com/phpstan/phpstan-deprecation-rules.git",
"reference": "a22b36b955a2e9a3d39fe533b6c1bb5359f9c319" "reference": "089d8a8258ed0aeefdc7b68b6c3d25572ebfdbaa"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/a22b36b955a2e9a3d39fe533b6c1bb5359f9c319", "url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/089d8a8258ed0aeefdc7b68b6c3d25572ebfdbaa",
"reference": "a22b36b955a2e9a3d39fe533b6c1bb5359f9c319", "reference": "089d8a8258ed0aeefdc7b68b6c3d25572ebfdbaa",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^7.2 || ^8.0", "php": "^7.2 || ^8.0",
"phpstan/phpstan": "^1.10" "phpstan/phpstan": "^1.10.3"
}, },
"require-dev": { "require-dev": {
"php-parallel-lint/php-parallel-lint": "^1.2", "php-parallel-lint/php-parallel-lint": "^1.2",
@@ -1284,9 +1284,9 @@
"description": "PHPStan rules for detecting usage of deprecated classes, methods, properties, constants and traits.", "description": "PHPStan rules for detecting usage of deprecated classes, methods, properties, constants and traits.",
"support": { "support": {
"issues": "https://github.com/phpstan/phpstan-deprecation-rules/issues", "issues": "https://github.com/phpstan/phpstan-deprecation-rules/issues",
"source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/1.1.3" "source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/1.1.4"
}, },
"time": "2023-03-17T07:50:08+00:00" "time": "2023-08-05T09:02:04+00:00"
}, },
{ {
"name": "psr/container", "name": "psr/container",
@@ -2402,16 +2402,16 @@
}, },
{ {
"name": "vimeo/psalm", "name": "vimeo/psalm",
"version": "5.14.1", "version": "5.15.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/vimeo/psalm.git", "url": "https://github.com/vimeo/psalm.git",
"reference": "b9d355e0829c397b9b3b47d0c0ed042a8a70284d" "reference": "5c774aca4746caf3d239d9c8cadb9f882ca29352"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/vimeo/psalm/zipball/b9d355e0829c397b9b3b47d0c0ed042a8a70284d", "url": "https://api.github.com/repos/vimeo/psalm/zipball/5c774aca4746caf3d239d9c8cadb9f882ca29352",
"reference": "b9d355e0829c397b9b3b47d0c0ed042a8a70284d", "reference": "5c774aca4746caf3d239d9c8cadb9f882ca29352",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2439,6 +2439,9 @@
"symfony/console": "^4.1.6 || ^5.0 || ^6.0", "symfony/console": "^4.1.6 || ^5.0 || ^6.0",
"symfony/filesystem": "^5.4 || ^6.0" "symfony/filesystem": "^5.4 || ^6.0"
}, },
"conflict": {
"nikic/php-parser": "4.17.0"
},
"provide": { "provide": {
"psalm/psalm": "self.version" "psalm/psalm": "self.version"
}, },
@@ -2502,9 +2505,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/vimeo/psalm/issues", "issues": "https://github.com/vimeo/psalm/issues",
"source": "https://github.com/vimeo/psalm/tree/5.14.1" "source": "https://github.com/vimeo/psalm/tree/5.15.0"
}, },
"time": "2023-08-01T05:16:55+00:00" "time": "2023-08-20T23:07:30+00:00"
}, },
{ {
"name": "webmozart/assert", "name": "webmozart/assert",

View File

@@ -53,3 +53,6 @@ parameters:
# paths: # paths:
# - ... # - ...
# - ... # - ...
-
message: "#^Call to deprecated method #"
path: www/admin/class_test*.php

View File

@@ -764,17 +764,17 @@
}, },
{ {
"name": "nikic/php-parser", "name": "nikic/php-parser",
"version": "v4.16.0", "version": "v4.17.1",
"version_normalized": "4.16.0.0", "version_normalized": "4.17.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nikic/PHP-Parser.git", "url": "https://github.com/nikic/PHP-Parser.git",
"reference": "19526a33fb561ef417e822e85f08a00db4059c17" "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/19526a33fb561ef417e822e85f08a00db4059c17", "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
"reference": "19526a33fb561ef417e822e85f08a00db4059c17", "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -785,7 +785,7 @@
"ircmaxell/php-yacc": "^0.0.7", "ircmaxell/php-yacc": "^0.0.7",
"phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
}, },
"time": "2023-06-25T14:52:30+00:00", "time": "2023-08-13T19:53:39+00:00",
"bin": [ "bin": [
"bin/php-parse" "bin/php-parse"
], ],
@@ -817,7 +817,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/nikic/PHP-Parser/issues", "issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.16.0" "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1"
}, },
"install-path": "../nikic/php-parser" "install-path": "../nikic/php-parser"
}, },
@@ -1021,17 +1021,17 @@
}, },
{ {
"name": "phpdocumentor/type-resolver", "name": "phpdocumentor/type-resolver",
"version": "1.7.2", "version": "1.7.3",
"version_normalized": "1.7.2.0", "version_normalized": "1.7.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git", "url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "b2fe4d22a5426f38e014855322200b97b5362c0d" "reference": "3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b2fe4d22a5426f38e014855322200b97b5362c0d", "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419",
"reference": "b2fe4d22a5426f38e014855322200b97b5362c0d", "reference": "3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1050,7 +1050,7 @@
"rector/rector": "^0.13.9", "rector/rector": "^0.13.9",
"vimeo/psalm": "^4.25" "vimeo/psalm": "^4.25"
}, },
"time": "2023-05-30T18:13:47+00:00", "time": "2023-08-12T11:01:26+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
@@ -1076,7 +1076,7 @@
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": { "support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues", "issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.2" "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.3"
}, },
"install-path": "../phpdocumentor/type-resolver" "install-path": "../phpdocumentor/type-resolver"
}, },
@@ -1129,17 +1129,17 @@
}, },
{ {
"name": "phpstan/phpdoc-parser", "name": "phpstan/phpdoc-parser",
"version": "1.23.0", "version": "1.23.1",
"version_normalized": "1.23.0.0", "version_normalized": "1.23.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git", "url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "a2b24135c35852b348894320d47b3902a94bc494" "reference": "846ae76eef31c6d7790fac9bc399ecee45160b26"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/a2b24135c35852b348894320d47b3902a94bc494", "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/846ae76eef31c6d7790fac9bc399ecee45160b26",
"reference": "a2b24135c35852b348894320d47b3902a94bc494", "reference": "846ae76eef31c6d7790fac9bc399ecee45160b26",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1156,7 +1156,7 @@
"phpunit/phpunit": "^9.5", "phpunit/phpunit": "^9.5",
"symfony/process": "^5.2" "symfony/process": "^5.2"
}, },
"time": "2023-07-23T22:17:56+00:00", "time": "2023-08-03T16:32:59+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@@ -1173,23 +1173,23 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types", "description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": { "support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues", "issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.23.0" "source": "https://github.com/phpstan/phpdoc-parser/tree/1.23.1"
}, },
"install-path": "../phpstan/phpdoc-parser" "install-path": "../phpstan/phpdoc-parser"
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "1.10.26", "version": "1.10.29",
"version_normalized": "1.10.26.0", "version_normalized": "1.10.29.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "5d660cbb7e1b89253a47147ae44044f49832351f" "reference": "ee5d8f2d3977fb09e55603eee6fb53bdd76ee9c1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/5d660cbb7e1b89253a47147ae44044f49832351f", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ee5d8f2d3977fb09e55603eee6fb53bdd76ee9c1",
"reference": "5d660cbb7e1b89253a47147ae44044f49832351f", "reference": "ee5d8f2d3977fb09e55603eee6fb53bdd76ee9c1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1198,7 +1198,7 @@
"conflict": { "conflict": {
"phpstan/phpstan-shim": "*" "phpstan/phpstan-shim": "*"
}, },
"time": "2023-07-19T12:44:37+00:00", "time": "2023-08-14T13:24:11+00:00",
"bin": [ "bin": [
"phpstan", "phpstan",
"phpstan.phar" "phpstan.phar"
@@ -1244,22 +1244,22 @@
}, },
{ {
"name": "phpstan/phpstan-deprecation-rules", "name": "phpstan/phpstan-deprecation-rules",
"version": "1.1.3", "version": "1.1.4",
"version_normalized": "1.1.3.0", "version_normalized": "1.1.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan-deprecation-rules.git", "url": "https://github.com/phpstan/phpstan-deprecation-rules.git",
"reference": "a22b36b955a2e9a3d39fe533b6c1bb5359f9c319" "reference": "089d8a8258ed0aeefdc7b68b6c3d25572ebfdbaa"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/a22b36b955a2e9a3d39fe533b6c1bb5359f9c319", "url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/089d8a8258ed0aeefdc7b68b6c3d25572ebfdbaa",
"reference": "a22b36b955a2e9a3d39fe533b6c1bb5359f9c319", "reference": "089d8a8258ed0aeefdc7b68b6c3d25572ebfdbaa",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^7.2 || ^8.0", "php": "^7.2 || ^8.0",
"phpstan/phpstan": "^1.10" "phpstan/phpstan": "^1.10.3"
}, },
"require-dev": { "require-dev": {
"php-parallel-lint/php-parallel-lint": "^1.2", "php-parallel-lint/php-parallel-lint": "^1.2",
@@ -1267,7 +1267,7 @@
"phpstan/phpstan-phpunit": "^1.0", "phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^9.5" "phpunit/phpunit": "^9.5"
}, },
"time": "2023-03-17T07:50:08+00:00", "time": "2023-08-05T09:02:04+00:00",
"type": "phpstan-extension", "type": "phpstan-extension",
"extra": { "extra": {
"phpstan": { "phpstan": {
@@ -1289,7 +1289,7 @@
"description": "PHPStan rules for detecting usage of deprecated classes, methods, properties, constants and traits.", "description": "PHPStan rules for detecting usage of deprecated classes, methods, properties, constants and traits.",
"support": { "support": {
"issues": "https://github.com/phpstan/phpstan-deprecation-rules/issues", "issues": "https://github.com/phpstan/phpstan-deprecation-rules/issues",
"source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/1.1.3" "source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/1.1.4"
}, },
"install-path": "../phpstan/phpstan-deprecation-rules" "install-path": "../phpstan/phpstan-deprecation-rules"
}, },
@@ -2505,17 +2505,17 @@
}, },
{ {
"name": "vimeo/psalm", "name": "vimeo/psalm",
"version": "5.14.1", "version": "5.15.0",
"version_normalized": "5.14.1.0", "version_normalized": "5.15.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/vimeo/psalm.git", "url": "https://github.com/vimeo/psalm.git",
"reference": "b9d355e0829c397b9b3b47d0c0ed042a8a70284d" "reference": "5c774aca4746caf3d239d9c8cadb9f882ca29352"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/vimeo/psalm/zipball/b9d355e0829c397b9b3b47d0c0ed042a8a70284d", "url": "https://api.github.com/repos/vimeo/psalm/zipball/5c774aca4746caf3d239d9c8cadb9f882ca29352",
"reference": "b9d355e0829c397b9b3b47d0c0ed042a8a70284d", "reference": "5c774aca4746caf3d239d9c8cadb9f882ca29352",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2543,6 +2543,9 @@
"symfony/console": "^4.1.6 || ^5.0 || ^6.0", "symfony/console": "^4.1.6 || ^5.0 || ^6.0",
"symfony/filesystem": "^5.4 || ^6.0" "symfony/filesystem": "^5.4 || ^6.0"
}, },
"conflict": {
"nikic/php-parser": "4.17.0"
},
"provide": { "provide": {
"psalm/psalm": "self.version" "psalm/psalm": "self.version"
}, },
@@ -2566,7 +2569,7 @@
"ext-curl": "In order to send data to shepherd", "ext-curl": "In order to send data to shepherd",
"ext-igbinary": "^2.0.5 is required, used to serialize caching data" "ext-igbinary": "^2.0.5 is required, used to serialize caching data"
}, },
"time": "2023-08-01T05:16:55+00:00", "time": "2023-08-20T23:07:30+00:00",
"bin": [ "bin": [
"psalm", "psalm",
"psalm-language-server", "psalm-language-server",
@@ -2608,7 +2611,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/vimeo/psalm/issues", "issues": "https://github.com/vimeo/psalm/issues",
"source": "https://github.com/vimeo/psalm/tree/5.14.1" "source": "https://github.com/vimeo/psalm/tree/5.15.0"
}, },
"install-path": "../vimeo/psalm" "install-path": "../vimeo/psalm"
}, },

View File

@@ -128,9 +128,9 @@
'dev_requirement' => true, 'dev_requirement' => true,
), ),
'nikic/php-parser' => array( 'nikic/php-parser' => array(
'pretty_version' => 'v4.16.0', 'pretty_version' => 'v4.17.1',
'version' => '4.16.0.0', 'version' => '4.17.1.0',
'reference' => '19526a33fb561ef417e822e85f08a00db4059c17', 'reference' => 'a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../nikic/php-parser', 'install_path' => __DIR__ . '/../nikic/php-parser',
'aliases' => array(), 'aliases' => array(),
@@ -164,9 +164,9 @@
'dev_requirement' => true, 'dev_requirement' => true,
), ),
'phpdocumentor/type-resolver' => array( 'phpdocumentor/type-resolver' => array(
'pretty_version' => '1.7.2', 'pretty_version' => '1.7.3',
'version' => '1.7.2.0', 'version' => '1.7.3.0',
'reference' => 'b2fe4d22a5426f38e014855322200b97b5362c0d', 'reference' => '3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../phpdocumentor/type-resolver', 'install_path' => __DIR__ . '/../phpdocumentor/type-resolver',
'aliases' => array(), 'aliases' => array(),
@@ -182,27 +182,27 @@
'dev_requirement' => true, 'dev_requirement' => true,
), ),
'phpstan/phpdoc-parser' => array( 'phpstan/phpdoc-parser' => array(
'pretty_version' => '1.23.0', 'pretty_version' => '1.23.1',
'version' => '1.23.0.0', 'version' => '1.23.1.0',
'reference' => 'a2b24135c35852b348894320d47b3902a94bc494', 'reference' => '846ae76eef31c6d7790fac9bc399ecee45160b26',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../phpstan/phpdoc-parser', 'install_path' => __DIR__ . '/../phpstan/phpdoc-parser',
'aliases' => array(), 'aliases' => array(),
'dev_requirement' => true, 'dev_requirement' => true,
), ),
'phpstan/phpstan' => array( 'phpstan/phpstan' => array(
'pretty_version' => '1.10.26', 'pretty_version' => '1.10.29',
'version' => '1.10.26.0', 'version' => '1.10.29.0',
'reference' => '5d660cbb7e1b89253a47147ae44044f49832351f', 'reference' => 'ee5d8f2d3977fb09e55603eee6fb53bdd76ee9c1',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../phpstan/phpstan', 'install_path' => __DIR__ . '/../phpstan/phpstan',
'aliases' => array(), 'aliases' => array(),
'dev_requirement' => true, 'dev_requirement' => true,
), ),
'phpstan/phpstan-deprecation-rules' => array( 'phpstan/phpstan-deprecation-rules' => array(
'pretty_version' => '1.1.3', 'pretty_version' => '1.1.4',
'version' => '1.1.3.0', 'version' => '1.1.4.0',
'reference' => 'a22b36b955a2e9a3d39fe533b6c1bb5359f9c319', 'reference' => '089d8a8258ed0aeefdc7b68b6c3d25572ebfdbaa',
'type' => 'phpstan-extension', 'type' => 'phpstan-extension',
'install_path' => __DIR__ . '/../phpstan/phpstan-deprecation-rules', 'install_path' => __DIR__ . '/../phpstan/phpstan-deprecation-rules',
'aliases' => array(), 'aliases' => array(),
@@ -211,7 +211,7 @@
'psalm/psalm' => array( 'psalm/psalm' => array(
'dev_requirement' => true, 'dev_requirement' => true,
'provided' => array( 'provided' => array(
0 => '5.14.1', 0 => '5.15.0',
), ),
), ),
'psr/container' => array( 'psr/container' => array(
@@ -365,9 +365,9 @@
'dev_requirement' => true, 'dev_requirement' => true,
), ),
'vimeo/psalm' => array( 'vimeo/psalm' => array(
'pretty_version' => '5.14.1', 'pretty_version' => '5.15.0',
'version' => '5.14.1.0', 'version' => '5.15.0.0',
'reference' => 'b9d355e0829c397b9b3b47d0c0ed042a8a70284d', 'reference' => '5c774aca4746caf3d239d9c8cadb9f882ca29352',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../vimeo/psalm', 'install_path' => __DIR__ . '/../vimeo/psalm',
'aliases' => array(), 'aliases' => array(),

View File

@@ -221,7 +221,10 @@ non_empty_class_const_list:
; ;
class_const: class_const:
identifier_maybe_reserved '=' expr { $$ = Node\Const_[$1, $3]; } T_STRING '=' expr
{ $$ = Node\Const_[new Node\Identifier($1, stackAttributes(#1)), $3]; }
| semi_reserved '=' expr
{ $$ = Node\Const_[new Node\Identifier($1, stackAttributes(#1)), $3]; }
; ;
inner_statement_list_ex: inner_statement_list_ex:
@@ -722,6 +725,9 @@ class_statement:
| optional_attributes method_modifiers T_CONST class_const_list semi | optional_attributes method_modifiers T_CONST class_const_list semi
{ $$ = new Stmt\ClassConst($4, $2, attributes(), $1); { $$ = new Stmt\ClassConst($4, $2, attributes(), $1);
$this->checkClassConst($$, #2); } $this->checkClassConst($$, #2); }
| optional_attributes method_modifiers T_CONST type_expr class_const_list semi
{ $$ = new Stmt\ClassConst($5, $2, attributes(), $1, $4);
$this->checkClassConst($$, #2); }
| optional_attributes method_modifiers T_FUNCTION optional_ref identifier_maybe_reserved '(' parameter_list ')' | optional_attributes method_modifiers T_FUNCTION optional_ref identifier_maybe_reserved '(' parameter_list ')'
optional_return_type method_body optional_return_type method_body
{ $$ = Stmt\ClassMethod[$5, ['type' => $2, 'byRef' => $4, 'params' => $7, 'returnType' => $9, 'stmts' => $10, 'attrGroups' => $1]]; { $$ = Stmt\ClassMethod[$5, ['type' => $2, 'byRef' => $4, 'params' => $7, 'returnType' => $9, 'stmts' => $10, 'attrGroups' => $1]];
@@ -943,8 +949,8 @@ expr:
; ;
anonymous_class: anonymous_class:
optional_attributes T_CLASS ctor_arguments extends_from implements_list '{' class_statement_list '}' optional_attributes class_entry_type ctor_arguments extends_from implements_list '{' class_statement_list '}'
{ $$ = array(Stmt\Class_[null, ['type' => 0, 'extends' => $4, 'implements' => $5, 'stmts' => $7, 'attrGroups' => $1]], $3); { $$ = array(Stmt\Class_[null, ['type' => $2, 'extends' => $4, 'implements' => $5, 'stmts' => $7, 'attrGroups' => $1]], $3);
$this->checkClass($$[0], -1); } $this->checkClass($$[0], -1); }
; ;
@@ -1040,6 +1046,8 @@ constant:
class_constant: class_constant:
class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier_maybe_reserved class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier_maybe_reserved
{ $$ = Expr\ClassConstFetch[$1, $3]; } { $$ = Expr\ClassConstFetch[$1, $3]; }
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM '{' expr '}'
{ $$ = Expr\ClassConstFetch[$1, $4]; }
/* We interpret an isolated FOO:: as an unfinished class constant fetch. It could also be /* We interpret an isolated FOO:: as an unfinished class constant fetch. It could also be
an unfinished static property fetch or unfinished scoped call. */ an unfinished static property fetch or unfinished scoped call. */
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM error | class_name_or_var T_PAAMAYIM_NEKUDOTAYIM error

View File

@@ -19,6 +19,8 @@ class ClassConst implements PhpParser\Builder
/** @var Node\AttributeGroup[] */ /** @var Node\AttributeGroup[] */
protected $attributeGroups = []; protected $attributeGroups = [];
/** @var Identifier|Node\Name|Node\ComplexType */
protected $type;
/** /**
* Creates a class constant builder * Creates a class constant builder
@@ -116,6 +118,19 @@ class ClassConst implements PhpParser\Builder
return $this; return $this;
} }
/**
* Sets the constant type.
*
* @param string|Node\Name|Identifier|Node\ComplexType $type
*
* @return $this
*/
public function setType($type) {
$this->type = BuilderHelpers::normalizeType($type);
return $this;
}
/** /**
* Returns the built class node. * Returns the built class node.
* *
@@ -126,7 +141,8 @@ class ClassConst implements PhpParser\Builder
$this->constants, $this->constants,
$this->flags, $this->flags,
$this->attributes, $this->attributes,
$this->attributeGroups $this->attributeGroups,
$this->type
); );
} }
} }

View File

@@ -349,15 +349,15 @@ class BuilderFactory
/** /**
* Creates a class constant fetch node. * Creates a class constant fetch node.
* *
* @param string|Name|Expr $class Class name * @param string|Name|Expr $class Class name
* @param string|Identifier $name Constant name * @param string|Identifier|Expr $name Constant name
* *
* @return Expr\ClassConstFetch * @return Expr\ClassConstFetch
*/ */
public function classConstFetch($class, $name): Expr\ClassConstFetch { public function classConstFetch($class, $name): Expr\ClassConstFetch {
return new Expr\ClassConstFetch( return new Expr\ClassConstFetch(
BuilderHelpers::normalizeNameOrExpr($class), BuilderHelpers::normalizeNameOrExpr($class),
BuilderHelpers::normalizeIdentifier($name) BuilderHelpers::normalizeIdentifierOrExpr($name)
); );
} }

View File

@@ -19,6 +19,8 @@ class PrintableNewAnonClassNode extends Expr
{ {
/** @var Node\AttributeGroup[] PHP attribute groups */ /** @var Node\AttributeGroup[] PHP attribute groups */
public $attrGroups; public $attrGroups;
/** @var int Modifiers */
public $flags;
/** @var Node\Arg[] Arguments */ /** @var Node\Arg[] Arguments */
public $args; public $args;
/** @var null|Node\Name Name of extended class */ /** @var null|Node\Name Name of extended class */
@@ -29,11 +31,12 @@ class PrintableNewAnonClassNode extends Expr
public $stmts; public $stmts;
public function __construct( public function __construct(
array $attrGroups, array $args, Node\Name $extends = null, array $implements, array $attrGroups, int $flags, array $args, Node\Name $extends = null, array $implements,
array $stmts, array $attributes array $stmts, array $attributes
) { ) {
parent::__construct($attributes); parent::__construct($attributes);
$this->attrGroups = $attrGroups; $this->attrGroups = $attrGroups;
$this->flags = $flags;
$this->args = $args; $this->args = $args;
$this->extends = $extends; $this->extends = $extends;
$this->implements = $implements; $this->implements = $implements;
@@ -46,7 +49,7 @@ class PrintableNewAnonClassNode extends Expr
// We don't assert that $class->name is null here, to allow consumers to assign unique names // We don't assert that $class->name is null here, to allow consumers to assign unique names
// to anonymous classes for their own purposes. We simplify ignore the name here. // to anonymous classes for their own purposes. We simplify ignore the name here.
return new self( return new self(
$class->attrGroups, $newNode->args, $class->extends, $class->implements, $class->attrGroups, $class->flags, $newNode->args, $class->extends, $class->implements,
$class->stmts, $newNode->getAttributes() $class->stmts, $newNode->getAttributes()
); );
} }
@@ -56,6 +59,6 @@ class PrintableNewAnonClassNode extends Expr
} }
public function getSubNodeNames() : array { public function getSubNodeNames() : array {
return ['attrGroups', 'args', 'extends', 'implements', 'stmts']; return ['attrGroups', 'flags', 'args', 'extends', 'implements', 'stmts'];
} }
} }

View File

@@ -10,15 +10,15 @@ class ClassConstFetch extends Expr
{ {
/** @var Name|Expr Class name */ /** @var Name|Expr Class name */
public $class; public $class;
/** @var Identifier|Error Constant name */ /** @var Identifier|Expr|Error Constant name */
public $name; public $name;
/** /**
* Constructs a class const fetch node. * Constructs a class const fetch node.
* *
* @param Name|Expr $class Class name * @param Name|Expr $class Class name
* @param string|Identifier|Error $name Constant name * @param string|Identifier|Expr|Error $name Constant name
* @param array $attributes Additional attributes * @param array $attributes Additional attributes
*/ */
public function __construct($class, $name, array $attributes = []) { public function __construct($class, $name, array $attributes = []) {
$this->attributes = $attributes; $this->attributes = $attributes;

View File

@@ -10,31 +10,36 @@ class ClassConst extends Node\Stmt
public $flags; public $flags;
/** @var Node\Const_[] Constant declarations */ /** @var Node\Const_[] Constant declarations */
public $consts; public $consts;
/** @var Node\AttributeGroup[] */ /** @var Node\AttributeGroup[] PHP attribute groups */
public $attrGroups; public $attrGroups;
/** @var Node\Identifier|Node\Name|Node\ComplexType|null Type declaration */
public $type;
/** /**
* Constructs a class const list node. * Constructs a class const list node.
* *
* @param Node\Const_[] $consts Constant declarations * @param Node\Const_[] $consts Constant declarations
* @param int $flags Modifiers * @param int $flags Modifiers
* @param array $attributes Additional attributes * @param array $attributes Additional attributes
* @param Node\AttributeGroup[] $attrGroups PHP attribute groups * @param Node\AttributeGroup[] $attrGroups PHP attribute groups
* @param null|string|Node\Identifier|Node\Name|Node\ComplexType $type Type declaration
*/ */
public function __construct( public function __construct(
array $consts, array $consts,
int $flags = 0, int $flags = 0,
array $attributes = [], array $attributes = [],
array $attrGroups = [] array $attrGroups = [],
$type = null
) { ) {
$this->attributes = $attributes; $this->attributes = $attributes;
$this->flags = $flags; $this->flags = $flags;
$this->consts = $consts; $this->consts = $consts;
$this->attrGroups = $attrGroups; $this->attrGroups = $attrGroups;
$this->type = \is_string($type) ? new Node\Identifier($type) : $type;
} }
public function getSubNodeNames() : array { public function getSubNodeNames() : array {
return ['attrGroups', 'flags', 'consts']; return ['attrGroups', 'flags', 'type', 'consts'];
} }
/** /**

File diff suppressed because it is too large Load Diff

View File

@@ -529,7 +529,7 @@ class Standard extends PrettyPrinterAbstract
} }
protected function pExpr_StaticCall(Expr\StaticCall $node) { protected function pExpr_StaticCall(Expr\StaticCall $node) {
return $this->pDereferenceLhs($node->class) . '::' return $this->pStaticDereferenceLhs($node->class) . '::'
. ($node->name instanceof Expr . ($node->name instanceof Expr
? ($node->name instanceof Expr\Variable ? ($node->name instanceof Expr\Variable
? $this->p($node->name) ? $this->p($node->name)
@@ -606,7 +606,7 @@ class Standard extends PrettyPrinterAbstract
} }
protected function pExpr_ClassConstFetch(Expr\ClassConstFetch $node) { protected function pExpr_ClassConstFetch(Expr\ClassConstFetch $node) {
return $this->pDereferenceLhs($node->class) . '::' . $this->p($node->name); return $this->pStaticDereferenceLhs($node->class) . '::' . $this->pObjectProperty($node->name);
} }
protected function pExpr_PropertyFetch(Expr\PropertyFetch $node) { protected function pExpr_PropertyFetch(Expr\PropertyFetch $node) {
@@ -618,7 +618,7 @@ class Standard extends PrettyPrinterAbstract
} }
protected function pExpr_StaticPropertyFetch(Expr\StaticPropertyFetch $node) { protected function pExpr_StaticPropertyFetch(Expr\StaticPropertyFetch $node) {
return $this->pDereferenceLhs($node->class) . '::$' . $this->pObjectProperty($node->name); return $this->pStaticDereferenceLhs($node->class) . '::$' . $this->pObjectProperty($node->name);
} }
protected function pExpr_ShellExec(Expr\ShellExec $node) { protected function pExpr_ShellExec(Expr\ShellExec $node) {
@@ -814,7 +814,9 @@ class Standard extends PrettyPrinterAbstract
protected function pStmt_ClassConst(Stmt\ClassConst $node) { protected function pStmt_ClassConst(Stmt\ClassConst $node) {
return $this->pAttrGroups($node->attrGroups) return $this->pAttrGroups($node->attrGroups)
. $this->pModifiers($node->flags) . $this->pModifiers($node->flags)
. 'const ' . $this->pCommaSeparated($node->consts) . ';'; . 'const '
. (null !== $node->type ? $this->p($node->type) . ' ' : '')
. $this->pCommaSeparated($node->consts) . ';';
} }
protected function pStmt_Function(Stmt\Function_ $node) { protected function pStmt_Function(Stmt\Function_ $node) {
@@ -1067,6 +1069,14 @@ class Standard extends PrettyPrinterAbstract
} }
} }
protected function pStaticDereferenceLhs(Node $node) {
if (!$this->staticDereferenceLhsRequiresParens($node)) {
return $this->p($node);
} else {
return '(' . $this->p($node) . ')';
}
}
protected function pCallLhs(Node $node) { protected function pCallLhs(Node $node) {
if (!$this->callLhsRequiresParens($node)) { if (!$this->callLhsRequiresParens($node)) {
return $this->p($node); return $this->p($node);
@@ -1075,9 +1085,12 @@ class Standard extends PrettyPrinterAbstract
} }
} }
protected function pNewVariable(Node $node) { protected function pNewVariable(Node $node): string {
// TODO: This is not fully accurate. if (!$this->newOperandRequiresParens($node)) {
return $this->pDereferenceLhs($node); return $this->p($node);
} else {
return '(' . $this->p($node) . ')';
}
} }
/** /**

View File

@@ -21,6 +21,8 @@ abstract class PrettyPrinterAbstract
const FIXUP_BRACED_NAME = 4; // Name operand that may require bracing const FIXUP_BRACED_NAME = 4; // Name operand that may require bracing
const FIXUP_VAR_BRACED_NAME = 5; // Name operand that may require ${} bracing const FIXUP_VAR_BRACED_NAME = 5; // Name operand that may require ${} bracing
const FIXUP_ENCAPSED = 6; // Encapsed string part const FIXUP_ENCAPSED = 6; // Encapsed string part
const FIXUP_NEW = 7; // New/instanceof operand
const FIXUP_STATIC_DEREF_LHS = 8; // LHS of static dereferencing operation
protected $precedenceMap = [ protected $precedenceMap = [
// [precedence, associativity] // [precedence, associativity]
@@ -977,6 +979,19 @@ abstract class PrettyPrinterAbstract
return '(' . $this->p($subNode) . ')'; return '(' . $this->p($subNode) . ')';
} }
break; break;
case self::FIXUP_STATIC_DEREF_LHS:
if ($this->staticDereferenceLhsRequiresParens($subNode)
&& !$this->origTokens->haveParens($subStartPos, $subEndPos)
) {
return '(' . $this->p($subNode) . ')';
}
break;
case self::FIXUP_NEW:
if ($this->newOperandRequiresParens($subNode)
&& !$this->origTokens->haveParens($subStartPos, $subEndPos)) {
return '(' . $this->p($subNode) . ')';
}
break;
case self::FIXUP_BRACED_NAME: case self::FIXUP_BRACED_NAME:
case self::FIXUP_VAR_BRACED_NAME: case self::FIXUP_VAR_BRACED_NAME:
if ($subNode instanceof Expr if ($subNode instanceof Expr
@@ -1047,13 +1062,26 @@ abstract class PrettyPrinterAbstract
} }
/** /**
* Determines whether the LHS of a dereferencing operation must be wrapped in parenthesis. * Determines whether the LHS of an array/object operation must be wrapped in parentheses.
* *
* @param Node $node LHS of dereferencing operation * @param Node $node LHS of dereferencing operation
* *
* @return bool Whether parentheses are required * @return bool Whether parentheses are required
*/ */
protected function dereferenceLhsRequiresParens(Node $node) : bool { protected function dereferenceLhsRequiresParens(Node $node) : bool {
// A constant can occur on the LHS of an array/object deref, but not a static deref.
return $this->staticDereferenceLhsRequiresParens($node)
&& !$node instanceof Expr\ConstFetch;
}
/**
* Determines whether the LHS of a static operation must be wrapped in parentheses.
*
* @param Node $node LHS of dereferencing operation
*
* @return bool Whether parentheses are required
*/
protected function staticDereferenceLhsRequiresParens(Node $node): bool {
return !($node instanceof Expr\Variable return !($node instanceof Expr\Variable
|| $node instanceof Node\Name || $node instanceof Node\Name
|| $node instanceof Expr\ArrayDimFetch || $node instanceof Expr\ArrayDimFetch
@@ -1066,10 +1094,31 @@ abstract class PrettyPrinterAbstract
|| $node instanceof Expr\StaticCall || $node instanceof Expr\StaticCall
|| $node instanceof Expr\Array_ || $node instanceof Expr\Array_
|| $node instanceof Scalar\String_ || $node instanceof Scalar\String_
|| $node instanceof Expr\ConstFetch
|| $node instanceof Expr\ClassConstFetch); || $node instanceof Expr\ClassConstFetch);
} }
/**
* Determines whether an expression used in "new" or "instanceof" requires parentheses.
*
* @param Node $node New or instanceof operand
*
* @return bool Whether parentheses are required
*/
protected function newOperandRequiresParens(Node $node): bool {
if ($node instanceof Node\Name || $node instanceof Expr\Variable) {
return false;
}
if ($node instanceof Expr\ArrayDimFetch || $node instanceof Expr\PropertyFetch ||
$node instanceof Expr\NullsafePropertyFetch
) {
return $this->newOperandRequiresParens($node->var);
}
if ($node instanceof Expr\StaticPropertyFetch) {
return $this->newOperandRequiresParens($node->class);
}
return true;
}
/** /**
* Print modifiers, including trailing whitespace. * Print modifiers, including trailing whitespace.
* *
@@ -1171,7 +1220,7 @@ abstract class PrettyPrinterAbstract
Expr\PostDec::class => ['var' => self::FIXUP_PREC_LEFT], Expr\PostDec::class => ['var' => self::FIXUP_PREC_LEFT],
Expr\Instanceof_::class => [ Expr\Instanceof_::class => [
'expr' => self::FIXUP_PREC_LEFT, 'expr' => self::FIXUP_PREC_LEFT,
'class' => self::FIXUP_PREC_RIGHT, // TODO: FIXUP_NEW_VARIABLE 'class' => self::FIXUP_NEW,
], ],
Expr\Ternary::class => [ Expr\Ternary::class => [
'cond' => self::FIXUP_PREC_LEFT, 'cond' => self::FIXUP_PREC_LEFT,
@@ -1179,10 +1228,13 @@ abstract class PrettyPrinterAbstract
], ],
Expr\FuncCall::class => ['name' => self::FIXUP_CALL_LHS], Expr\FuncCall::class => ['name' => self::FIXUP_CALL_LHS],
Expr\StaticCall::class => ['class' => self::FIXUP_DEREF_LHS], Expr\StaticCall::class => ['class' => self::FIXUP_STATIC_DEREF_LHS],
Expr\ArrayDimFetch::class => ['var' => self::FIXUP_DEREF_LHS], Expr\ArrayDimFetch::class => ['var' => self::FIXUP_DEREF_LHS],
Expr\ClassConstFetch::class => ['var' => self::FIXUP_DEREF_LHS], Expr\ClassConstFetch::class => [
Expr\New_::class => ['class' => self::FIXUP_DEREF_LHS], // TODO: FIXUP_NEW_VARIABLE 'class' => self::FIXUP_STATIC_DEREF_LHS,
'name' => self::FIXUP_BRACED_NAME,
],
Expr\New_::class => ['class' => self::FIXUP_NEW],
Expr\MethodCall::class => [ Expr\MethodCall::class => [
'var' => self::FIXUP_DEREF_LHS, 'var' => self::FIXUP_DEREF_LHS,
'name' => self::FIXUP_BRACED_NAME, 'name' => self::FIXUP_BRACED_NAME,
@@ -1192,7 +1244,7 @@ abstract class PrettyPrinterAbstract
'name' => self::FIXUP_BRACED_NAME, 'name' => self::FIXUP_BRACED_NAME,
], ],
Expr\StaticPropertyFetch::class => [ Expr\StaticPropertyFetch::class => [
'class' => self::FIXUP_DEREF_LHS, 'class' => self::FIXUP_STATIC_DEREF_LHS,
'name' => self::FIXUP_VAR_BRACED_NAME, 'name' => self::FIXUP_VAR_BRACED_NAME,
], ],
Expr\PropertyFetch::class => [ Expr\PropertyFetch::class => [
@@ -1278,6 +1330,7 @@ abstract class PrettyPrinterAbstract
'Param->default' => $stripEquals, 'Param->default' => $stripEquals,
'Stmt_Break->num' => $stripBoth, 'Stmt_Break->num' => $stripBoth,
'Stmt_Catch->var' => $stripLeft, 'Stmt_Catch->var' => $stripLeft,
'Stmt_ClassConst->type' => $stripRight,
'Stmt_ClassMethod->returnType' => $stripColon, 'Stmt_ClassMethod->returnType' => $stripColon,
'Stmt_Class->extends' => ['left' => \T_EXTENDS], 'Stmt_Class->extends' => ['left' => \T_EXTENDS],
'Stmt_Enum->scalarType' => $stripColon, 'Stmt_Enum->scalarType' => $stripColon,
@@ -1319,6 +1372,7 @@ abstract class PrettyPrinterAbstract
'Stmt_Break->num' => [\T_BREAK, false, ' ', null], 'Stmt_Break->num' => [\T_BREAK, false, ' ', null],
'Stmt_Catch->var' => [null, false, ' ', null], 'Stmt_Catch->var' => [null, false, ' ', null],
'Stmt_ClassMethod->returnType' => [')', false, ' : ', null], 'Stmt_ClassMethod->returnType' => [')', false, ' : ', null],
'Stmt_ClassConst->type' => [\T_CONST, false, ' ', null],
'Stmt_Class->extends' => [null, false, ' extends ', null], 'Stmt_Class->extends' => [null, false, ' extends ', null],
'Stmt_Enum->scalarType' => [null, false, ' : ', null], 'Stmt_Enum->scalarType' => [null, false, ' : ', null],
'Stmt_EnumCase->expr' => [null, false, ' = ', null], 'Stmt_EnumCase->expr' => [null, false, ' = ', null],
@@ -1508,6 +1562,7 @@ abstract class PrettyPrinterAbstract
'Stmt_ClassMethod->flags' => \T_FUNCTION, 'Stmt_ClassMethod->flags' => \T_FUNCTION,
'Stmt_Class->flags' => \T_CLASS, 'Stmt_Class->flags' => \T_CLASS,
'Stmt_Property->flags' => \T_VARIABLE, 'Stmt_Property->flags' => \T_VARIABLE,
'Expr_PrintableNewAnonClass->flags' => \T_CLASS,
'Param->flags' => \T_VARIABLE, 'Param->flags' => \T_VARIABLE,
//'Stmt_TraitUseAdaptation_Alias->newModifier' => 0, // TODO //'Stmt_TraitUseAdaptation_Alias->newModifier' => 0, // TODO
]; ];

View File

@@ -181,6 +181,7 @@ final class ContextFactory
$currentNamespace = $this->parseNamespace($tokens); $currentNamespace = $this->parseNamespace($tokens);
break; break;
case T_CLASS: case T_CLASS:
case T_TRAIT:
// Fast-forward the iterator through the class so that any // Fast-forward the iterator through the class so that any
// T_USE tokens found within are skipped - these are not // T_USE tokens found within are skipped - these are not
// valid namespace use statements so should be ignored. // valid namespace use statements so should be ignored.

View File

@@ -0,0 +1,42 @@
<?php declare(strict_types = 1);
namespace PHPStan\PhpDocParser\Ast\ConstExpr;
use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function sprintf;
use function str_replace;
use function strlen;
use function substr;
class DoctrineConstExprStringNode extends ConstExprStringNode
{
use NodeAttributes;
/** @var string */
public $value;
public function __construct(string $value)
{
parent::__construct($value);
$this->value = $value;
}
public function __toString(): string
{
return self::escape($this->value);
}
public static function unescape(string $value): string
{
// from https://github.com/doctrine/annotations/blob/a9ec7af212302a75d1f92fa65d3abfbd16245a2a/lib/Doctrine/Common/Annotations/DocLexer.php#L103-L107
return str_replace('""', '"', substr($value, 1, strlen($value) - 2));
}
private static function escape(string $value): string
{
// from https://github.com/phpstan/phpdoc-parser/issues/205#issuecomment-1662323656
return sprintf('"%s"', str_replace('"', '""', $value));
}
}

View File

@@ -35,19 +35,20 @@ class Lexer
public const TOKEN_INTEGER = 20; public const TOKEN_INTEGER = 20;
public const TOKEN_SINGLE_QUOTED_STRING = 21; public const TOKEN_SINGLE_QUOTED_STRING = 21;
public const TOKEN_DOUBLE_QUOTED_STRING = 22; public const TOKEN_DOUBLE_QUOTED_STRING = 22;
public const TOKEN_IDENTIFIER = 23; public const TOKEN_DOCTRINE_ANNOTATION_STRING = 23;
public const TOKEN_THIS_VARIABLE = 24; public const TOKEN_IDENTIFIER = 24;
public const TOKEN_VARIABLE = 25; public const TOKEN_THIS_VARIABLE = 25;
public const TOKEN_HORIZONTAL_WS = 26; public const TOKEN_VARIABLE = 26;
public const TOKEN_PHPDOC_EOL = 27; public const TOKEN_HORIZONTAL_WS = 27;
public const TOKEN_OTHER = 28; public const TOKEN_PHPDOC_EOL = 28;
public const TOKEN_END = 29; public const TOKEN_OTHER = 29;
public const TOKEN_COLON = 30; public const TOKEN_END = 30;
public const TOKEN_WILDCARD = 31; public const TOKEN_COLON = 31;
public const TOKEN_OPEN_CURLY_BRACKET = 32; public const TOKEN_WILDCARD = 32;
public const TOKEN_CLOSE_CURLY_BRACKET = 33; public const TOKEN_OPEN_CURLY_BRACKET = 33;
public const TOKEN_NEGATED = 34; public const TOKEN_CLOSE_CURLY_BRACKET = 34;
public const TOKEN_ARROW = 35; public const TOKEN_NEGATED = 35;
public const TOKEN_ARROW = 36;
public const TOKEN_LABELS = [ public const TOKEN_LABELS = [
self::TOKEN_REFERENCE => '\'&\'', self::TOKEN_REFERENCE => '\'&\'',
@@ -79,6 +80,7 @@ class Lexer
self::TOKEN_INTEGER => 'TOKEN_INTEGER', self::TOKEN_INTEGER => 'TOKEN_INTEGER',
self::TOKEN_SINGLE_QUOTED_STRING => 'TOKEN_SINGLE_QUOTED_STRING', self::TOKEN_SINGLE_QUOTED_STRING => 'TOKEN_SINGLE_QUOTED_STRING',
self::TOKEN_DOUBLE_QUOTED_STRING => 'TOKEN_DOUBLE_QUOTED_STRING', self::TOKEN_DOUBLE_QUOTED_STRING => 'TOKEN_DOUBLE_QUOTED_STRING',
self::TOKEN_DOCTRINE_ANNOTATION_STRING => 'TOKEN_DOCTRINE_ANNOTATION_STRING',
self::TOKEN_IDENTIFIER => 'type', self::TOKEN_IDENTIFIER => 'type',
self::TOKEN_THIS_VARIABLE => '\'$this\'', self::TOKEN_THIS_VARIABLE => '\'$this\'',
self::TOKEN_VARIABLE => 'variable', self::TOKEN_VARIABLE => 'variable',
@@ -180,6 +182,7 @@ class Lexer
if ($this->parseDoctrineAnnotations) { if ($this->parseDoctrineAnnotations) {
$patterns[self::TOKEN_DOCTRINE_TAG] = '@[a-z_\\\\][a-z0-9_\:\\\\]*[a-z_][a-z0-9_]*'; $patterns[self::TOKEN_DOCTRINE_TAG] = '@[a-z_\\\\][a-z0-9_\:\\\\]*[a-z_][a-z0-9_]*';
$patterns[self::TOKEN_DOCTRINE_ANNOTATION_STRING] = '"(?:""|[^"])*+"';
} }
// anything but TOKEN_CLOSE_PHPDOC or TOKEN_HORIZONTAL_WS or TOKEN_EOL // anything but TOKEN_CLOSE_PHPDOC or TOKEN_HORIZONTAL_WS or TOKEN_EOL

View File

@@ -23,6 +23,9 @@ class ConstExprParser
/** @var bool */ /** @var bool */
private $useIndexAttributes; private $useIndexAttributes;
/** @var bool */
private $parseDoctrineStrings;
/** /**
* @param array{lines?: bool, indexes?: bool} $usedAttributes * @param array{lines?: bool, indexes?: bool} $usedAttributes
*/ */
@@ -36,6 +39,24 @@ class ConstExprParser
$this->quoteAwareConstExprString = $quoteAwareConstExprString; $this->quoteAwareConstExprString = $quoteAwareConstExprString;
$this->useLinesAttributes = $usedAttributes['lines'] ?? false; $this->useLinesAttributes = $usedAttributes['lines'] ?? false;
$this->useIndexAttributes = $usedAttributes['indexes'] ?? false; $this->useIndexAttributes = $usedAttributes['indexes'] ?? false;
$this->parseDoctrineStrings = false;
}
/**
* @internal
*/
public function toDoctrine(): self
{
$self = new self(
$this->unescapeStrings,
$this->quoteAwareConstExprString,
[
'lines' => $this->useLinesAttributes,
'indexes' => $this->useIndexAttributes,
]
);
$self->parseDoctrineStrings = true;
return $self;
} }
public function parse(TokenIterator $tokens, bool $trimStrings = false): Ast\ConstExpr\ConstExprNode public function parse(TokenIterator $tokens, bool $trimStrings = false): Ast\ConstExpr\ConstExprNode
@@ -66,7 +87,41 @@ class ConstExprParser
); );
} }
if ($this->parseDoctrineStrings && $tokens->isCurrentTokenType(Lexer::TOKEN_DOCTRINE_ANNOTATION_STRING)) {
$value = $tokens->currentTokenValue();
$tokens->next();
return $this->enrichWithAttributes(
$tokens,
new Ast\ConstExpr\DoctrineConstExprStringNode(Ast\ConstExpr\DoctrineConstExprStringNode::unescape($value)),
$startLine,
$startIndex
);
}
if ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING, Lexer::TOKEN_DOUBLE_QUOTED_STRING)) { if ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING, Lexer::TOKEN_DOUBLE_QUOTED_STRING)) {
if ($this->parseDoctrineStrings) {
if ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) {
throw new ParserException(
$tokens->currentTokenValue(),
$tokens->currentTokenType(),
$tokens->currentTokenOffset(),
Lexer::TOKEN_DOUBLE_QUOTED_STRING,
null,
$tokens->currentTokenLine()
);
}
$value = $tokens->currentTokenValue();
$tokens->next();
return $this->enrichWithAttributes(
$tokens,
$this->parseDoctrineString($value, $tokens),
$startLine,
$startIndex
);
}
$value = $tokens->currentTokenValue(); $value = $tokens->currentTokenValue();
$type = $tokens->currentTokenType(); $type = $tokens->currentTokenType();
if ($trimStrings) { if ($trimStrings) {
@@ -214,6 +269,23 @@ class ConstExprParser
} }
/**
* This method is supposed to be called with TokenIterator after reading TOKEN_DOUBLE_QUOTED_STRING and shifting
* to the next token.
*/
public function parseDoctrineString(string $text, TokenIterator $tokens): Ast\ConstExpr\DoctrineConstExprStringNode
{
// Because of how Lexer works, a valid Doctrine string
// can consist of a sequence of TOKEN_DOUBLE_QUOTED_STRING and TOKEN_DOCTRINE_ANNOTATION_STRING
while ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING, Lexer::TOKEN_DOCTRINE_ANNOTATION_STRING)) {
$text .= $tokens->currentTokenValue();
$tokens->next();
}
return new Ast\ConstExpr\DoctrineConstExprStringNode(Ast\ConstExpr\DoctrineConstExprStringNode::unescape($text));
}
private function parseArrayItem(TokenIterator $tokens): Ast\ConstExpr\ConstExprArrayItemNode private function parseArrayItem(TokenIterator $tokens): Ast\ConstExpr\ConstExprArrayItemNode
{ {
$startLine = $tokens->currentTokenLine(); $startLine = $tokens->currentTokenLine();

View File

@@ -35,6 +35,9 @@ class PhpDocParser
/** @var ConstExprParser */ /** @var ConstExprParser */
private $constantExprParser; private $constantExprParser;
/** @var ConstExprParser */
private $doctrineConstantExprParser;
/** @var bool */ /** @var bool */
private $requireWhitespaceBeforeDescription; private $requireWhitespaceBeforeDescription;
@@ -68,6 +71,7 @@ class PhpDocParser
{ {
$this->typeParser = $typeParser; $this->typeParser = $typeParser;
$this->constantExprParser = $constantExprParser; $this->constantExprParser = $constantExprParser;
$this->doctrineConstantExprParser = $constantExprParser->toDoctrine();
$this->requireWhitespaceBeforeDescription = $requireWhitespaceBeforeDescription; $this->requireWhitespaceBeforeDescription = $requireWhitespaceBeforeDescription;
$this->preserveTypeAliasesWithInvalidTypes = $preserveTypeAliasesWithInvalidTypes; $this->preserveTypeAliasesWithInvalidTypes = $preserveTypeAliasesWithInvalidTypes;
$this->parseDoctrineAnnotations = $parseDoctrineAnnotations; $this->parseDoctrineAnnotations = $parseDoctrineAnnotations;
@@ -688,7 +692,7 @@ class PhpDocParser
); );
try { try {
$constExpr = $this->constantExprParser->parse($tokens, true); $constExpr = $this->doctrineConstantExprParser->parse($tokens, true);
if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) { if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) {
throw $exception; throw $exception;
} }
@@ -750,14 +754,15 @@ class PhpDocParser
$key = new Ast\ConstExpr\ConstExprIntegerNode(str_replace('_', '', $tokens->currentTokenValue())); $key = new Ast\ConstExpr\ConstExprIntegerNode(str_replace('_', '', $tokens->currentTokenValue()));
$tokens->next(); $tokens->next();
} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) { } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOCTRINE_ANNOTATION_STRING)) {
$key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::SINGLE_QUOTED); $key = new Ast\ConstExpr\DoctrineConstExprStringNode(Ast\ConstExpr\DoctrineConstExprStringNode::unescape($tokens->currentTokenValue()));
$tokens->next(); $tokens->next();
} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING)) { } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING)) {
$key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::DOUBLE_QUOTED); $value = $tokens->currentTokenValue();
$tokens->next(); $tokens->next();
$key = $this->doctrineConstantExprParser->parseDoctrineString($value, $tokens);
} else { } else {
$currentTokenValue = $tokens->currentTokenValue(); $currentTokenValue = $tokens->currentTokenValue();
@@ -786,7 +791,7 @@ class PhpDocParser
} }
$tokens->rollback(); $tokens->rollback();
$constExpr = $this->constantExprParser->parse($tokens, true); $constExpr = $this->doctrineConstantExprParser->parse($tokens, true);
if (!$constExpr instanceof Ast\ConstExpr\ConstFetchNode) { if (!$constExpr instanceof Ast\ConstExpr\ConstFetchNode) {
throw new ParserException( throw new ParserException(
$tokens->currentTokenValue(), $tokens->currentTokenValue(),

View File

@@ -36,3 +36,48 @@ In case you don't own the code which you want to be considered deprecated, use [
/** @deprecated */ /** @deprecated */
class ThirdPartyClass {} class ThirdPartyClass {}
``` ```
## Custom deprecated scopes
Usage of deprecated code is not reported in code that is also deprecated:
```php
/** @deprecated */
function doFoo(): void
{
// not reported:
anotherDeprecatedFunction();
}
```
If you have [a different way](https://github.com/phpstan/phpstan-deprecation-rules/issues/64) of marking code that calls deprecated symbols on purpose and you don't want these calls to be reported either, you can write an extension by implementing the [`DeprecatedScopeResolver`](https://github.com/phpstan/phpstan-deprecation-rules/blob/1.1.x/src/Rules/Deprecations/DeprecatedScopeResolver.php) interface.
For example if you mark your PHPUnit tests that test deprecated code with `@group legacy`, you can implement the extension this way:
```php
class GroupLegacyScopeResolver implements DeprecatedScopeResolver
{
public function isScopeDeprecated(Scope $scope): bool
{
$function = $scope->getFunction();
return $function !== null
&& $function->getDocComment() !== null
&& strpos($function->getDocComment(), '@group legacy') !== false;
}
}
```
And register it in your [configuration file](https://phpstan.org/config-reference):
```neon
services:
-
class: GroupLegacyScopeResolver
tags:
- phpstan.deprecations.deprecatedScopeResolver
```
[Learn more about Scope](https://phpstan.org/developing-extensions/scope), a core concept for implementing custom PHPStan extensions.

View File

@@ -1,8 +1,9 @@
{ {
"require-dev": { "require-dev": {
"consistence-community/coding-standard": "^3.10", "consistence-community/coding-standard": "^3.11.0",
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", "dealerdirect/phpcodesniffer-composer-installer": "^1.0.0",
"slevomat/coding-standard": "^7.0" "slevomat/coding-standard": "^8.8.0",
"squizlabs/php_codesniffer": "^3.5.3"
}, },
"config": { "config": {
"allow-plugins": { "allow-plugins": {

View File

@@ -4,35 +4,35 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "4485bbedba7bcc71ace5f69dbb9b6c47", "content-hash": "e69c1916405a7e3c8001c1b609a0ee61",
"packages": [], "packages": [],
"packages-dev": [ "packages-dev": [
{ {
"name": "consistence-community/coding-standard", "name": "consistence-community/coding-standard",
"version": "3.11.1", "version": "3.11.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/consistence-community/coding-standard.git", "url": "https://github.com/consistence-community/coding-standard.git",
"reference": "4632fead8c9ee8f50044fcbce9f66c797b34c0df" "reference": "f38e06327d5bf80ff5ff523a2c05e623b5e8d8b1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/consistence-community/coding-standard/zipball/4632fead8c9ee8f50044fcbce9f66c797b34c0df", "url": "https://api.github.com/repos/consistence-community/coding-standard/zipball/f38e06327d5bf80ff5ff523a2c05e623b5e8d8b1",
"reference": "4632fead8c9ee8f50044fcbce9f66c797b34c0df", "reference": "f38e06327d5bf80ff5ff523a2c05e623b5e8d8b1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=7.4", "php": "~8.0",
"slevomat/coding-standard": "~7.0", "slevomat/coding-standard": "~8.0",
"squizlabs/php_codesniffer": "~3.6.0" "squizlabs/php_codesniffer": "~3.7.0"
}, },
"replace": { "replace": {
"consistence/coding-standard": "3.10.*" "consistence/coding-standard": "3.10.*"
}, },
"require-dev": { "require-dev": {
"phing/phing": "2.16.4", "phing/phing": "2.17.0",
"php-parallel-lint/php-parallel-lint": "1.3.0", "php-parallel-lint/php-parallel-lint": "1.3.1",
"phpunit/phpunit": "9.5.4" "phpunit/phpunit": "9.5.10"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@@ -70,41 +70,44 @@
], ],
"support": { "support": {
"issues": "https://github.com/consistence-community/coding-standard/issues", "issues": "https://github.com/consistence-community/coding-standard/issues",
"source": "https://github.com/consistence-community/coding-standard/tree/3.11.1" "source": "https://github.com/consistence-community/coding-standard/tree/3.11.3"
}, },
"time": "2021-05-03T18:13:22+00:00" "time": "2023-03-27T14:55:41+00:00"
}, },
{ {
"name": "dealerdirect/phpcodesniffer-composer-installer", "name": "dealerdirect/phpcodesniffer-composer-installer",
"version": "v0.7.2", "version": "v1.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git", "url": "https://github.com/PHPCSStandards/composer-installer.git",
"reference": "1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db" "reference": "4be43904336affa5c2f70744a348312336afd0da"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db", "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da",
"reference": "1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db", "reference": "4be43904336affa5c2f70744a348312336afd0da",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"composer-plugin-api": "^1.0 || ^2.0", "composer-plugin-api": "^1.0 || ^2.0",
"php": ">=5.3", "php": ">=5.4",
"squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0"
}, },
"require-dev": { "require-dev": {
"composer/composer": "*", "composer/composer": "*",
"ext-json": "*",
"ext-zip": "*",
"php-parallel-lint/php-parallel-lint": "^1.3.1", "php-parallel-lint/php-parallel-lint": "^1.3.1",
"phpcompatibility/php-compatibility": "^9.0" "phpcompatibility/php-compatibility": "^9.0",
"yoast/phpunit-polyfills": "^1.0"
}, },
"type": "composer-plugin", "type": "composer-plugin",
"extra": { "extra": {
"class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/"
} }
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
@@ -120,7 +123,7 @@
}, },
{ {
"name": "Contributors", "name": "Contributors",
"homepage": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer/graphs/contributors" "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors"
} }
], ],
"description": "PHP_CodeSniffer Standards Composer Installer Plugin", "description": "PHP_CodeSniffer Standards Composer Installer Plugin",
@@ -144,23 +147,23 @@
"tests" "tests"
], ],
"support": { "support": {
"issues": "https://github.com/dealerdirect/phpcodesniffer-composer-installer/issues", "issues": "https://github.com/PHPCSStandards/composer-installer/issues",
"source": "https://github.com/dealerdirect/phpcodesniffer-composer-installer" "source": "https://github.com/PHPCSStandards/composer-installer"
}, },
"time": "2022-02-04T12:51:07+00:00" "time": "2023-01-05T11:28:13+00:00"
}, },
{ {
"name": "phpstan/phpdoc-parser", "name": "phpstan/phpdoc-parser",
"version": "1.5.1", "version": "1.20.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git", "url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "981cc368a216c988e862a75e526b6076987d1b50" "reference": "7d568c87a9df9c5f7e8b5f075fc469aa8cb0a4cd"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/981cc368a216c988e862a75e526b6076987d1b50", "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/7d568c87a9df9c5f7e8b5f075fc469aa8cb0a4cd",
"reference": "981cc368a216c988e862a75e526b6076987d1b50", "reference": "7d568c87a9df9c5f7e8b5f075fc469aa8cb0a4cd",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -170,6 +173,7 @@
"php-parallel-lint/php-parallel-lint": "^1.2", "php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/extension-installer": "^1.0", "phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^1.5", "phpstan/phpstan": "^1.5",
"phpstan/phpstan-phpunit": "^1.1",
"phpstan/phpstan-strict-rules": "^1.0", "phpstan/phpstan-strict-rules": "^1.0",
"phpunit/phpunit": "^9.5", "phpunit/phpunit": "^9.5",
"symfony/process": "^5.2" "symfony/process": "^5.2"
@@ -189,48 +193,48 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types", "description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": { "support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues", "issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.5.1" "source": "https://github.com/phpstan/phpdoc-parser/tree/1.20.4"
}, },
"time": "2022-05-05T11:32:40+00:00" "time": "2023-05-02T09:19:37+00:00"
}, },
{ {
"name": "slevomat/coding-standard", "name": "slevomat/coding-standard",
"version": "7.2.1", "version": "8.12.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/slevomat/coding-standard.git", "url": "https://github.com/slevomat/coding-standard.git",
"reference": "aff06ae7a84e4534bf6f821dc982a93a5d477c90" "reference": "cc04334ed0ce5a251389112fbd2dbe1dbc931ae8"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/slevomat/coding-standard/zipball/aff06ae7a84e4534bf6f821dc982a93a5d477c90", "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/cc04334ed0ce5a251389112fbd2dbe1dbc931ae8",
"reference": "aff06ae7a84e4534bf6f821dc982a93a5d477c90", "reference": "cc04334ed0ce5a251389112fbd2dbe1dbc931ae8",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7", "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.0",
"php": "^7.2 || ^8.0", "php": "^7.2 || ^8.0",
"phpstan/phpdoc-parser": "^1.5.1", "phpstan/phpdoc-parser": ">=1.20.0 <1.21.0",
"squizlabs/php_codesniffer": "^3.6.2" "squizlabs/php_codesniffer": "^3.7.1"
}, },
"require-dev": { "require-dev": {
"phing/phing": "2.17.3", "phing/phing": "2.17.4",
"php-parallel-lint/php-parallel-lint": "1.3.2", "php-parallel-lint/php-parallel-lint": "1.3.2",
"phpstan/phpstan": "1.4.10|1.7.1", "phpstan/phpstan": "1.10.15",
"phpstan/phpstan-deprecation-rules": "1.0.0", "phpstan/phpstan-deprecation-rules": "1.1.3",
"phpstan/phpstan-phpunit": "1.0.0|1.1.1", "phpstan/phpstan-phpunit": "1.3.11",
"phpstan/phpstan-strict-rules": "1.2.3", "phpstan/phpstan-strict-rules": "1.5.1",
"phpunit/phpunit": "7.5.20|8.5.21|9.5.20" "phpunit/phpunit": "7.5.20|8.5.21|9.6.8|10.1.3"
}, },
"type": "phpcodesniffer-standard", "type": "phpcodesniffer-standard",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "7.x-dev" "dev-master": "8.x-dev"
} }
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"SlevomatCodingStandard\\": "SlevomatCodingStandard" "SlevomatCodingStandard\\": "SlevomatCodingStandard/"
} }
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
@@ -238,9 +242,13 @@
"MIT" "MIT"
], ],
"description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.",
"keywords": [
"dev",
"phpcs"
],
"support": { "support": {
"issues": "https://github.com/slevomat/coding-standard/issues", "issues": "https://github.com/slevomat/coding-standard/issues",
"source": "https://github.com/slevomat/coding-standard/tree/7.2.1" "source": "https://github.com/slevomat/coding-standard/tree/8.12.0"
}, },
"funding": [ "funding": [
{ {
@@ -252,20 +260,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-05-25T10:58:12+00:00" "time": "2023-05-14T20:06:01+00:00"
}, },
{ {
"name": "squizlabs/php_codesniffer", "name": "squizlabs/php_codesniffer",
"version": "3.6.2", "version": "3.7.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
"reference": "5e4e71592f69da17871dba6e80dd51bce74a351a" "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/5e4e71592f69da17871dba6e80dd51bce74a351a", "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879",
"reference": "5e4e71592f69da17871dba6e80dd51bce74a351a", "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -301,14 +309,15 @@
"homepage": "https://github.com/squizlabs/PHP_CodeSniffer", "homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
"keywords": [ "keywords": [
"phpcs", "phpcs",
"standards" "standards",
"static analysis"
], ],
"support": { "support": {
"issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues",
"source": "https://github.com/squizlabs/PHP_CodeSniffer", "source": "https://github.com/squizlabs/PHP_CodeSniffer",
"wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki"
}, },
"time": "2021-12-12T21:44:58+00:00" "time": "2023-02-22T23:07:41+00:00"
} }
], ],
"aliases": [], "aliases": [],

View File

@@ -7,7 +7,7 @@
], ],
"require": { "require": {
"php": "^7.2 || ^8.0", "php": "^7.2 || ^8.0",
"phpstan/phpstan": "^1.10" "phpstan/phpstan": "^1.10.3"
}, },
"require-dev": { "require-dev": {
"php-parallel-lint/php-parallel-lint": "^1.2", "php-parallel-lint/php-parallel-lint": "^1.2",

View File

@@ -2,8 +2,19 @@ parameters:
deprecationRulesInstalled: true deprecationRulesInstalled: true
services: services:
- -
class: PHPStan\Rules\Deprecations\DeprecatedClassHelper class: PHPStan\Rules\Deprecations\DeprecatedClassHelper
-
class: PHPStan\DependencyInjection\LazyDeprecatedScopeResolverProvider
-
class: PHPStan\Rules\Deprecations\DeprecatedScopeHelper
factory: @PHPStan\DependencyInjection\LazyDeprecatedScopeResolverProvider::get
-
class: PHPStan\Rules\Deprecations\DefaultDeprecatedScopeResolver
tags:
- phpstan.deprecations.deprecatedScopeResolver
rules: rules:
- PHPStan\Rules\Deprecations\AccessDeprecatedPropertyRule - PHPStan\Rules\Deprecations\AccessDeprecatedPropertyRule

View File

@@ -0,0 +1,33 @@
<?php declare(strict_types = 1);
namespace PHPStan\DependencyInjection;
use PHPStan\Rules\Deprecations\DeprecatedScopeHelper;
final class LazyDeprecatedScopeResolverProvider
{
public const EXTENSION_TAG = 'phpstan.deprecations.deprecatedScopeResolver';
/** @var Container */
private $container;
/** @var DeprecatedScopeHelper */
private $scopeHelper;
public function __construct(Container $container)
{
$this->container = $container;
}
public function get(): DeprecatedScopeHelper
{
if ($this->scopeHelper === null) {
$this->scopeHelper = new DeprecatedScopeHelper(
$this->container->getServicesByTag(self::EXTENSION_TAG)
);
}
return $this->scopeHelper;
}
}

View File

@@ -21,9 +21,13 @@ class AccessDeprecatedPropertyRule implements Rule
/** @var ReflectionProvider */ /** @var ReflectionProvider */
private $reflectionProvider; private $reflectionProvider;
public function __construct(ReflectionProvider $reflectionProvider) /** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(ReflectionProvider $reflectionProvider, DeprecatedScopeHelper $deprecatedScopeHelper)
{ {
$this->reflectionProvider = $reflectionProvider; $this->reflectionProvider = $reflectionProvider;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
} }
public function getNodeType(): string public function getNodeType(): string
@@ -33,7 +37,7 @@ class AccessDeprecatedPropertyRule implements Rule
public function processNode(Node $node, Scope $scope): array public function processNode(Node $node, Scope $scope): array
{ {
if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return []; return [];
} }

View File

@@ -28,10 +28,14 @@ class AccessDeprecatedStaticPropertyRule implements Rule
/** @var RuleLevelHelper */ /** @var RuleLevelHelper */
private $ruleLevelHelper; private $ruleLevelHelper;
public function __construct(ReflectionProvider $reflectionProvider, RuleLevelHelper $ruleLevelHelper) /** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(ReflectionProvider $reflectionProvider, RuleLevelHelper $ruleLevelHelper, DeprecatedScopeHelper $deprecatedScopeHelper)
{ {
$this->reflectionProvider = $reflectionProvider; $this->reflectionProvider = $reflectionProvider;
$this->ruleLevelHelper = $ruleLevelHelper; $this->ruleLevelHelper = $ruleLevelHelper;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
} }
public function getNodeType(): string public function getNodeType(): string
@@ -41,7 +45,7 @@ class AccessDeprecatedStaticPropertyRule implements Rule
public function processNode(Node $node, Scope $scope): array public function processNode(Node $node, Scope $scope): array
{ {
if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return []; return [];
} }

View File

@@ -20,9 +20,13 @@ class CallToDeprecatedFunctionRule implements Rule
/** @var ReflectionProvider */ /** @var ReflectionProvider */
private $reflectionProvider; private $reflectionProvider;
public function __construct(ReflectionProvider $reflectionProvider) /** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(ReflectionProvider $reflectionProvider, DeprecatedScopeHelper $deprecatedScopeHelper)
{ {
$this->reflectionProvider = $reflectionProvider; $this->reflectionProvider = $reflectionProvider;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
} }
public function getNodeType(): string public function getNodeType(): string
@@ -32,7 +36,7 @@ class CallToDeprecatedFunctionRule implements Rule
public function processNode(Node $node, Scope $scope): array public function processNode(Node $node, Scope $scope): array
{ {
if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return []; return [];
} }

View File

@@ -21,9 +21,13 @@ class CallToDeprecatedMethodRule implements Rule
/** @var ReflectionProvider */ /** @var ReflectionProvider */
private $reflectionProvider; private $reflectionProvider;
public function __construct(ReflectionProvider $reflectionProvider) /** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(ReflectionProvider $reflectionProvider, DeprecatedScopeHelper $deprecatedScopeHelper)
{ {
$this->reflectionProvider = $reflectionProvider; $this->reflectionProvider = $reflectionProvider;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
} }
public function getNodeType(): string public function getNodeType(): string
@@ -33,7 +37,7 @@ class CallToDeprecatedMethodRule implements Rule
public function processNode(Node $node, Scope $scope): array public function processNode(Node $node, Scope $scope): array
{ {
if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return []; return [];
} }

View File

@@ -28,10 +28,14 @@ class CallToDeprecatedStaticMethodRule implements Rule
/** @var RuleLevelHelper */ /** @var RuleLevelHelper */
private $ruleLevelHelper; private $ruleLevelHelper;
public function __construct(ReflectionProvider $reflectionProvider, RuleLevelHelper $ruleLevelHelper) /** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(ReflectionProvider $reflectionProvider, RuleLevelHelper $ruleLevelHelper, DeprecatedScopeHelper $deprecatedScopeHelper)
{ {
$this->reflectionProvider = $reflectionProvider; $this->reflectionProvider = $reflectionProvider;
$this->ruleLevelHelper = $ruleLevelHelper; $this->ruleLevelHelper = $ruleLevelHelper;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
} }
public function getNodeType(): string public function getNodeType(): string
@@ -41,7 +45,7 @@ class CallToDeprecatedStaticMethodRule implements Rule
public function processNode(Node $node, Scope $scope): array public function processNode(Node $node, Scope $scope): array
{ {
if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return []; return [];
} }

View File

@@ -0,0 +1,30 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Deprecations;
use PHPStan\Analyser\Scope;
final class DefaultDeprecatedScopeResolver implements DeprecatedScopeResolver
{
public function isScopeDeprecated(Scope $scope): bool
{
$class = $scope->getClassReflection();
if ($class !== null && $class->isDeprecated()) {
return true;
}
$trait = $scope->getTraitReflection();
if ($trait !== null && $trait->isDeprecated()) {
return true;
}
$function = $scope->getFunction();
if ($function !== null && $function->isDeprecated()->yes()) {
return true;
}
return false;
}
}

View File

@@ -7,21 +7,23 @@ use PHPStan\Analyser\Scope;
class DeprecatedScopeHelper class DeprecatedScopeHelper
{ {
public static function isScopeDeprecated(Scope $scope): bool /** @var DeprecatedScopeResolver[] */
private $resolvers;
/**
* @param DeprecatedScopeResolver[] $checkers
*/
public function __construct(array $checkers)
{ {
$class = $scope->getClassReflection(); $this->resolvers = $checkers;
if ($class !== null && $class->isDeprecated()) { }
return true;
}
$trait = $scope->getTraitReflection(); public function isScopeDeprecated(Scope $scope): bool
if ($trait !== null && $trait->isDeprecated()) { {
return true; foreach ($this->resolvers as $checker) {
} if ($checker->isScopeDeprecated($scope)) {
return true;
$function = $scope->getFunction(); }
if ($function !== null && $function->isDeprecated()->yes()) {
return true;
} }
return false; return false;

View File

@@ -0,0 +1,27 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Deprecations;
use PHPStan\Analyser\Scope;
/**
* This is the interface for custom deprecated scope resolvers.
*
* To register it in the configuration file use the `phpstan.deprecations.deprecatedScopeResolver` service tag:
*
* ```
* services:
* -
* class: App\PHPStan\MyExtension
* tags:
* - phpstan.deprecations.deprecatedScopeResolver
* ```
*
* @api
*/
interface DeprecatedScopeResolver
{
public function isScopeDeprecated(Scope $scope): bool;
}

View File

@@ -28,10 +28,14 @@ class FetchingClassConstOfDeprecatedClassRule implements Rule
/** @var RuleLevelHelper */ /** @var RuleLevelHelper */
private $ruleLevelHelper; private $ruleLevelHelper;
public function __construct(ReflectionProvider $reflectionProvider, RuleLevelHelper $ruleLevelHelper) /** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(ReflectionProvider $reflectionProvider, RuleLevelHelper $ruleLevelHelper, DeprecatedScopeHelper $deprecatedScopeHelper)
{ {
$this->reflectionProvider = $reflectionProvider; $this->reflectionProvider = $reflectionProvider;
$this->ruleLevelHelper = $ruleLevelHelper; $this->ruleLevelHelper = $ruleLevelHelper;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
} }
public function getNodeType(): string public function getNodeType(): string
@@ -41,7 +45,7 @@ class FetchingClassConstOfDeprecatedClassRule implements Rule
public function processNode(Node $node, Scope $scope): array public function processNode(Node $node, Scope $scope): array
{ {
if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return []; return [];
} }

View File

@@ -19,12 +19,16 @@ class FetchingDeprecatedConstRule implements Rule
/** @var ReflectionProvider */ /** @var ReflectionProvider */
private $reflectionProvider; private $reflectionProvider;
/** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
/** @var array<string,string> */ /** @var array<string,string> */
private $deprecatedConstants = []; private $deprecatedConstants = [];
public function __construct(ReflectionProvider $reflectionProvider) public function __construct(ReflectionProvider $reflectionProvider, DeprecatedScopeHelper $deprecatedScopeHelper)
{ {
$this->reflectionProvider = $reflectionProvider; $this->reflectionProvider = $reflectionProvider;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
// phpcs:ignore SlevomatCodingStandard.ControlStructures.EarlyExit.EarlyExitNotUsed // phpcs:ignore SlevomatCodingStandard.ControlStructures.EarlyExit.EarlyExitNotUsed
if (PHP_VERSION_ID >= 70300) { if (PHP_VERSION_ID >= 70300) {
@@ -40,7 +44,7 @@ class FetchingDeprecatedConstRule implements Rule
public function processNode(Node $node, Scope $scope): array public function processNode(Node $node, Scope $scope): array
{ {
if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return []; return [];
} }

View File

@@ -19,9 +19,13 @@ class ImplementationOfDeprecatedInterfaceRule implements Rule
/** @var ReflectionProvider */ /** @var ReflectionProvider */
private $reflectionProvider; private $reflectionProvider;
public function __construct(ReflectionProvider $reflectionProvider) /** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(ReflectionProvider $reflectionProvider, DeprecatedScopeHelper $deprecatedScopeHelper)
{ {
$this->reflectionProvider = $reflectionProvider; $this->reflectionProvider = $reflectionProvider;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
} }
public function getNodeType(): string public function getNodeType(): string
@@ -31,7 +35,7 @@ class ImplementationOfDeprecatedInterfaceRule implements Rule
public function processNode(Node $node, Scope $scope): array public function processNode(Node $node, Scope $scope): array
{ {
if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return []; return [];
} }

View File

@@ -19,9 +19,13 @@ class InheritanceOfDeprecatedClassRule implements Rule
/** @var ReflectionProvider */ /** @var ReflectionProvider */
private $reflectionProvider; private $reflectionProvider;
public function __construct(ReflectionProvider $reflectionProvider) /** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(ReflectionProvider $reflectionProvider, DeprecatedScopeHelper $deprecatedScopeHelper)
{ {
$this->reflectionProvider = $reflectionProvider; $this->reflectionProvider = $reflectionProvider;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
} }
public function getNodeType(): string public function getNodeType(): string
@@ -31,7 +35,7 @@ class InheritanceOfDeprecatedClassRule implements Rule
public function processNode(Node $node, Scope $scope): array public function processNode(Node $node, Scope $scope): array
{ {
if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return []; return [];
} }

View File

@@ -26,10 +26,14 @@ class InstantiationOfDeprecatedClassRule implements Rule
/** @var RuleLevelHelper */ /** @var RuleLevelHelper */
private $ruleLevelHelper; private $ruleLevelHelper;
public function __construct(ReflectionProvider $reflectionProvider, RuleLevelHelper $ruleLevelHelper) /** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(ReflectionProvider $reflectionProvider, RuleLevelHelper $ruleLevelHelper, DeprecatedScopeHelper $deprecatedScopeHelper)
{ {
$this->reflectionProvider = $reflectionProvider; $this->reflectionProvider = $reflectionProvider;
$this->ruleLevelHelper = $ruleLevelHelper; $this->ruleLevelHelper = $ruleLevelHelper;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
} }
public function getNodeType(): string public function getNodeType(): string
@@ -39,7 +43,7 @@ class InstantiationOfDeprecatedClassRule implements Rule
public function processNode(Node $node, Scope $scope): array public function processNode(Node $node, Scope $scope): array
{ {
if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return []; return [];
} }

View File

@@ -18,9 +18,13 @@ class TypeHintDeprecatedInClassMethodSignatureRule implements Rule
/** @var DeprecatedClassHelper */ /** @var DeprecatedClassHelper */
private $deprecatedClassHelper; private $deprecatedClassHelper;
public function __construct(DeprecatedClassHelper $deprecatedClassHelper) /** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(DeprecatedClassHelper $deprecatedClassHelper, DeprecatedScopeHelper $deprecatedScopeHelper)
{ {
$this->deprecatedClassHelper = $deprecatedClassHelper; $this->deprecatedClassHelper = $deprecatedClassHelper;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
} }
public function getNodeType(): string public function getNodeType(): string
@@ -30,7 +34,7 @@ class TypeHintDeprecatedInClassMethodSignatureRule implements Rule
public function processNode(Node $node, Scope $scope): array public function processNode(Node $node, Scope $scope): array
{ {
if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return []; return [];
} }

View File

@@ -18,9 +18,13 @@ class TypeHintDeprecatedInClosureSignatureRule implements Rule
/** @var DeprecatedClassHelper */ /** @var DeprecatedClassHelper */
private $deprecatedClassHelper; private $deprecatedClassHelper;
public function __construct(DeprecatedClassHelper $deprecatedClassHelper) /** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(DeprecatedClassHelper $deprecatedClassHelper, DeprecatedScopeHelper $deprecatedScopeHelper)
{ {
$this->deprecatedClassHelper = $deprecatedClassHelper; $this->deprecatedClassHelper = $deprecatedClassHelper;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
} }
public function getNodeType(): string public function getNodeType(): string
@@ -30,7 +34,7 @@ class TypeHintDeprecatedInClosureSignatureRule implements Rule
public function processNode(Node $node, Scope $scope): array public function processNode(Node $node, Scope $scope): array
{ {
if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return []; return [];
} }

View File

@@ -19,9 +19,13 @@ class TypeHintDeprecatedInFunctionSignatureRule implements Rule
/** @var DeprecatedClassHelper */ /** @var DeprecatedClassHelper */
private $deprecatedClassHelper; private $deprecatedClassHelper;
public function __construct(DeprecatedClassHelper $deprecatedClassHelper) /** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(DeprecatedClassHelper $deprecatedClassHelper, DeprecatedScopeHelper $deprecatedScopeHelper)
{ {
$this->deprecatedClassHelper = $deprecatedClassHelper; $this->deprecatedClassHelper = $deprecatedClassHelper;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
} }
public function getNodeType(): string public function getNodeType(): string
@@ -31,7 +35,7 @@ class TypeHintDeprecatedInFunctionSignatureRule implements Rule
public function processNode(Node $node, Scope $scope): array public function processNode(Node $node, Scope $scope): array
{ {
if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return []; return [];
} }

View File

@@ -14,6 +14,14 @@ use function sprintf;
class UsageOfDeprecatedCastRule implements Rule class UsageOfDeprecatedCastRule implements Rule
{ {
/** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(DeprecatedScopeHelper $deprecatedScopeHelper)
{
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
}
public function getNodeType(): string public function getNodeType(): string
{ {
return Cast::class; return Cast::class;
@@ -21,7 +29,7 @@ class UsageOfDeprecatedCastRule implements Rule
public function processNode(Node $node, Scope $scope): array public function processNode(Node $node, Scope $scope): array
{ {
if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return []; return [];
} }

View File

@@ -20,9 +20,13 @@ class UsageOfDeprecatedTraitRule implements Rule
/** @var ReflectionProvider */ /** @var ReflectionProvider */
private $reflectionProvider; private $reflectionProvider;
public function __construct(ReflectionProvider $reflectionProvider) /** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(ReflectionProvider $reflectionProvider, DeprecatedScopeHelper $deprecatedScopeHelper)
{ {
$this->reflectionProvider = $reflectionProvider; $this->reflectionProvider = $reflectionProvider;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
} }
public function getNodeType(): string public function getNodeType(): string
@@ -32,7 +36,7 @@ class UsageOfDeprecatedTraitRule implements Rule
public function processNode(Node $node, Scope $scope): array public function processNode(Node $node, Scope $scope): array
{ {
if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return []; return [];
} }

Binary file not shown.

View File

@@ -1,16 +1,16 @@
-----BEGIN PGP SIGNATURE----- -----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEynwsejDI6OEnSoR2UcZzBf/C5cAFAmS32poACgkQUcZzBf/C iQIzBAABCgAdFiEEynwsejDI6OEnSoR2UcZzBf/C5cAFAmTaKt8ACgkQUcZzBf/C
5cCvmg/+JJmyX663fa+FHy7ED2SexVuChivpbp82dyLx1gRAl15rtNG4zjxNRfnW 5cBjcA//TOyzijQKOpxHJ73Y0F9j5169FDZE95exCWDYxOLkFOr8V/lvjZhXESqh
6GpsysMhKqrN7p6xur18ZkLqdFKAjeNnpTunnh/ADetcrs8wzLNyAy7luQtyXAuj g5qSn93q4BjAq60pjocZe/sBHxPpyxVLmvWzZcwozP0fauZABsPAXuhPrGtuBn7Q
SOv5f/Yitg9yvZ2GHrbzchQuSjkbUR2KroBYsRhwVTH7pMIgdvysRBYiENfbz350 v7ykPPycayBUiCNNcUi00x5d9+5V4Fvd3URDg/eC/rpBb7O3mA2UWcQrR+bx178z
n91WOCApDnVCygzEhBbhkwA/xklJnUxkRJX3AlbbCwES9K64ELyGd0BqJ1Ohy2a7 v91dnztyti8U8PL4ol+BZr56g7mm75wy/oFhDgr4h4xtmH6RzDiCa3DUyKyNqUIG
4cFjwRJq9/tXf99fyncamN8xyBdvYBXSNRNMPYcjKqKIZCOePlR8Q3b7nt154w+e KqAILtxhcSYRFoDWlakwKGY6lGQrrcrcwKZL+d9yEdXxrgsV0qw5y58b3Tmz39vR
w2qnAevOB4dYzJaSjwJlaVQYR1YIQ7NlYkGboONq/lrtJlEejDdiRmGvgHZ8nSYW A2CapzNmpuUaSIH7jjdiFak6fAKwKsgZysKRilbMLoON2AS+NZmezqMsX2invrPl
Ob2JwqgYDfUPfsnXAwXM+whpUNJi30MDB7MSw3SiDlyw690HheT/DCKOJ9yNUiOB QgURzFJZ2iP2i+83Z02nIB3DiHAZOapQwBEfqhdPq6yG5SNFh5ZvLsSPbbEI2jRL
TSGkbIGW/ASett78gowjwniYdryE5ufUPwZbkSaFC3CDysHfs6Jgc+lxe3wnOHtD b29ehUYag3ccxe7tvU2nwOWljMg6zKKAVFTxyGRQ7PW5P7FFxYZ6KCW+25wFj2/d
WyPl1TqDRNuLOZ26TgxI3gGEYqMcVDYQfmuiOakoebHx6j0bpvyEaP51j0/JFpu6 sXfOAnr+TWmftNkCs8HFkKV2EyxPcslHk3hKfBFh+3GqL1UtcvQdM0NxfwQmklG3
okKulXgC1DUluKFWMPhobPQRZ8zC29macnU74JvmJIiUhfiP2Pl16D+XcjFW++zH FZ5J+P7UmbZhqXdNIXXtxUa9N7pnEJ1b9sL8DpXd0lCSqjiHwH+euXauouiVcLXd
EDEghcCdgz0pIF6UI5j02rbNAfu7Oo685pnYeXq0DexgXjqoFOE= jl2N0U5M/Qc8tIfeGCxEYm81wTzLi44XcHv62yPqST3UzZ0jYEI=
=NF4z =jF08
-----END PGP SIGNATURE----- -----END PGP SIGNATURE-----

View File

@@ -39,6 +39,9 @@
"symfony/console": "^4.1.6 || ^5.0 || ^6.0", "symfony/console": "^4.1.6 || ^5.0 || ^6.0",
"symfony/filesystem": "^5.4 || ^6.0" "symfony/filesystem": "^5.4 || ^6.0"
}, },
"conflict": {
"nikic/php-parser": "4.17.0"
},
"provide": { "provide": {
"psalm/psalm": "self.version" "psalm/psalm": "self.version"
}, },

View File

@@ -1679,10 +1679,10 @@ return [
'DOMDocument::getElementsByTagName' => ['DOMNodeList', 'qualifiedName'=>'string'], 'DOMDocument::getElementsByTagName' => ['DOMNodeList', 'qualifiedName'=>'string'],
'DOMDocument::getElementsByTagNameNS' => ['DOMNodeList', 'namespace'=>'?string', 'localName'=>'string'], 'DOMDocument::getElementsByTagNameNS' => ['DOMNodeList', 'namespace'=>'?string', 'localName'=>'string'],
'DOMDocument::importNode' => ['DOMNode|false', 'node'=>'DOMNode', 'deep='=>'bool'], 'DOMDocument::importNode' => ['DOMNode|false', 'node'=>'DOMNode', 'deep='=>'bool'],
'DOMDocument::load' => ['DOMDocument|bool', 'filename'=>'string', 'options='=>'int'], 'DOMDocument::load' => ['bool', 'filename'=>'string', 'options='=>'int'],
'DOMDocument::loadHTML' => ['bool', 'source'=>'non-empty-string', 'options='=>'int'], 'DOMDocument::loadHTML' => ['bool', 'source'=>'non-empty-string', 'options='=>'int'],
'DOMDocument::loadHTMLFile' => ['bool', 'filename'=>'string', 'options='=>'int'], 'DOMDocument::loadHTMLFile' => ['bool', 'filename'=>'string', 'options='=>'int'],
'DOMDocument::loadXML' => ['DOMDocument|bool', 'source'=>'non-empty-string', 'options='=>'int'], 'DOMDocument::loadXML' => ['bool', 'source'=>'non-empty-string', 'options='=>'int'],
'DOMDocument::normalizeDocument' => ['void'], 'DOMDocument::normalizeDocument' => ['void'],
'DOMDocument::registerNodeClass' => ['bool', 'baseClass'=>'string', 'extendedClass'=>'?string'], 'DOMDocument::registerNodeClass' => ['bool', 'baseClass'=>'string', 'extendedClass'=>'?string'],
'DOMDocument::relaxNGValidate' => ['bool', 'filename'=>'string'], 'DOMDocument::relaxNGValidate' => ['bool', 'filename'=>'string'],
@@ -7825,10 +7825,10 @@ return [
'mysqli::begin_transaction' => ['bool', 'flags='=>'int', 'name='=>'?string'], 'mysqli::begin_transaction' => ['bool', 'flags='=>'int', 'name='=>'?string'],
'mysqli::change_user' => ['bool', 'username'=>'string', 'password'=>'string', 'database'=>'?string'], 'mysqli::change_user' => ['bool', 'username'=>'string', 'password'=>'string', 'database'=>'?string'],
'mysqli::character_set_name' => ['string'], 'mysqli::character_set_name' => ['string'],
'mysqli::close' => ['bool'], 'mysqli::close' => ['true'],
'mysqli::commit' => ['bool', 'flags='=>'int', 'name='=>'?string'], 'mysqli::commit' => ['bool', 'flags='=>'int', 'name='=>'?string'],
'mysqli::connect' => ['bool', 'hostname='=>'string|null', 'username='=>'string|null', 'password='=>'string|null', 'database='=>'string|null', 'port='=>'int|null', 'socket='=>'string|null'], 'mysqli::connect' => ['bool', 'hostname='=>'string|null', 'username='=>'string|null', 'password='=>'string|null', 'database='=>'string|null', 'port='=>'int|null', 'socket='=>'string|null'],
'mysqli::debug' => ['bool', 'options'=>'string'], 'mysqli::debug' => ['true', 'options'=>'string'],
'mysqli::dump_debug_info' => ['bool'], 'mysqli::dump_debug_info' => ['bool'],
'mysqli::escape_string' => ['string', 'string'=>'string'], 'mysqli::escape_string' => ['string', 'string'=>'string'],
'mysqli::execute_query' => ['mysqli_result|bool', 'query'=>'non-empty-string', 'params='=>'list<mixed>|null'], 'mysqli::execute_query' => ['mysqli_result|bool', 'query'=>'non-empty-string', 'params='=>'list<mixed>|null'],
@@ -7857,7 +7857,7 @@ return [
'mysqli::select_db' => ['bool', 'database'=>'string'], 'mysqli::select_db' => ['bool', 'database'=>'string'],
'mysqli::set_charset' => ['bool', 'charset'=>'string'], 'mysqli::set_charset' => ['bool', 'charset'=>'string'],
'mysqli::set_opt' => ['bool', 'option'=>'int', 'value'=>'string|int'], 'mysqli::set_opt' => ['bool', 'option'=>'int', 'value'=>'string|int'],
'mysqli::ssl_set' => ['bool', 'key'=>'?string', 'certificate'=>'?string', 'ca_certificate'=>'?string', 'ca_path'=>'?string', 'cipher_algos'=>'?string'], 'mysqli::ssl_set' => ['true', 'key'=>'?string', 'certificate'=>'?string', 'ca_certificate'=>'?string', 'ca_path'=>'?string', 'cipher_algos'=>'?string'],
'mysqli::stat' => ['string|false'], 'mysqli::stat' => ['string|false'],
'mysqli::stmt_init' => ['mysqli_stmt'], 'mysqli::stmt_init' => ['mysqli_stmt'],
'mysqli::store_result' => ['mysqli_result|false', 'mode='=>'int'], 'mysqli::store_result' => ['mysqli_result|false', 'mode='=>'int'],
@@ -7903,7 +7903,7 @@ return [
'mysqli_fetch_object' => ['object|false|null', 'result'=>'mysqli_result', 'class='=>'string', 'constructor_args='=>'array'], 'mysqli_fetch_object' => ['object|false|null', 'result'=>'mysqli_result', 'class='=>'string', 'constructor_args='=>'array'],
'mysqli_fetch_row' => ['list<null|int|float|string>|false|null', 'result'=>'mysqli_result'], 'mysqli_fetch_row' => ['list<null|int|float|string>|false|null', 'result'=>'mysqli_result'],
'mysqli_field_count' => ['int', 'mysql'=>'mysqli'], 'mysqli_field_count' => ['int', 'mysql'=>'mysqli'],
'mysqli_field_seek' => ['bool', 'result'=>'mysqli_result', 'index'=>'int'], 'mysqli_field_seek' => ['true', 'result'=>'mysqli_result', 'index'=>'int'],
'mysqli_field_tell' => ['int', 'result'=>'mysqli_result'], 'mysqli_field_tell' => ['int', 'result'=>'mysqli_result'],
'mysqli_free_result' => ['void', 'result'=>'mysqli_result'], 'mysqli_free_result' => ['void', 'result'=>'mysqli_result'],
'mysqli_get_cache_stats' => ['array|false'], 'mysqli_get_cache_stats' => ['array|false'],
@@ -7957,7 +7957,7 @@ return [
'mysqli_result::fetch_fields' => ['list<object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}>'], 'mysqli_result::fetch_fields' => ['list<object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}>'],
'mysqli_result::fetch_object' => ['object|false|null', 'class='=>'string', 'constructor_args='=>'array'], 'mysqli_result::fetch_object' => ['object|false|null', 'class='=>'string', 'constructor_args='=>'array'],
'mysqli_result::fetch_row' => ['list<null|int|float|string>|false|null'], 'mysqli_result::fetch_row' => ['list<null|int|float|string>|false|null'],
'mysqli_result::field_seek' => ['bool', 'index'=>'int'], 'mysqli_result::field_seek' => ['true', 'index'=>'int'],
'mysqli_result::free' => ['void'], 'mysqli_result::free' => ['void'],
'mysqli_result::free_result' => ['void'], 'mysqli_result::free_result' => ['void'],
'mysqli_rollback' => ['bool', 'mysql'=>'mysqli', 'flags='=>'int', 'name='=>'?string'], 'mysqli_rollback' => ['bool', 'mysql'=>'mysqli', 'flags='=>'int', 'name='=>'?string'],
@@ -7981,7 +7981,7 @@ return [
'mysqli_stmt::attr_set' => ['bool', 'attribute'=>'int', 'value'=>'int'], 'mysqli_stmt::attr_set' => ['bool', 'attribute'=>'int', 'value'=>'int'],
'mysqli_stmt::bind_param' => ['bool', 'types'=>'string', '&var'=>'mixed', '&...vars='=>'mixed'], 'mysqli_stmt::bind_param' => ['bool', 'types'=>'string', '&var'=>'mixed', '&...vars='=>'mixed'],
'mysqli_stmt::bind_result' => ['bool', '&w_var1'=>'', '&...w_vars='=>''], 'mysqli_stmt::bind_result' => ['bool', '&w_var1'=>'', '&...w_vars='=>''],
'mysqli_stmt::close' => ['bool'], 'mysqli_stmt::close' => ['true'],
'mysqli_stmt::data_seek' => ['void', 'offset'=>'int'], 'mysqli_stmt::data_seek' => ['void', 'offset'=>'int'],
'mysqli_stmt::execute' => ['bool', 'params='=>'list<mixed>|null'], 'mysqli_stmt::execute' => ['bool', 'params='=>'list<mixed>|null'],
'mysqli_stmt::fetch' => ['bool|null'], 'mysqli_stmt::fetch' => ['bool|null'],

View File

@@ -100,6 +100,22 @@ return [
'old' => ['DOMNodeList', 'namespace'=>'string', 'localName'=>'string'], 'old' => ['DOMNodeList', 'namespace'=>'string', 'localName'=>'string'],
'new' => ['DOMNodeList', 'namespace'=>'?string', 'localName'=>'string'], 'new' => ['DOMNodeList', 'namespace'=>'?string', 'localName'=>'string'],
], ],
'DOMDocument::load' => [
'old' => ['DOMDocument|bool', 'filename'=>'string', 'options='=>'int'],
'new' => ['bool', 'filename'=>'string', 'options='=>'int'],
],
'DOMDocument::loadXML' => [
'old' => ['DOMDocument|bool', 'source'=>'non-empty-string', 'options='=>'int'],
'new' => ['bool', 'source'=>'non-empty-string', 'options='=>'int'],
],
'DOMDocument::loadHTML' => [
'old' => ['DOMDocument|bool', 'source'=>'non-empty-string', 'options='=>'int'],
'new' => ['bool', 'source'=>'non-empty-string', 'options='=>'int'],
],
'DOMDocument::loadHTMLFile' => [
'old' => ['DOMDocument|bool', 'filename'=>'string', 'options='=>'int'],
'new' => ['bool', 'filename'=>'string', 'options='=>'int'],
],
'DOMImplementation::createDocument' => [ 'DOMImplementation::createDocument' => [
'old' => ['DOMDocument|false', 'namespace='=>'string', 'qualifiedName='=>'string', 'doctype='=>'DOMDocumentType'], 'old' => ['DOMDocument|false', 'namespace='=>'string', 'qualifiedName='=>'string', 'doctype='=>'DOMDocumentType'],
'new' => ['DOMDocument|false', 'namespace='=>'?string', 'qualifiedName='=>'string', 'doctype='=>'?DOMDocumentType'], 'new' => ['DOMDocument|false', 'namespace='=>'?string', 'qualifiedName='=>'string', 'doctype='=>'?DOMDocumentType'],
@@ -224,6 +240,14 @@ return [
'old' => ['string', 'locale'=>'string', 'displayLocale='=>'string'], 'old' => ['string', 'locale'=>'string', 'displayLocale='=>'string'],
'new' => ['string', 'locale'=>'string', 'displayLocale='=>'?string'], 'new' => ['string', 'locale'=>'string', 'displayLocale='=>'?string'],
], ],
'mysqli_field_seek' => [
'old' => ['bool', 'result'=>'mysqli_result', 'index'=>'int'],
'new' => ['true', 'result'=>'mysqli_result', 'index'=>'int'],
],
'mysqli_result::field_seek' => [
'old' => ['bool', 'index'=>'int'],
'new' => ['true', 'index'=>'int'],
],
'mysqli_stmt::__construct' => [ 'mysqli_stmt::__construct' => [
'old' => ['void', 'mysql'=>'mysqli', 'query='=>'string'], 'old' => ['void', 'mysql'=>'mysqli', 'query='=>'string'],
'new' => ['void', 'mysql'=>'mysqli', 'query='=>'?string'], 'new' => ['void', 'mysql'=>'mysqli', 'query='=>'?string'],

View File

@@ -94,6 +94,10 @@ return [
'old' => ['int|false', 'fields'=>'array<array-key, null|scalar|Stringable>', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'], 'old' => ['int|false', 'fields'=>'array<array-key, null|scalar|Stringable>', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'],
'new' => ['int|false', 'fields'=>'array<array-key, null|scalar|Stringable>', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string', 'eol='=>'string'], 'new' => ['int|false', 'fields'=>'array<array-key, null|scalar|Stringable>', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string', 'eol='=>'string'],
], ],
'hash_pbkdf2' => [
'old' => ['non-empty-string', 'algo'=>'string', 'password'=>'string', 'salt'=>'string', 'iterations'=>'int', 'length='=>'int', 'binary='=>'bool'],
'new' => ['non-empty-string', 'algo'=>'string', 'password'=>'string', 'salt'=>'string', 'iterations'=>'int', 'length='=>'int', 'binary='=>'bool', 'options=' => 'array'],
],
'finfo_buffer' => [ 'finfo_buffer' => [
'old' => ['string|false', 'finfo'=>'resource', 'string'=>'string', 'flags='=>'int', 'context='=>'resource'], 'old' => ['string|false', 'finfo'=>'resource', 'string'=>'string', 'flags='=>'int', 'context='=>'resource'],
'new' => ['string|false', 'finfo'=>'finfo', 'string'=>'string', 'flags='=>'int', 'context='=>'resource'], 'new' => ['string|false', 'finfo'=>'finfo', 'string'=>'string', 'flags='=>'int', 'context='=>'resource'],

View File

@@ -49,10 +49,6 @@ return [
'old' => ['bool', '&rw_array'=>'array', 'flags='=>'int'], 'old' => ['bool', '&rw_array'=>'array', 'flags='=>'int'],
'new' => ['true', '&rw_array'=>'array', 'flags='=>'int'], 'new' => ['true', '&rw_array'=>'array', 'flags='=>'int'],
], ],
'hash_pbkdf2' => [
'old' => ['non-empty-string', 'algo'=>'string', 'password'=>'string', 'salt'=>'string', 'iterations'=>'int', 'length='=>'int', 'binary='=>'bool'],
'new' => ['non-empty-string', 'algo'=>'string', 'password'=>'string', 'salt'=>'string', 'iterations'=>'int', 'length='=>'int', 'binary='=>'bool', 'options=' => 'array'],
],
'imap_setflag_full' => [ 'imap_setflag_full' => [
'old' => ['bool', 'imap'=>'IMAP\Connection', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'], 'old' => ['bool', 'imap'=>'IMAP\Connection', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'],
'new' => ['true', 'imap'=>'IMAP\Connection', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'], 'new' => ['true', 'imap'=>'IMAP\Connection', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'],

View File

@@ -733,8 +733,8 @@ return [
'DOMDocument::getElementsByTagNameNS' => ['DOMNodeList', 'namespace'=>'string', 'localName'=>'string'], 'DOMDocument::getElementsByTagNameNS' => ['DOMNodeList', 'namespace'=>'string', 'localName'=>'string'],
'DOMDocument::importNode' => ['DOMNode|false', 'node'=>'DOMNode', 'deep='=>'bool'], 'DOMDocument::importNode' => ['DOMNode|false', 'node'=>'DOMNode', 'deep='=>'bool'],
'DOMDocument::load' => ['DOMDocument|bool', 'filename'=>'string', 'options='=>'int'], 'DOMDocument::load' => ['DOMDocument|bool', 'filename'=>'string', 'options='=>'int'],
'DOMDocument::loadHTML' => ['bool', 'source'=>'non-empty-string', 'options='=>'int'], 'DOMDocument::loadHTML' => ['DOMDocument|bool', 'source'=>'non-empty-string', 'options='=>'int'],
'DOMDocument::loadHTMLFile' => ['bool', 'filename'=>'string', 'options='=>'int'], 'DOMDocument::loadHTMLFile' => ['DOMDocument|bool', 'filename'=>'string', 'options='=>'int'],
'DOMDocument::loadXML' => ['DOMDocument|bool', 'source'=>'non-empty-string', 'options='=>'int'], 'DOMDocument::loadXML' => ['DOMDocument|bool', 'source'=>'non-empty-string', 'options='=>'int'],
'DOMDocument::normalizeDocument' => ['void'], 'DOMDocument::normalizeDocument' => ['void'],
'DOMDocument::registerNodeClass' => ['bool', 'baseClass'=>'string', 'extendedClass'=>'?string'], 'DOMDocument::registerNodeClass' => ['bool', 'baseClass'=>'string', 'extendedClass'=>'?string'],
@@ -12737,10 +12737,10 @@ return [
'mysqli::begin_transaction' => ['bool', 'flags='=>'int', 'name='=>'string'], 'mysqli::begin_transaction' => ['bool', 'flags='=>'int', 'name='=>'string'],
'mysqli::change_user' => ['bool', 'username'=>'string', 'password'=>'string', 'database'=>'?string'], 'mysqli::change_user' => ['bool', 'username'=>'string', 'password'=>'string', 'database'=>'?string'],
'mysqli::character_set_name' => ['string'], 'mysqli::character_set_name' => ['string'],
'mysqli::close' => ['bool'], 'mysqli::close' => ['true'],
'mysqli::commit' => ['bool', 'flags='=>'int', 'name='=>'string'], 'mysqli::commit' => ['bool', 'flags='=>'int', 'name='=>'string'],
'mysqli::connect' => ['null|false', 'hostname='=>'string', 'username='=>'string', 'password='=>'string', 'database='=>'string', 'port='=>'int', 'socket='=>'string'], 'mysqli::connect' => ['null|false', 'hostname='=>'string', 'username='=>'string', 'password='=>'string', 'database='=>'string', 'port='=>'int', 'socket='=>'string'],
'mysqli::debug' => ['bool', 'options'=>'string'], 'mysqli::debug' => ['true', 'options'=>'string'],
'mysqli::dump_debug_info' => ['bool'], 'mysqli::dump_debug_info' => ['bool'],
'mysqli::escape_string' => ['string', 'string'=>'string'], 'mysqli::escape_string' => ['string', 'string'=>'string'],
'mysqli::get_charset' => ['object'], 'mysqli::get_charset' => ['object'],
@@ -12768,7 +12768,7 @@ return [
'mysqli::select_db' => ['bool', 'database'=>'string'], 'mysqli::select_db' => ['bool', 'database'=>'string'],
'mysqli::set_charset' => ['bool', 'charset'=>'string'], 'mysqli::set_charset' => ['bool', 'charset'=>'string'],
'mysqli::set_opt' => ['bool', 'option'=>'int', 'value'=>'string|int'], 'mysqli::set_opt' => ['bool', 'option'=>'int', 'value'=>'string|int'],
'mysqli::ssl_set' => ['bool', 'key'=>'?string', 'certificate'=>'?string', 'ca_certificate'=>'?string', 'ca_path'=>'?string', 'cipher_algos'=>'?string'], 'mysqli::ssl_set' => ['true', 'key'=>'?string', 'certificate'=>'?string', 'ca_certificate'=>'?string', 'ca_path'=>'?string', 'cipher_algos'=>'?string'],
'mysqli::stat' => ['string|false'], 'mysqli::stat' => ['string|false'],
'mysqli::stmt_init' => ['mysqli_stmt'], 'mysqli::stmt_init' => ['mysqli_stmt'],
'mysqli::store_result' => ['mysqli_result|false', 'mode='=>'int'], 'mysqli::store_result' => ['mysqli_result|false', 'mode='=>'int'],
@@ -12889,7 +12889,7 @@ return [
'mysqli_stmt::attr_set' => ['bool', 'attribute'=>'int', 'value'=>'int'], 'mysqli_stmt::attr_set' => ['bool', 'attribute'=>'int', 'value'=>'int'],
'mysqli_stmt::bind_param' => ['bool', 'types'=>'string', '&var'=>'mixed', '&...vars='=>'mixed'], 'mysqli_stmt::bind_param' => ['bool', 'types'=>'string', '&var'=>'mixed', '&...vars='=>'mixed'],
'mysqli_stmt::bind_result' => ['bool', '&w_var1'=>'', '&...w_vars='=>''], 'mysqli_stmt::bind_result' => ['bool', '&w_var1'=>'', '&...w_vars='=>''],
'mysqli_stmt::close' => ['bool'], 'mysqli_stmt::close' => ['true'],
'mysqli_stmt::data_seek' => ['void', 'offset'=>'int'], 'mysqli_stmt::data_seek' => ['void', 'offset'=>'int'],
'mysqli_stmt::execute' => ['bool'], 'mysqli_stmt::execute' => ['bool'],
'mysqli_stmt::fetch' => ['bool|null'], 'mysqli_stmt::fetch' => ['bool|null'],

View File

@@ -699,6 +699,7 @@ final class Codebase
); );
} }
/** @psalm-mutation-free */
public function classExtendsOrImplements(string $fq_class_name, string $possible_parent): bool public function classExtendsOrImplements(string $fq_class_name, string $possible_parent): bool
{ {
return $this->classlikes->classExtends($fq_class_name, $possible_parent) return $this->classlikes->classExtends($fq_class_name, $possible_parent)

View File

@@ -42,7 +42,6 @@ use Psalm\Progress\Progress;
use Psalm\Progress\VoidProgress; use Psalm\Progress\VoidProgress;
use RuntimeException; use RuntimeException;
use SimpleXMLElement; use SimpleXMLElement;
use SimpleXMLIterator;
use Symfony\Component\Filesystem\Path; use Symfony\Component\Filesystem\Path;
use Throwable; use Throwable;
use UnexpectedValueException; use UnexpectedValueException;
@@ -728,8 +727,6 @@ class Config
$this->eventDispatcher = new EventDispatcher(); $this->eventDispatcher = new EventDispatcher();
$this->universal_object_crates = [ $this->universal_object_crates = [
strtolower(stdClass::class), strtolower(stdClass::class),
strtolower(SimpleXMLElement::class),
strtolower(SimpleXMLIterator::class),
]; ];
} }
@@ -1030,7 +1027,6 @@ class Config
/** /**
* @param non-empty-string $file_contents * @param non-empty-string $file_contents
* @psalm-suppress MixedMethodCall
* @psalm-suppress MixedAssignment * @psalm-suppress MixedAssignment
* @psalm-suppress MixedArgument * @psalm-suppress MixedArgument
* @psalm-suppress MixedPropertyFetch * @psalm-suppress MixedPropertyFetch
@@ -1161,12 +1157,13 @@ class Config
} }
if (isset($config_xml['autoloader'])) { if (isset($config_xml['autoloader'])) {
$autoloader_path = $config->base_dir . DIRECTORY_SEPARATOR . $config_xml['autoloader']; $autoloader = (string) $config_xml['autoloader'];
$autoloader_path = $config->base_dir . DIRECTORY_SEPARATOR . $autoloader;
if (!file_exists($autoloader_path)) { if (!file_exists($autoloader_path)) {
// in here for legacy reasons where people put absolute paths but psalm resolved it relative // in here for legacy reasons where people put absolute paths but psalm resolved it relative
if ($config_xml['autoloader']->__toString()[0] === '/') { if ($autoloader[0] === '/') {
$autoloader_path = $config_xml['autoloader']->__toString(); $autoloader_path = $autoloader;
} }
if (!file_exists($autoloader_path)) { if (!file_exists($autoloader_path)) {
@@ -1312,7 +1309,7 @@ class Config
); );
} }
if (isset($config_xml->fileExtensions)) { if (isset($config_xml->fileExtensions->extension)) {
$config->file_extensions = []; $config->file_extensions = [];
$config->loadFileExtensions($config_xml->fileExtensions->extension); $config->loadFileExtensions($config_xml->fileExtensions->extension);
@@ -1336,7 +1333,6 @@ class Config
if (isset($config_xml->ignoreExceptions)) { if (isset($config_xml->ignoreExceptions)) {
if (isset($config_xml->ignoreExceptions->class)) { if (isset($config_xml->ignoreExceptions->class)) {
/** @var SimpleXMLElement $exception_class */
foreach ($config_xml->ignoreExceptions->class as $exception_class) { foreach ($config_xml->ignoreExceptions->class as $exception_class) {
$exception_name = (string) $exception_class['name']; $exception_name = (string) $exception_class['name'];
$global_attribute_text = (string) $exception_class['onlyGlobalScope']; $global_attribute_text = (string) $exception_class['onlyGlobalScope'];
@@ -1347,7 +1343,6 @@ class Config
} }
} }
if (isset($config_xml->ignoreExceptions->classAndDescendants)) { if (isset($config_xml->ignoreExceptions->classAndDescendants)) {
/** @var SimpleXMLElement $exception_class */
foreach ($config_xml->ignoreExceptions->classAndDescendants as $exception_class) { foreach ($config_xml->ignoreExceptions->classAndDescendants as $exception_class) {
$exception_name = (string) $exception_class['name']; $exception_name = (string) $exception_class['name'];
$global_attribute_text = (string) $exception_class['onlyGlobalScope']; $global_attribute_text = (string) $exception_class['onlyGlobalScope'];
@@ -1401,7 +1396,6 @@ class Config
// this plugin loading system borrows heavily from etsy/phan // this plugin loading system borrows heavily from etsy/phan
if (isset($config_xml->plugins)) { if (isset($config_xml->plugins)) {
if (isset($config_xml->plugins->plugin)) { if (isset($config_xml->plugins->plugin)) {
/** @var SimpleXMLElement $plugin */
foreach ($config_xml->plugins->plugin as $plugin) { foreach ($config_xml->plugins->plugin as $plugin) {
$plugin_file_name = (string) $plugin['filename']; $plugin_file_name = (string) $plugin['filename'];
@@ -1413,7 +1407,6 @@ class Config
} }
} }
if (isset($config_xml->plugins->pluginClass)) { if (isset($config_xml->plugins->pluginClass)) {
/** @var SimpleXMLElement $plugin */
foreach ($config_xml->plugins->pluginClass as $plugin) { foreach ($config_xml->plugins->pluginClass as $plugin) {
$plugin_class_name = $plugin['class']; $plugin_class_name = $plugin['class'];
// any child elements are used as plugin configuration // any child elements are used as plugin configuration
@@ -1429,21 +1422,23 @@ class Config
if (isset($config_xml->issueHandlers)) { if (isset($config_xml->issueHandlers)) {
foreach ($config_xml->issueHandlers as $issue_handlers) { foreach ($config_xml->issueHandlers as $issue_handlers) {
/** @var SimpleXMLElement $issue_handler */ $issue_handler_children = $issue_handlers->children();
foreach ($issue_handlers->children() as $key => $issue_handler) { if ($issue_handler_children) {
if ($key === 'PluginIssue') { foreach ($issue_handler_children as $key => $issue_handler) {
$custom_class_name = (string) $issue_handler['name']; if ($key === 'PluginIssue') {
/** @var string $key */ $custom_class_name = (string)$issue_handler['name'];
$config->issue_handlers[$custom_class_name] = IssueHandler::loadFromXMLElement( /** @var string $key */
$issue_handler, $config->issue_handlers[$custom_class_name] = IssueHandler::loadFromXMLElement(
$base_dir, $issue_handler,
); $base_dir,
} else { );
/** @var string $key */ } else {
$config->issue_handlers[$key] = IssueHandler::loadFromXMLElement( /** @var string $key */
$issue_handler, $config->issue_handlers[$key] = IssueHandler::loadFromXMLElement(
$base_dir, $issue_handler,
); $base_dir,
);
}
} }
} }
} }
@@ -2263,6 +2258,10 @@ class Config
$stubsDir . 'SPL.phpstub', $stubsDir . 'SPL.phpstub',
]; ];
if ($codebase->analysis_php_version_id >= 7_04_00) {
$this->internal_stubs[] = $stubsDir . 'Php74.phpstub';
}
if ($codebase->analysis_php_version_id >= 8_00_00) { if ($codebase->analysis_php_version_id >= 8_00_00) {
$this->internal_stubs[] = $stubsDir . 'CoreGenericAttributes.phpstub'; $this->internal_stubs[] = $stubsDir . 'CoreGenericAttributes.phpstub';
$this->internal_stubs[] = $stubsDir . 'Php80.phpstub'; $this->internal_stubs[] = $stubsDir . 'Php80.phpstub';

View File

@@ -389,7 +389,6 @@ class FileFilter
if ($e->directory) { if ($e->directory) {
$config['directory'] = []; $config['directory'] = [];
/** @var SimpleXMLElement $directory */
foreach ($e->directory as $directory) { foreach ($e->directory as $directory) {
$config['directory'][] = [ $config['directory'][] = [
'name' => (string) $directory['name'], 'name' => (string) $directory['name'],
@@ -402,7 +401,6 @@ class FileFilter
if ($e->file) { if ($e->file) {
$config['file'] = []; $config['file'] = [];
/** @var SimpleXMLElement $file */
foreach ($e->file as $file) { foreach ($e->file as $file) {
$config['file'][]['name'] = (string) $file['name']; $config['file'][]['name'] = (string) $file['name'];
} }
@@ -410,7 +408,6 @@ class FileFilter
if ($e->referencedClass) { if ($e->referencedClass) {
$config['referencedClass'] = []; $config['referencedClass'] = [];
/** @var SimpleXMLElement $referenced_class */
foreach ($e->referencedClass as $referenced_class) { foreach ($e->referencedClass as $referenced_class) {
$config['referencedClass'][]['name'] = strtolower((string)$referenced_class['name']); $config['referencedClass'][]['name'] = strtolower((string)$referenced_class['name']);
} }
@@ -418,7 +415,6 @@ class FileFilter
if ($e->referencedMethod) { if ($e->referencedMethod) {
$config['referencedMethod'] = []; $config['referencedMethod'] = [];
/** @var SimpleXMLElement $referenced_method */
foreach ($e->referencedMethod as $referenced_method) { foreach ($e->referencedMethod as $referenced_method) {
$config['referencedMethod'][]['name'] = (string)$referenced_method['name']; $config['referencedMethod'][]['name'] = (string)$referenced_method['name'];
} }
@@ -426,7 +422,6 @@ class FileFilter
if ($e->referencedFunction) { if ($e->referencedFunction) {
$config['referencedFunction'] = []; $config['referencedFunction'] = [];
/** @var SimpleXMLElement $referenced_function */
foreach ($e->referencedFunction as $referenced_function) { foreach ($e->referencedFunction as $referenced_function) {
$config['referencedFunction'][]['name'] = strtolower((string)$referenced_function['name']); $config['referencedFunction'][]['name'] = strtolower((string)$referenced_function['name']);
} }
@@ -434,7 +429,6 @@ class FileFilter
if ($e->referencedProperty) { if ($e->referencedProperty) {
$config['referencedProperty'] = []; $config['referencedProperty'] = [];
/** @var SimpleXMLElement $referenced_property */
foreach ($e->referencedProperty as $referenced_property) { foreach ($e->referencedProperty as $referenced_property) {
$config['referencedProperty'][]['name'] = strtolower((string)$referenced_property['name']); $config['referencedProperty'][]['name'] = strtolower((string)$referenced_property['name']);
} }
@@ -442,7 +436,6 @@ class FileFilter
if ($e->referencedConstant) { if ($e->referencedConstant) {
$config['referencedConstant'] = []; $config['referencedConstant'] = [];
/** @var SimpleXMLElement $referenced_constant */
foreach ($e->referencedConstant as $referenced_constant) { foreach ($e->referencedConstant as $referenced_constant) {
$config['referencedConstant'][]['name'] = strtolower((string)$referenced_constant['name']); $config['referencedConstant'][]['name'] = strtolower((string)$referenced_constant['name']);
} }
@@ -450,8 +443,6 @@ class FileFilter
if ($e->referencedVariable) { if ($e->referencedVariable) {
$config['referencedVariable'] = []; $config['referencedVariable'] = [];
/** @var SimpleXMLElement $referenced_variable */
foreach ($e->referencedVariable as $referenced_variable) { foreach ($e->referencedVariable as $referenced_variable) {
$config['referencedVariable'][]['name'] = strtolower((string)$referenced_variable['name']); $config['referencedVariable'][]['name'] = strtolower((string)$referenced_variable['name']);
} }

View File

@@ -38,9 +38,10 @@ final class IssueHandler
} }
} }
/** @var SimpleXMLElement $error_level */ if (isset($e->errorLevel)) {
foreach ($e->errorLevel as $error_level) { foreach ($e->errorLevel as $error_level) {
$handler->custom_levels[] = ErrorLevelFileFilter::loadFromXMLElement($error_level, $base_dir, true); $handler->custom_levels[] = ErrorLevelFileFilter::loadFromXMLElement($error_level, $base_dir, true);
}
} }
return $handler; return $handler;

View File

@@ -28,7 +28,6 @@ final class ProjectFileFilter extends FileFilter
throw new ConfigException('Cannot nest ignoreFiles inside itself'); throw new ConfigException('Cannot nest ignoreFiles inside itself');
} }
/** @var SimpleXMLElement $e->ignoreFiles */
$filter->file_filter = static::loadFromXMLElement($e->ignoreFiles, $base_dir, false); $filter->file_filter = static::loadFromXMLElement($e->ignoreFiles, $base_dir, false);
} }

View File

@@ -12,7 +12,8 @@ use Psalm\Internal\Scope\LoopScope;
use Psalm\Internal\Type\AssertionReconciler; use Psalm\Internal\Type\AssertionReconciler;
use Psalm\Storage\FunctionLikeStorage; use Psalm\Storage\FunctionLikeStorage;
use Psalm\Type\Atomic\DependentType; use Psalm\Type\Atomic\DependentType;
use Psalm\Type\Atomic\TArray; use Psalm\Type\Atomic\TIntRange;
use Psalm\Type\Atomic\TNull;
use Psalm\Type\Union; use Psalm\Type\Union;
use RuntimeException; use RuntimeException;
@@ -868,10 +869,19 @@ final class Context
public function defineGlobals(): void public function defineGlobals(): void
{ {
$globals = [ $globals = [
// not sure why this is declared here again, see VariableFetchAnalyzer
'$argv' => new Union([ '$argv' => new Union([
new TArray([Type::getInt(), Type::getString()]), Type::getNonEmptyListAtomic(Type::getString()),
new TNull(),
], [
'ignore_nullable_issues' => true,
]),
'$argc' => new Union([
new TIntRange(1, null),
new TNull(),
], [
'ignore_nullable_issues' => true,
]), ]),
'$argc' => Type::getInt(),
]; ];
$config = Config::getInstance(); $config = Config::getInstance();

View File

@@ -200,6 +200,10 @@ class ProjectAnalyzer
UnnecessaryVarAnnotation::class, UnnecessaryVarAnnotation::class,
]; ];
private const PHP_VERSION_REGEX = '^(0|[1-9]\d*)\.(0|[1-9]\d*)(?:\..*)?$';
private const PHP_SUPPORTED_VERSIONS_REGEX = '^(5\.[456]|7\.[01234]|8\.[0123])(\..*)?$';
/** /**
* @param array<ReportOptions> $generated_report_options * @param array<ReportOptions> $generated_report_options
*/ */
@@ -1179,8 +1183,16 @@ class ProjectAnalyzer
*/ */
public function setPhpVersion(string $version, string $source): void public function setPhpVersion(string $version, string $source): void
{ {
if (!preg_match('/^(5\.[456]|7\.[01234]|8\.[012])(\..*)?$/', $version)) { if (!preg_match('/' . self::PHP_VERSION_REGEX . '/', $version)) {
throw new UnexpectedValueException('Expecting a version number in the format x.y'); throw new UnexpectedValueException('Expecting a version number in the format x.y or x.y.z');
}
if (!preg_match('/' . self::PHP_SUPPORTED_VERSIONS_REGEX . '/', $version)) {
throw new UnexpectedValueException(
'Psalm supports PHP version ">=5.4". The specified version '
. $version
. " is either not supported or doesn't exist.",
);
} }
[$php_major_version, $php_minor_version] = explode('.', $version); [$php_major_version, $php_minor_version] = explode('.', $version);

View File

@@ -755,20 +755,6 @@ class ForeachAnalyzer
$has_valid_iterator = true; $has_valid_iterator = true;
if ($iterator_atomic_type instanceof TNamedObject
&& strtolower($iterator_atomic_type->value) === 'simplexmlelement'
) {
$value_type = Type::combineUnionTypes(
$value_type,
new Union([$iterator_atomic_type]),
);
$key_type = Type::combineUnionTypes(
$key_type,
Type::getString(),
);
}
if ($iterator_atomic_type instanceof TIterable if ($iterator_atomic_type instanceof TIterable
|| (strtolower($iterator_atomic_type->value) === 'traversable' || (strtolower($iterator_atomic_type->value) === 'traversable'
|| $codebase->classImplements( || $codebase->classImplements(

View File

@@ -29,6 +29,7 @@ use Psalm\Issue\UndefinedMethod;
use Psalm\IssueBuffer; use Psalm\IssueBuffer;
use Psalm\Type; use Psalm\Type;
use Psalm\Type\Atomic\TNamedObject; use Psalm\Type\Atomic\TNamedObject;
use Psalm\Type\Atomic\TObject;
use Psalm\Type\Atomic\TTemplateParam; use Psalm\Type\Atomic\TTemplateParam;
use Psalm\Type\Union; use Psalm\Type\Union;
@@ -412,7 +413,7 @@ class MethodCallAnalyzer extends CallAnalyzer
$types = $class_type->getAtomicTypes(); $types = $class_type->getAtomicTypes();
foreach ($types as $key => &$type) { foreach ($types as $key => &$type) {
if (!$type instanceof TNamedObject) { if (!$type instanceof TNamedObject && !$type instanceof TObject) {
unset($types[$key]); unset($types[$key]);
} else { } else {
$type = $type->setFromDocblock(false); $type = $type->setFromDocblock(false);

View File

@@ -1737,8 +1737,12 @@ class ArrayFetchAnalyzer
?Union &$array_access_type, ?Union &$array_access_type,
bool &$has_array_access bool &$has_array_access
): void { ): void {
if (strtolower($type->value) === 'simplexmlelement') { $codebase = $statements_analyzer->getCodebase();
$call_array_access_type = new Union([new TNamedObject('SimpleXMLElement')]); if (strtolower($type->value) === 'simplexmlelement'
|| ($codebase->classExists($type->value)
&& $codebase->classExtendsOrImplements($type->value, 'SimpleXMLElement'))
) {
$call_array_access_type = new Union([new TNull(), new TNamedObject('SimpleXMLElement')]);
} elseif (strtolower($type->value) === 'domnodelist' && $stmt->dim) { } elseif (strtolower($type->value) === 'domnodelist' && $stmt->dim) {
$old_data_provider = $statements_analyzer->node_data; $old_data_provider = $statements_analyzer->node_data;

View File

@@ -228,7 +228,7 @@ class AtomicPropertyFetchAnalyzer
self::handleEnumValue($statements_analyzer, $stmt, $stmt_var_type, $class_storage); self::handleEnumValue($statements_analyzer, $stmt, $stmt_var_type, $class_storage);
} elseif ($prop_name === 'name') { } elseif ($prop_name === 'name') {
$has_valid_fetch_type = true; $has_valid_fetch_type = true;
self::handleEnumName($statements_analyzer, $stmt, $lhs_type_part); self::handleEnumName($statements_analyzer, $stmt, $stmt_var_type, $class_storage);
} else { } else {
self::handleNonExistentProperty( self::handleNonExistentProperty(
$statements_analyzer, $statements_analyzer,
@@ -979,16 +979,31 @@ class AtomicPropertyFetchAnalyzer
private static function handleEnumName( private static function handleEnumName(
StatementsAnalyzer $statements_analyzer, StatementsAnalyzer $statements_analyzer,
PropertyFetch $stmt, PropertyFetch $stmt,
Atomic $lhs_type_part Union $stmt_var_type,
ClassLikeStorage $class_storage
): void { ): void {
if ($lhs_type_part instanceof TEnumCase) { $relevant_enum_cases = array_filter(
$statements_analyzer->node_data->setType( $stmt_var_type->getAtomicTypes(),
$stmt, static fn(Atomic $type): bool => $type instanceof TEnumCase,
new Union([Type::getAtomicStringFromLiteral($lhs_type_part->case_name)]), );
); $relevant_enum_case_names = array_map(
} else { static fn(TEnumCase $enumCase): string => $enumCase->case_name,
$statements_analyzer->node_data->setType($stmt, Type::getNonEmptyString()); $relevant_enum_cases,
);
if (empty($relevant_enum_case_names)) {
$relevant_enum_case_names = array_keys($class_storage->enum_cases);
} }
$statements_analyzer->node_data->setType(
$stmt,
empty($relevant_enum_case_names)
? Type::getNonEmptyString()
: new Union(array_map(
fn(string $name): TString => Type::getAtomicStringFromLiteral($name),
$relevant_enum_case_names,
)),
);
} }
private static function handleEnumValue( private static function handleEnumValue(

View File

@@ -3,9 +3,12 @@
namespace Psalm\Internal\Analyzer\Statements\Expression; namespace Psalm\Internal\Analyzer\Statements\Expression;
use PhpParser; use PhpParser;
use Psalm\CodeLocation;
use Psalm\Context; use Psalm\Context;
use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer; use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer;
use Psalm\Internal\Analyzer\StatementsAnalyzer; use Psalm\Internal\Analyzer\StatementsAnalyzer;
use Psalm\Issue\InvalidArgument;
use Psalm\IssueBuffer;
use Psalm\Type; use Psalm\Type;
/** /**
@@ -30,6 +33,15 @@ class IssetAnalyzer
$context->vars_in_scope[$var_id] = Type::getMixed(); $context->vars_in_scope[$var_id] = Type::getMixed();
$context->vars_possibly_in_scope[$var_id] = true; $context->vars_possibly_in_scope[$var_id] = true;
} }
} elseif (!self::isValidStatement($isset_var)) {
IssueBuffer::maybeAdd(
new InvalidArgument(
'Isset only works with variables and array elements',
new CodeLocation($statements_analyzer->getSource(), $isset_var),
'empty',
),
$statements_analyzer->getSuppressedIssues(),
);
} }
self::analyzeIssetVar($statements_analyzer, $isset_var, $context); self::analyzeIssetVar($statements_analyzer, $isset_var, $context);
@@ -49,4 +61,15 @@ class IssetAnalyzer
$context->inside_isset = false; $context->inside_isset = false;
} }
private static function isValidStatement(PhpParser\Node\Expr $stmt): bool
{
return $stmt instanceof PhpParser\Node\Expr\Variable
|| $stmt instanceof PhpParser\Node\Expr\ArrayDimFetch
|| $stmt instanceof PhpParser\Node\Expr\PropertyFetch
|| $stmt instanceof PhpParser\Node\Expr\StaticPropertyFetch
|| $stmt instanceof PhpParser\Node\Expr\NullsafePropertyFetch
|| $stmt instanceof PhpParser\Node\Expr\ClassConstFetch
|| $stmt instanceof PhpParser\Node\Expr\AssignRef;
}
} }

View File

@@ -12,6 +12,7 @@ use Psalm\Exception\ConfigNotFoundException;
use Psalm\Internal\Analyzer\ProjectAnalyzer; use Psalm\Internal\Analyzer\ProjectAnalyzer;
use Psalm\Report; use Psalm\Report;
use RuntimeException; use RuntimeException;
use UnexpectedValueException;
use function array_filter; use function array_filter;
use function array_key_exists; use function array_key_exists;
@@ -485,7 +486,15 @@ final class CliUtils
} }
if ($version !== null && $source !== null) { if ($version !== null && $source !== null) {
$project_analyzer->setPhpVersion($version, $source); try {
$project_analyzer->setPhpVersion($version, $source);
} catch (UnexpectedValueException $e) {
fwrite(
STDERR,
$e->getMessage() . PHP_EOL,
);
exit(1);
}
} }
} }

View File

@@ -597,6 +597,7 @@ class ClassLikes
/** /**
* Determine whether or not a class extends a parent * Determine whether or not a class extends a parent
* *
* @psalm-mutation-free
* @throws UnpopulatedClasslikeException when called on unpopulated class * @throws UnpopulatedClasslikeException when called on unpopulated class
* @throws InvalidArgumentException when class does not exist * @throws InvalidArgumentException when class does not exist
*/ */
@@ -620,6 +621,8 @@ class ClassLikes
/** /**
* Check whether a class implements an interface * Check whether a class implements an interface
*
* @psalm-mutation-free
*/ */
public function classImplements(string $fq_class_name, string $interface): bool public function classImplements(string $fq_class_name, string $interface): bool
{ {

View File

@@ -23,7 +23,6 @@ use LanguageServerProtocol\CodeDescription;
use LanguageServerProtocol\CompletionOptions; use LanguageServerProtocol\CompletionOptions;
use LanguageServerProtocol\Diagnostic; use LanguageServerProtocol\Diagnostic;
use LanguageServerProtocol\DiagnosticSeverity; use LanguageServerProtocol\DiagnosticSeverity;
use LanguageServerProtocol\ExecuteCommandOptions;
use LanguageServerProtocol\InitializeResult; use LanguageServerProtocol\InitializeResult;
use LanguageServerProtocol\InitializeResultServerInfo; use LanguageServerProtocol\InitializeResultServerInfo;
use LanguageServerProtocol\LogMessage; use LanguageServerProtocol\LogMessage;
@@ -446,9 +445,6 @@ class LanguageServer extends Dispatcher
$serverCapabilities = new ServerCapabilities(); $serverCapabilities = new ServerCapabilities();
//The server provides execute command support.
$serverCapabilities->executeCommandProvider = new ExecuteCommandOptions(['test']);
$textDocumentSyncOptions = new TextDocumentSyncOptions(); $textDocumentSyncOptions = new TextDocumentSyncOptions();
//Open and close notifications are sent to the server. //Open and close notifications are sent to the server.

View File

@@ -455,25 +455,6 @@ class TextDocument
], ],
]), ]),
); );
/*
$fixers["fixAll.{$diagnostic->data->type}"] = new CodeAction(
"FixAll {$diagnostic->data->type} for this file",
CodeActionKind::QUICK_FIX,
null,
null,
null,
null,
new Command(
"Fix All",
"psalm.fixall",
[
'uri' => $textDocument->uri,
'type' => $diagnostic->data->type
]
)
);
*/
} }
if (empty($fixers)) { if (empty($fixers)) {

View File

@@ -11,7 +11,6 @@ use Psalm\Internal\Provider\ReturnTypeProvider\DateTimeModifyReturnTypeProvider;
use Psalm\Internal\Provider\ReturnTypeProvider\DomNodeAppendChild; use Psalm\Internal\Provider\ReturnTypeProvider\DomNodeAppendChild;
use Psalm\Internal\Provider\ReturnTypeProvider\ImagickPixelColorReturnTypeProvider; use Psalm\Internal\Provider\ReturnTypeProvider\ImagickPixelColorReturnTypeProvider;
use Psalm\Internal\Provider\ReturnTypeProvider\PdoStatementReturnTypeProvider; use Psalm\Internal\Provider\ReturnTypeProvider\PdoStatementReturnTypeProvider;
use Psalm\Internal\Provider\ReturnTypeProvider\SimpleXmlElementAsXml;
use Psalm\Plugin\EventHandler\Event\MethodReturnTypeProviderEvent; use Psalm\Plugin\EventHandler\Event\MethodReturnTypeProviderEvent;
use Psalm\Plugin\EventHandler\MethodReturnTypeProviderInterface; use Psalm\Plugin\EventHandler\MethodReturnTypeProviderInterface;
use Psalm\StatementsSource; use Psalm\StatementsSource;
@@ -39,7 +38,6 @@ class MethodReturnTypeProvider
$this->registerClass(DomNodeAppendChild::class); $this->registerClass(DomNodeAppendChild::class);
$this->registerClass(ImagickPixelColorReturnTypeProvider::class); $this->registerClass(ImagickPixelColorReturnTypeProvider::class);
$this->registerClass(SimpleXmlElementAsXml::class);
$this->registerClass(PdoStatementReturnTypeProvider::class); $this->registerClass(PdoStatementReturnTypeProvider::class);
$this->registerClass(ClosureFromCallableReturnTypeProvider::class); $this->registerClass(ClosureFromCallableReturnTypeProvider::class);
$this->registerClass(DateTimeModifyReturnTypeProvider::class); $this->registerClass(DateTimeModifyReturnTypeProvider::class);

View File

@@ -1,34 +0,0 @@
<?php
namespace Psalm\Internal\Provider\ReturnTypeProvider;
use Psalm\Plugin\EventHandler\Event\MethodReturnTypeProviderEvent;
use Psalm\Plugin\EventHandler\MethodReturnTypeProviderInterface;
use Psalm\Type;
use Psalm\Type\Union;
use function count;
/**
* @internal
*/
class SimpleXmlElementAsXml implements MethodReturnTypeProviderInterface
{
public static function getClassLikeNames(): array
{
return ['SimpleXMLElement'];
}
public static function getMethodReturnType(MethodReturnTypeProviderEvent $event): ?Union
{
$call_args = $event->getCallArgs();
$method_name_lowercase = $event->getMethodNameLowercase();
if ($method_name_lowercase === 'asxml'
&& !count($call_args)
) {
return Type::parseString('string|false');
}
return null;
}
}

View File

@@ -4,6 +4,7 @@ namespace Psalm\Internal\Provider\ReturnTypeProvider;
use ArgumentCountError; use ArgumentCountError;
use Psalm\Issue\InvalidArgument; use Psalm\Issue\InvalidArgument;
use Psalm\Issue\RedundantFunctionCall;
use Psalm\Issue\TooFewArguments; use Psalm\Issue\TooFewArguments;
use Psalm\Issue\TooManyArguments; use Psalm\Issue\TooManyArguments;
use Psalm\IssueBuffer; use Psalm\IssueBuffer;
@@ -25,6 +26,7 @@ use function count;
use function is_string; use function is_string;
use function preg_match; use function preg_match;
use function sprintf; use function sprintf;
use function strlen;
/** /**
* @internal * @internal
@@ -47,6 +49,11 @@ class SprintfReturnTypeProvider implements FunctionReturnTypeProviderInterface
$statements_source = $event->getStatementsSource(); $statements_source = $event->getStatementsSource();
$call_args = $event->getCallArgs(); $call_args = $event->getCallArgs();
// invalid - will already report an error for the params anyway
if (count($call_args) < 1) {
return null;
}
$has_splat_args = false; $has_splat_args = false;
$node_type_provider = $statements_source->getNodeTypeProvider(); $node_type_provider = $statements_source->getNodeTypeProvider();
foreach ($call_args as $call_arg) { foreach ($call_args as $call_arg) {
@@ -67,17 +74,29 @@ class SprintfReturnTypeProvider implements FunctionReturnTypeProviderInterface
// eventually this could be refined // eventually this could be refined
// to check if it's an array with literal string as first element for further checking // to check if it's an array with literal string as first element for further checking
if (count($call_args) === 1 && $has_splat_args === true) { if (count($call_args) === 1 && $has_splat_args === true) {
IssueBuffer::maybeAdd(
new RedundantFunctionCall(
'Using the splat operator is redundant, as v' . $event->getFunctionId()
. ' without splat operator can be used instead of ' . $event->getFunctionId(),
$event->getCodeLocation(),
),
$statements_source->getSuppressedIssues(),
);
return null; return null;
} }
// it makes no sense to use sprintf when there is only 1 arg (the format) // it makes no sense to use sprintf when there is only 1 arg (the format)
// as it wouldn't have any placeholders // as it wouldn't have any placeholders
if (count($call_args) === 1 && $event->getFunctionId() === 'sprintf') { // if it's a literal string, we can check it further though!
$first_arg_type = $node_type_provider->getType($call_args[0]->value);
if (count($call_args) === 1
&& ($first_arg_type === null || !$first_arg_type->isSingleStringLiteral())) {
IssueBuffer::maybeAdd( IssueBuffer::maybeAdd(
new TooFewArguments( new RedundantFunctionCall(
'Too few arguments for ' . $event->getFunctionId() . ', expecting at least 2 arguments', 'Using ' . $event->getFunctionId()
. ' with a single argument is redundant, since there are no placeholder params to be substituted',
$event->getCodeLocation(), $event->getCodeLocation(),
$event->getFunctionId(),
), ),
$statements_source->getSuppressedIssues(), $statements_source->getSuppressedIssues(),
); );
@@ -89,7 +108,10 @@ class SprintfReturnTypeProvider implements FunctionReturnTypeProviderInterface
$is_falsable = true; $is_falsable = true;
foreach ($call_args as $index => $call_arg) { foreach ($call_args as $index => $call_arg) {
$type = $node_type_provider->getType($call_arg->value); $type = $node_type_provider->getType($call_arg->value);
if ($type === null && $index === 0 && $event->getFunctionId() === 'printf') { if ($type === null && $index === 0 && $event->getFunctionId() === 'printf') {
// printf only has the format validated above
// don't change the return type
break; break;
} }
@@ -100,10 +122,9 @@ class SprintfReturnTypeProvider implements FunctionReturnTypeProviderInterface
if ($index === 0 && $type->isSingleStringLiteral()) { if ($index === 0 && $type->isSingleStringLiteral()) {
if ($type->getSingleStringLiteral()->value === '') { if ($type->getSingleStringLiteral()->value === '') {
IssueBuffer::maybeAdd( IssueBuffer::maybeAdd(
new InvalidArgument( new RedundantFunctionCall(
'Argument 1 of ' . $event->getFunctionId() . ' must not be an empty string', 'Calling ' . $event->getFunctionId() . ' with an empty first argument does nothing',
$event->getCodeLocation(), $event->getCodeLocation(),
$event->getFunctionId(),
), ),
$statements_source->getSuppressedIssues(), $statements_source->getSuppressedIssues(),
); );
@@ -158,17 +179,48 @@ class SprintfReturnTypeProvider implements FunctionReturnTypeProviderInterface
$initial_result = $result; $initial_result = $result;
if ($result === $type->getSingleStringLiteral()->value) { if ($result === $type->getSingleStringLiteral()->value) {
IssueBuffer::maybeAdd( if (count($call_args) > 1) {
new InvalidArgument( // we need to report this here too, since we return early without further validation
'Argument 1 of ' . $event->getFunctionId() // otherwise people who have suspended RedundantFunctionCall errors
. ' does not contain any placeholders', // will not get an error for this
$event->getCodeLocation(), IssueBuffer::maybeAdd(
$event->getFunctionId(), new TooManyArguments(
), 'Too many arguments for the number of placeholders in '
$statements_source->getSuppressedIssues(), . $event->getFunctionId(),
); $event->getCodeLocation(),
$event->getFunctionId(),
),
$statements_source->getSuppressedIssues(),
);
}
return null; // the same error as above, but we have validated the pattern now
if (count($call_args) === 1) {
IssueBuffer::maybeAdd(
new RedundantFunctionCall(
'Using ' . $event->getFunctionId()
. ' with a single argument is redundant,'
. ' since there are no placeholder params to be substituted',
$event->getCodeLocation(),
),
$statements_source->getSuppressedIssues(),
);
} else {
IssueBuffer::maybeAdd(
new RedundantFunctionCall(
'Argument 1 of ' . $event->getFunctionId()
. ' does not contain any placeholders',
$event->getCodeLocation(),
),
$statements_source->getSuppressedIssues(),
);
}
if ($event->getFunctionId() === 'printf') {
return Type::getInt(false, strlen($type->getSingleStringLiteral()->value));
}
return $type;
} }
} }
} catch (ValueError $value_error) { } catch (ValueError $value_error) {

View File

@@ -323,7 +323,7 @@ abstract class Atomic implements TypeNode
return $analysis_php_version_id !== null ? new TNamedObject($value) : new TScalar(); return $analysis_php_version_id !== null ? new TNamedObject($value) : new TScalar();
case 'null': case 'null':
if ($analysis_php_version_id === null || $analysis_php_version_id >= 8_00_00) { if ($analysis_php_version_id === null || $analysis_php_version_id >= 7_00_00) {
return new TNull(); return new TNull();
} }

View File

@@ -424,6 +424,10 @@ class Reconciler
{ {
foreach ($new_types as $nk => $type) { foreach ($new_types as $nk => $type) {
if (strpos($nk, '[') || strpos($nk, '->')) { if (strpos($nk, '[') || strpos($nk, '->')) {
$type = array_values($type);
if (!isset($type[0][0])) {
continue;
}
if ($type[0][0] instanceof IsEqualIsset if ($type[0][0] instanceof IsEqualIsset
|| $type[0][0] instanceof IsIsset || $type[0][0] instanceof IsIsset
|| $type[0][0] instanceof NonEmpty || $type[0][0] instanceof NonEmpty

View File

@@ -1359,9 +1359,10 @@ function realpath(string $path) {}
* *
* @param numeric-string $num1 * @param numeric-string $num1
* @param numeric-string $num2 * @param numeric-string $num2
* @param int|null $scale
* @return (PHP_MAJOR_VERSION is 8 ? numeric-string : ($num2 is "0" ? null : numeric-string)) * @return (PHP_MAJOR_VERSION is 8 ? numeric-string : ($num2 is "0" ? null : numeric-string))
*/ */
function bcdiv(string $num1, string $num2, int $scale = 0): ?string {} function bcdiv(string $num1, string $num2, ?int $scale = null): ?string {}
/** /**
* @psalm-pure * @psalm-pure

11
vendor/vimeo/psalm/stubs/Php74.phpstub vendored Normal file
View File

@@ -0,0 +1,11 @@
<?php
/**
* @psalm-pure
*
* @psalm-taint-escape html
* @psalm-flow ($string) -> return
*
* @param null|string|array<array-key,string> $allowed_tags
*/
function strip_tags(string $string, null|string|array $allowed_tags = null) : string {}

View File

@@ -471,13 +471,13 @@ class DOMDocument extends DOMNode implements DOMParentNode
public function importNode(DOMNode $node, bool $deep = false) {} public function importNode(DOMNode $node, bool $deep = false) {}
/** /**
* @return DOMDocument|false * @return bool
* @psalm-ignore-falsable-return * @psalm-ignore-falsable-return
**/ **/
public function load(string $filename, int $options = 0) {} public function load(string $filename, int $options = 0) {}
/** /**
* @return DOMDocument|false * @return bool
* @psalm-ignore-falsable-return * @psalm-ignore-falsable-return
*/ */
public function loadXML(string $source, int $options = 0) {} public function loadXML(string $source, int $options = 0) {}
@@ -492,10 +492,10 @@ class DOMDocument extends DOMNode implements DOMParentNode
*/ */
public function save(string $filename, int $options = 0) {} public function save(string $filename, int $options = 0) {}
/** @return DOMDocument|bool */ /** @return bool */
public function loadHTML(string $source, int $options = 0) {} public function loadHTML(string $source, int $options = 0) {}
/** @return DOMDocument|bool */ /** @return bool */
public function loadHTMLFile(string $filename, int $options = 0) {} public function loadHTMLFile(string $filename, int $options = 0) {}
/** /**

View File

@@ -25,6 +25,7 @@ function simplexml_import_dom(SimpleXMLElement|DOMNode $node, ?string $class_nam
/** /**
* @implements Traversable<string, SimpleXMLElement> * @implements Traversable<string, SimpleXMLElement>
* @psalm-no-seal-properties
*/ */
class SimpleXMLElement implements Traversable, Countable class SimpleXMLElement implements Traversable, Countable
{ {
@@ -63,6 +64,8 @@ class SimpleXMLElement implements Traversable, Countable
public function __toString(): string {} public function __toString(): string {}
public function count(): int {} public function count(): int {}
public function __get(string $name): SimpleXMLElement|SimpleXMLIterator|null {}
} }
/** /**

View File

@@ -0,0 +1,42 @@
<?php // phpcs:ignore warning
/**
* @phan-file-suppress PhanTypeSuspiciousStringExpression
*/
declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start();
// sample config
require 'config.php';
// define log file id
$LOG_FILE_ID = 'classTest_class_calls';
ob_end_flush();
$log = new CoreLibs\Logging\Logging([
'log_folder' => BASE . LOG,
'log_file_id' => $LOG_FILE_ID,
'log_per_date' => true,
]);
// db connection and attach logger
$db = new CoreLibs\DB\IO(DB_CONFIG, $log);
// define a list of from to color sets for conversion test
$PAGE_NAME = 'TEST CLASS: CLASS CALLS';
print "<!DOCTYPE html>";
print "<html><head><title>" . $PAGE_NAME . "</title><head>";
print "<body>";
print '<div><a href="class_test.php">Class Test Master</a></div>';
print '<div><h1>' . $PAGE_NAME . '</h1></div>';
$test = new \TestCalls\Test($db, $log);
$test->testDbCall();
print "</body></html>";
// __END__

View File

@@ -169,6 +169,7 @@ class TestL
public function test(?string $ts = null): bool public function test(?string $ts = null): bool
{ {
print "* GETCALLERCLASS(INSIDE CLASS): " . \CoreLibs\Debug\Support::getCallerClass() . "<br>"; print "* GETCALLERCLASS(INSIDE CLASS): " . \CoreLibs\Debug\Support::getCallerClass() . "<br>";
print "* GETCALLERTOPCLASS(INSIDE CLASS): " . \CoreLibs\Debug\Support::getCallerTopLevelClass() . "<br>";
$this->log->debug('TESTL', 'Logging in class testL' . ($ts !== null ? ': ' . $ts : '')); $this->log->debug('TESTL', 'Logging in class testL' . ($ts !== null ? ': ' . $ts : ''));
$this->log->debug('TESTL', 'Some other message'); $this->log->debug('TESTL', 'Some other message');
return true; return true;
@@ -191,6 +192,7 @@ class TestR extends TestL
public function subTest(): bool public function subTest(): bool
{ {
print "** GETCALLERCLASS(INSIDE EXTND CLASS): " . \CoreLibs\Debug\Support::getCallerClass() . "<br>"; print "** GETCALLERCLASS(INSIDE EXTND CLASS): " . \CoreLibs\Debug\Support::getCallerClass() . "<br>";
print "** GETCALLERTOPCLASS(INSIDE EXTND CLASS): " . \CoreLibs\Debug\Support::getCallerTopLevelClass() . "<br>";
$this->log->debug('TESTR', 'Logging in class testR (extends testL)'); $this->log->debug('TESTR', 'Logging in class testR (extends testL)');
$this->test('TESTR INSIDE'); $this->test('TESTR INSIDE');
$this->log->debug('TESTR', 'Array: ' $this->log->debug('TESTR', 'Array: '

View File

@@ -75,7 +75,6 @@ print "EL_O: <pre>" . print_r($el_o, true) . "</pre>";
echo "<hr>"; echo "<hr>";
print "buildHtml(): <pre>" . htmlentities($el_o->buildHtml()) . "</pre>"; print "buildHtml(): <pre>" . htmlentities($el_o->buildHtml()) . "</pre>";
echo "<hr>"; echo "<hr>";
/** @phpstan-ignore-next-line */
print "phfo(\$el_o): <pre>" . htmlentities($el_o::printHtmlFromObject($el_o, true)) . "</pre>"; print "phfo(\$el_o): <pre>" . htmlentities($el_o::printHtmlFromObject($el_o, true)) . "</pre>";
echo "<hr>"; echo "<hr>";
print "phfa(\$el_list): <pre>" . htmlentities($el_o::buildHtmlFromList($el_o_list, true)) . "</pre>"; print "phfa(\$el_list): <pre>" . htmlentities($el_o::buildHtmlFromList($el_o_list, true)) . "</pre>";

View File

@@ -51,7 +51,6 @@ echo "<br><b>AUTO DETECT</b><br>";
// DEPRECATED // DEPRECATED
// $get_locale = Language\GetLocale::setLocale(); // $get_locale = Language\GetLocale::setLocale();
// print "[AUTO, DEPRECATED]: " . Support::printAr($get_locale) . "<br>"; // print "[AUTO, DEPRECATED]: " . Support::printAr($get_locale) . "<br>";
/** @phpstan-ignore-next-line */
$get_locale = Language\GetLocale::setLocaleFromSession( $get_locale = Language\GetLocale::setLocaleFromSession(
SITE_LOCALE, SITE_LOCALE,
str_replace('/', '', CONTENT_PATH), str_replace('/', '', CONTENT_PATH),
@@ -59,7 +58,6 @@ $get_locale = Language\GetLocale::setLocaleFromSession(
BASE . INCLUDES . LOCALE BASE . INCLUDES . LOCALE
); );
print "[NAMED CONSTANTS OUTSIDE]: " . Support::printAr($get_locale) . "<br>"; print "[NAMED CONSTANTS OUTSIDE]: " . Support::printAr($get_locale) . "<br>";
/** @phpstan-ignore-next-line */
$get_locale = Language\GetLocale::setLocaleFromSession( $get_locale = Language\GetLocale::setLocaleFromSession(
'en', 'en',
'foo', 'foo',
@@ -76,7 +74,6 @@ $_SESSION['DEFAULT_LOCALE'] = 'ja_JP.UTF-8';
$_SESSION['DEFAULT_CHARSET'] = 'UTF-8'; $_SESSION['DEFAULT_CHARSET'] = 'UTF-8';
$_SESSION['DEFAULT_DOMAIN'] = 'admin'; $_SESSION['DEFAULT_DOMAIN'] = 'admin';
$_SESSION['LOCALE_PATH'] = BASE . INCLUDES . LOCALE; $_SESSION['LOCALE_PATH'] = BASE . INCLUDES . LOCALE;
/** @phpstan-ignore-next-line */
$get_locale = Language\GetLocale::setLocaleFromSession( $get_locale = Language\GetLocale::setLocaleFromSession(
SITE_LOCALE, SITE_LOCALE,
SITE_DOMAIN, SITE_DOMAIN,
@@ -93,7 +90,6 @@ $_SESSION['DEFAULT_LOCALE'] = '00000#####';
$_SESSION['DEFAULT_CHARSET'] = ''; $_SESSION['DEFAULT_CHARSET'] = '';
$_SESSION['DEFAULT_DOMAIN'] = 'admin'; $_SESSION['DEFAULT_DOMAIN'] = 'admin';
$_SESSION['LOCALE_PATH'] = BASE . INCLUDES . LOCALE; $_SESSION['LOCALE_PATH'] = BASE . INCLUDES . LOCALE;
/** @phpstan-ignore-next-line */
$get_locale = Language\GetLocale::setLocaleFromSession( $get_locale = Language\GetLocale::setLocaleFromSession(
SITE_LOCALE, SITE_LOCALE,
SITE_DOMAIN, SITE_DOMAIN,

View File

@@ -114,6 +114,7 @@ $test_files = [
'class_test.autoloader.php' => 'Class Test: AUTOLOADER', 'class_test.autoloader.php' => 'Class Test: AUTOLOADER',
'class_test.config.link.php' => 'Class Test: CONFIG LINK', 'class_test.config.link.php' => 'Class Test: CONFIG LINK',
'class_test.config.direct.php' => 'Class Test: CONFIG DIRECT', 'class_test.config.direct.php' => 'Class Test: CONFIG DIRECT',
'class_test.class-calls.php' => 'Class Test: CLASS CALLS',
'subfolder/class_test.config.direct.php' => 'Class Test: CONFIG DIRECT SUB', 'subfolder/class_test.config.direct.php' => 'Class Test: CONFIG DIRECT SUB',
]; ];

View File

@@ -35,7 +35,6 @@ print '<div><h1>' . $PAGE_NAME . '</h1></div>';
print "ALREADY from config.php: " . \CoreLibs\Debug\Support::printAr($_ENV) . "<br>"; print "ALREADY from config.php: " . \CoreLibs\Debug\Support::printAr($_ENV) . "<br>";
// test .env in local // test .env in local
/** @phpstan-ignore-next-line */
$status = \CoreLibs\Get\DotEnv::readEnvFile('.', 'test.env'); $status = \CoreLibs\Get\DotEnv::readEnvFile('.', 'test.env');
print "test.env: STATUS: " . $status . "<br>"; print "test.env: STATUS: " . $status . "<br>";
print "AFTER reading test.env file: " . \CoreLibs\Debug\Support::printAr($_ENV) . "<br>"; print "AFTER reading test.env file: " . \CoreLibs\Debug\Support::printAr($_ENV) . "<br>";

49
www/composer.lock generated
View File

@@ -273,16 +273,16 @@
}, },
{ {
"name": "nikic/php-parser", "name": "nikic/php-parser",
"version": "v4.15.5", "version": "v4.17.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nikic/PHP-Parser.git", "url": "https://github.com/nikic/PHP-Parser.git",
"reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e" "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/11e2663a5bc9db5d714eedb4277ee300403b4a9e", "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
"reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e", "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -323,9 +323,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/nikic/PHP-Parser/issues", "issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.5" "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1"
}, },
"time": "2023-05-19T20:20:00+00:00" "time": "2023-08-13T19:53:39+00:00"
}, },
{ {
"name": "phar-io/manifest", "name": "phar-io/manifest",
@@ -440,16 +440,16 @@
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
"version": "9.2.26", "version": "9.2.27",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1" "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/b0a88255cb70d52653d80c890bd7f38740ea50d1",
"reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -505,7 +505,8 @@
], ],
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26" "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.27"
}, },
"funding": [ "funding": [
{ {
@@ -513,7 +514,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-03-06T12:58:08+00:00" "time": "2023-07-26T13:44:30+00:00"
}, },
{ {
"name": "phpunit/php-file-iterator", "name": "phpunit/php-file-iterator",
@@ -758,16 +759,16 @@
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "9.6.8", "version": "9.6.11",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e" "reference": "810500e92855eba8a7a5319ae913be2da6f957b0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/17d621b3aff84d0c8b62539e269e87d8d5baa76e", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/810500e92855eba8a7a5319ae913be2da6f957b0",
"reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e", "reference": "810500e92855eba8a7a5319ae913be2da6f957b0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -841,7 +842,7 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues", "issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy", "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.8" "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.11"
}, },
"funding": [ "funding": [
{ {
@@ -857,7 +858,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-05-11T05:14:45+00:00" "time": "2023-08-19T07:10:56+00:00"
}, },
{ {
"name": "sebastian/cli-parser", "name": "sebastian/cli-parser",
@@ -1365,16 +1366,16 @@
}, },
{ {
"name": "sebastian/global-state", "name": "sebastian/global-state",
"version": "5.0.5", "version": "5.0.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git", "url": "https://github.com/sebastianbergmann/global-state.git",
"reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" "reference": "bde739e7565280bda77be70044ac1047bc007e34"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34",
"reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", "reference": "bde739e7565280bda77be70044ac1047bc007e34",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1417,7 +1418,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues", "issues": "https://github.com/sebastianbergmann/global-state/issues",
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6"
}, },
"funding": [ "funding": [
{ {
@@ -1425,7 +1426,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2022-02-14T08:28:10+00:00" "time": "2023-08-02T09:26:13+00:00"
}, },
{ {
"name": "sebastian/lines-of-code", "name": "sebastian/lines-of-code",

View File

@@ -556,7 +556,7 @@ class Backend
string $suffix = '', string $suffix = '',
int $min_steps = 1, int $min_steps = 1,
bool $name_pos_back = false bool $name_pos_back = false
) { ): string {
// get the build layout // get the build layout
$html_time = \CoreLibs\Output\Form\Elements::printDateTime( $html_time = \CoreLibs\Output\Form\Elements::printDateTime(
$year, $year,

View File

@@ -805,7 +805,10 @@ class IO
$call_stack[] = $call_stack[] =
($call_trace['file'] ?? 'n/f') . ':' ($call_trace['file'] ?? 'n/f') . ':'
. ($call_trace['line'] ?? '-') . ':' . ($call_trace['line'] ?? '-') . ':'
. (!empty($call_trace['class']) ? $call_trace['class'] . '->' : '') . (!empty($call_trace['class']) ?
$call_trace['class'] . ($call_trace['type'] ?? '') :
''
)
. $call_trace['function']; . $call_trace['function'];
} }
$context = [ $context = [
@@ -825,7 +828,7 @@ class IO
); );
break; break;
default: default:
// used named arguments so we can easy change the order of debug // used named arguments so we can easy change the order of debug
$this->log->debug( $this->log->debug(
group_id: $debug_id, group_id: $debug_id,
message: $error_string, message: $error_string,

View File

@@ -405,7 +405,7 @@ class LoggingLegacy
// set per class, but don't use get_class as we will only get self // set per class, but don't use get_class as we will only get self
$rpl_string = !$this->log_per_class ? '' : '_' $rpl_string = !$this->log_per_class ? '' : '_'
// set sub class settings // set sub class settings
. str_replace('\\', '-', Support::getCallerClass()); . str_replace('\\', '-', Support::getCallerTopLevelClass());
$fn = str_replace('{CLASS}', $rpl_string, $fn); // create output filename $fn = str_replace('{CLASS}', $rpl_string, $fn); // create output filename
// if request to write to one file // if request to write to one file
@@ -756,7 +756,7 @@ class LoggingLegacy
return $status; return $status;
} }
// get the last class entry and wrie that // get the last class entry and wrie that
$class = Support::getCallerClass(); $class = Support::getCallerTopLevelClass();
// get timestamp // get timestamp
$timestamp = Support::printTime(); $timestamp = Support::printTime();
// same string put for print (no html data inside) // same string put for print (no html data inside)
@@ -855,7 +855,7 @@ class LoggingLegacy
. 'border-bottom: 1px solid black; margin: 10px 0 10px 0; ' . 'border-bottom: 1px solid black; margin: 10px 0 10px 0; '
. 'background-color: white; color: black;">' . 'background-color: white; color: black;">'
. '<div style="font-size: 12px;">{<span style="font-style: italic; color: #928100;">' . '<div style="font-size: 12px;">{<span style="font-style: italic; color: #928100;">'
. Support::getCallerClass() . '</span>}</div>'; . Support::getCallerTopLevelClass() . '</span>}</div>';
$string_output = $string_prefix . $string_output $string_output = $string_prefix . $string_output
. '<div><span style="font-style: italic; color: #108db3;">Script Run Time:</span> ' . '<div><span style="font-style: italic; color: #108db3;">Script Run Time:</span> '
. $script_end . '</div>' . $script_end . '</div>'

View File

@@ -79,10 +79,10 @@ class Support
* default true: true, false: false * default true: true, false: false
* *
* @param bool $bool Variable to convert * @param bool $bool Variable to convert
* @param string $name [default: ''] Prefix name * @param string $name [=''] Prefix name
* @param string $true [default: 'true'] True string * @param string $true [='true'] True string
* @param string $false [default: 'false'] False string * @param string $false [='false'] False string
* @param bool $no_html [default: false] if true do not print html * @param bool $no_html [=false] if true do not print html
* @return string String with converted bool text for debug * @return string String with converted bool text for debug
*/ */
public static function printBool( public static function printBool(
@@ -104,8 +104,8 @@ class Support
* Convert bool value to string value. Short name alias for printBool * Convert bool value to string value. Short name alias for printBool
* *
* @param bool $bool Bool value to be transformed * @param bool $bool Bool value to be transformed
* @param string $true [default: 'true'] Override default string 'true' * @param string $true [='true'] Override default string 'true'
* @param string $false [default: 'false'] Override default string 'false' * @param string $false [=false'] Override default string 'false'
* @return string $true or $false string for true/false bool * @return string $true or $false string for true/false bool
*/ */
public static function prBl( public static function prBl(
@@ -159,7 +159,7 @@ class Support
* Recommended debug output * Recommended debug output
* *
* @param mixed $data Anything * @param mixed $data Anything
* @param bool $no_html [default=false] If true strip all html tags * @param bool $no_html [=false] If true strip all html tags
* (for text print) * (for text print)
* @return string A text string * @return string A text string
*/ */
@@ -203,7 +203,7 @@ class Support
* exports (dumps) var, in more printable design, but without detail info * exports (dumps) var, in more printable design, but without detail info
* *
* @param mixed $data Anything * @param mixed $data Anything
* @param bool $no_html If true true do not add <pre> tags * @param bool $no_html [=false] If true true do not add <pre> tags
* @return string A text string * @return string A text string
*/ */
public static function exportVar(mixed $data, bool $no_html = false): string public static function exportVar(mixed $data, bool $no_html = false): string
@@ -217,7 +217,7 @@ class Support
* Return file name and line number where this was called * Return file name and line number where this was called
* One level up * One level up
* *
* @param int $level trace level, default 1 * @param int $level [=1] trace level
* @return string|null null or file name:line number * @return string|null null or file name:line number
*/ */
public static function getCallerFileLine(int $level = 1): ?string public static function getCallerFileLine(int $level = 1): ?string
@@ -238,14 +238,14 @@ class Support
* eg for debugging, this function does this * eg for debugging, this function does this
* *
* call this method in the child method and you get the parent function that called * call this method in the child method and you get the parent function that called
* @param int $level trace level, default 1 * @param int $level [=1] trace level
* @return ?string null or the function that called the function * @return string|null null or the function that called the function
* where this method is called * where this method is called
*/ */
public static function getCallerMethod(int $level = 1): ?string public static function getCallerMethod(int $level = 1): ?string
{ {
$traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); $traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
// print \CoreLibs\Debug\Support::printAr($traces); // print "getCallerMethod:<br>" . \CoreLibs\Debug\Support::printAr($traces);
// We should check from top down if unset? // We should check from top down if unset?
// sets the start point here, and in level two (the sub call) we find this // sets the start point here, and in level two (the sub call) we find this
if (isset($traces[$level])) { if (isset($traces[$level])) {
@@ -254,6 +254,41 @@ class Support
return null; return null;
} }
/**
* get the class that first called it and skip the base class
* Companion method to getCallerMethod
*
* @param int $level [=1] trace level
* @return ?string null if class not found
*/
public static function getCallerClass(int $level = 1): ?string
{
$traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
// print "getCallerClass:<br>" . \CoreLibs\Debug\Support::printAr($traces);
if (isset($traces[$level])) {
return $traces[$level]['class'] ?? null;
}
return null;
}
/**
* Returns class and method together
*
* @param int $level [=1] travel level
* @return string|null null if trace level not found, else namespace class and method
*/
public static function getCallerClassMethod(int $level = 1): ?string
{
$traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
// print "getCallerClass:<br>" . \CoreLibs\Debug\Support::printAr($traces);
if (isset($traces[$level])) {
return ($traces[$level]['class'] ?? '-')
. ($traces[$level]['type'] ?? '')
. $traces[$level]['function'];
}
return null;
}
/** /**
* Returns array with all methods in the call stack in the order so that last * Returns array with all methods in the call stack in the order so that last
* called is last in order * called is last in order
@@ -283,25 +318,21 @@ class Support
* Is mostly used in debug log statements to get the class where the debug * Is mostly used in debug log statements to get the class where the debug
* was called * was called
* gets top level class * gets top level class
* loops over the debug backtrace until if finds the first class (from the end) * loops over the debug backtrace until if finds the first class (from the end)
* *
* @return string Class name with namespace * @return string Class name with namespace
*/ */
public static function getCallerClass(): string public static function getCallerTopLevelClass(): string
{ {
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); $traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
// ?? [['class' => get_called_class()]]; // print "getCallerClass:<br>" . \CoreLibs\Debug\Support::printAr($traces);
// TODO make sure that this doesn't loop forver
$class = null; $class = null;
while ($class === null && count($backtrace) > 0) { // reverse and stop at first set class, this is the top level one
// if current is foreach (array_reverse($traces) as $trace) {
// [function] => debug $class = $trace['class'] ?? null;
// [class] => CoreLibs\Debug\Logging if (!empty($class)) {
// then return break;
// (OUTSIDE) because it was not called from a class method }
// or return file name
$get_class = array_pop($backtrace);
$class = $get_class['class'] ?? null;
} }
// on null or empty return empty string // on null or empty return empty string
return empty($class) ? '' : $class; return empty($class) ? '' : $class;

View File

@@ -381,7 +381,7 @@ class Logging
// auto set (should be deprecated in future) // auto set (should be deprecated in future)
$this->setLogFileId( $this->setLogFileId(
str_replace(':', '-', $this->host_name) . '_' str_replace(':', '-', $this->host_name) . '_'
. str_replace('\\', '-', Support::getCallerClass()) . str_replace('\\', '-', Support::getCallerTopLevelClass())
); );
} }
if (empty($this->getLogFileId())) { if (empty($this->getLogFileId())) {
@@ -460,7 +460,7 @@ class Logging
// set per class, but don't use get_class as we will only get self // set per class, but don't use get_class as we will only get self
$rpl_string = !$this->getLogFlag(Flag::per_class) ? '' : '_' $rpl_string = !$this->getLogFlag(Flag::per_class) ? '' : '_'
// set sub class settings // set sub class settings
. str_replace('\\', '-', Support::getCallerClass()); . str_replace('\\', '-', Support::getCallerTopLevelClass());
$fn = str_replace('{CLASS}', $rpl_string, $fn); // create output filename $fn = str_replace('{CLASS}', $rpl_string, $fn); // create output filename
// if request to write to one file // if request to write to one file
@@ -526,7 +526,10 @@ class Logging
/** /**
* Prepare the log message with all needed info blocks: * Prepare the log message with all needed info blocks:
* [timestamp] [host name] [file path + file] [running uid] {class} <debug level/group id> - message * [timestamp] [host name] [file path + file::row number] [running uid] {class::/->method}
* <debug level:debug group id> - message
* Note: group id is only for debug level
* if no method can be found or no class is found a - will be wirtten
* *
* @param Level $level Log level we will write to * @param Level $level Log level we will write to
* @param string|Stringable $message The message to write * @param string|Stringable $message The message to write
@@ -545,16 +548,32 @@ class Logging
if (!$this->checkLogLevel($level)) { if (!$this->checkLogLevel($level)) {
return ''; return '';
} }
$file_line = '';
$caller_class_method = '-';
$traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
// print "[" . $level->getName() . "] [$message] prepareLog:<br>" . Support::printAr($traces);
// file + line: call not this but one before (the one that calls this) // file + line: call not this but one before (the one that calls this)
$file_line = Support::getCallerFileLine(2) ?? // start from this level, if unset fall down until we are at null
System::getPageName(System::FULL_PATH); $start_trace_level = 2;
// get the last class entry and wrie that for ($trace_level = $start_trace_level; $trace_level >= 0; $trace_level--) {
$class = Support::getCallerClass(); if (isset($traces[$trace_level])) {
// method/function: prepareLog->(debug|info|...)->[THIS] $file_line = ($traces[$trace_level]['file'] ?? $traces[$trace_level]['function'])
$method = Support::getCallerMethod(3); . ':' . ($traces[$trace_level]['line'] ?? '-');
if ($method !== null) { // as namespace\class->method
$class .= '::' . $method; $caller_class_method =
// get the last call before we are in the Logging class
($traces[$trace_level]['class'] ?? '')
// connector, if unkown use ==
. ($traces[$trace_level]['type'] ?? '')
// method/function: prepareLog->(debug|info|...)->[THIS]
. $traces[$trace_level]['function'];
break;
}
} }
if (empty($file_line)) {
$file_line = System::getPageName(System::FULL_PATH);
}
// print "CLASS: " . $class . "<br>";
// get timestamp // get timestamp
$timestamp = Support::printTime(); $timestamp = Support::printTime();
@@ -574,7 +593,7 @@ class Logging
. '[' . $this->host_name . '] ' . '[' . $this->host_name . '] '
. '[' . $file_line . '] ' . '[' . $file_line . '] '
. '[' . $this->running_uid . '] ' . '[' . $this->running_uid . '] '
. '{' . $class . '} ' . '{' . $caller_class_method . '} '
. '<' . strtoupper($group_str) . '> ' . '<' . strtoupper($group_str) . '> '
. $message . $message
. $context_str; . $context_str;

View File

@@ -4,40 +4,28 @@
* TEST sets for DB::IO * TEST sets for DB::IO
*/ */
namespace Test\DB; namespace TestCalls\DB;
use CoreLibs\DB\IO;
class TestDB class TestDB
{ {
/** @var IO */ /** @var \CoreLibs\DB\IO */
private $db; private \CoreLibs\DB\IO $db;
/** @var array<mixed> */ /** @var \CoreLibs\Logging\Logging */
private $config; private \CoreLibs\Logging\Logging $log;
/** @var \TestCalls\Test */
public $main;
/** /**
* Undocumented function * Undocumented function
* *
* @param \CoreLibs\Logging\Logging $log * @param \TestCalls\Test $main
*/ */
public function __construct( public function __construct(
\CoreLibs\Logging\Logging $log \TestCalls\Test $main
) { ) {
$this->config = [ $this->db = $main->db;
'db_name' => $_ENV['DB_NAME_TEST'] ?? '', $this->log = $main->log;
'db_user' => $_ENV['DB_USER_TEST'] ?? '',
'db_pass' => $_ENV['DB_PASS_TEST'] ?? '',
'db_host' => $_ENV['DB_HOST_TEST'] ?? '',
'db_port' => 5432,
'db_schema' => 'public',
'db_type' => 'pgsql',
'db_encoding' => '',
'db_ssl' => 'allow'
];
$this->db = new IO(
$this->config,
$log
);
} }
/** /**
@@ -47,6 +35,7 @@ class TestDB
*/ */
private function testDBa(): void private function testDBa(): void
{ {
$this->log->debug('TEST DB', 'Call in testDBa');
$this->db->dbInfo(); $this->db->dbInfo();
} }
@@ -57,6 +46,7 @@ class TestDB
*/ */
public function testRunDB(): void public function testRunDB(): void
{ {
$this->log->debug('TEST DB', 'Call in testRunDB');
$this->testDBa(); $this->testDBa();
} }
} }

View File

@@ -14,25 +14,33 @@
declare(strict_types=1); declare(strict_types=1);
namespace Test; namespace TestCalls;
use Test\DB; use TestCalls\DB;
class Test class Test
{ {
/** @var DB\TestDB */ /** @var DB\TestDB */
private $test_db; private $test_db;
/** @var \CoreLibs\DB\IO */
public \CoreLibs\DB\IO $db;
/** @var \CoreLibs\Logging\Logging */
public \CoreLibs\Logging\Logging $log;
public function __construct( public function __construct(
\CoreLibs\DB\IO $db,
\CoreLibs\Logging\Logging $log \CoreLibs\Logging\Logging $log
) { ) {
$this->db = $db;
$this->log = $log;
// calls all tests // calls all tests
$this->testPrivate(); $this->testPrivate();
$this->testProtected(); $this->testProtected();
$this->testPublic(); $this->testPublic();
// call intern // call intern
$this->test_db = new DB\TestDB($log); $this->test_db = new DB\TestDB($this);
} }
public function __destruct() public function __destruct()
@@ -82,6 +90,28 @@ class Test
{ {
$this->test_db->testRunDB(); $this->test_db->testRunDB();
} }
/**
* Undocumented function
*
* @return void
*/
public function testDbCall(): void
{
$q = <<<SQL
SELECT
type, sdate, integer
FROM
foobar
LIMIT
1;
SQL;
if (is_array($res = $this->db->dbReturnRow($q))) {
print "OUTPUT: " . $this->log->prAr($res);
} else {
$this->log->error('Failure to run query');
}
}
} }
// __END__ // __END__

View File

@@ -139,6 +139,7 @@ return array(
'PHPUnit\\Framework\\Constraint\\LogicalXor' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Operator/LogicalXor.php', 'PHPUnit\\Framework\\Constraint\\LogicalXor' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Operator/LogicalXor.php',
'PHPUnit\\Framework\\Constraint\\ObjectEquals' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Object/ObjectEquals.php', 'PHPUnit\\Framework\\Constraint\\ObjectEquals' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Object/ObjectEquals.php',
'PHPUnit\\Framework\\Constraint\\ObjectHasAttribute' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Object/ObjectHasAttribute.php', 'PHPUnit\\Framework\\Constraint\\ObjectHasAttribute' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Object/ObjectHasAttribute.php',
'PHPUnit\\Framework\\Constraint\\ObjectHasProperty' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Object/ObjectHasProperty.php',
'PHPUnit\\Framework\\Constraint\\Operator' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Operator/Operator.php', 'PHPUnit\\Framework\\Constraint\\Operator' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Operator/Operator.php',
'PHPUnit\\Framework\\Constraint\\RegularExpression' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/String/RegularExpression.php', 'PHPUnit\\Framework\\Constraint\\RegularExpression' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/String/RegularExpression.php',
'PHPUnit\\Framework\\Constraint\\SameSize' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Cardinality/SameSize.php', 'PHPUnit\\Framework\\Constraint\\SameSize' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Cardinality/SameSize.php',
@@ -369,8 +370,8 @@ return array(
'PHPUnit\\TextUI\\XmlConfiguration\\Migrator' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrator.php', 'PHPUnit\\TextUI\\XmlConfiguration\\Migrator' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrator.php',
'PHPUnit\\TextUI\\XmlConfiguration\\MoveAttributesFromFilterWhitelistToCoverage' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveAttributesFromFilterWhitelistToCoverage.php', 'PHPUnit\\TextUI\\XmlConfiguration\\MoveAttributesFromFilterWhitelistToCoverage' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveAttributesFromFilterWhitelistToCoverage.php',
'PHPUnit\\TextUI\\XmlConfiguration\\MoveAttributesFromRootToCoverage' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveAttributesFromRootToCoverage.php', 'PHPUnit\\TextUI\\XmlConfiguration\\MoveAttributesFromRootToCoverage' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveAttributesFromRootToCoverage.php',
'PHPUnit\\TextUI\\XmlConfiguration\\MoveWhitelistDirectoriesToCoverage' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveWhitelistDirectoriesToCoverage.php',
'PHPUnit\\TextUI\\XmlConfiguration\\MoveWhitelistExcludesToCoverage' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveWhitelistExcludesToCoverage.php', 'PHPUnit\\TextUI\\XmlConfiguration\\MoveWhitelistExcludesToCoverage' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveWhitelistExcludesToCoverage.php',
'PHPUnit\\TextUI\\XmlConfiguration\\MoveWhitelistIncludesToCoverage' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveWhitelistIncludesToCoverage.php',
'PHPUnit\\TextUI\\XmlConfiguration\\PHPUnit' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/PHPUnit/PHPUnit.php', 'PHPUnit\\TextUI\\XmlConfiguration\\PHPUnit' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/PHPUnit/PHPUnit.php',
'PHPUnit\\TextUI\\XmlConfiguration\\Php' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/Php.php', 'PHPUnit\\TextUI\\XmlConfiguration\\Php' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/Php.php',
'PHPUnit\\TextUI\\XmlConfiguration\\PhpHandler' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/PhpHandler.php', 'PHPUnit\\TextUI\\XmlConfiguration\\PhpHandler' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/PhpHandler.php',
@@ -876,8 +877,8 @@ return array(
'Smarty_Variable' => $vendorDir . '/egrajp/smarty-extended/src/sysplugins/smarty_variable.php', 'Smarty_Variable' => $vendorDir . '/egrajp/smarty-extended/src/sysplugins/smarty_variable.php',
'TPC_yyStackEntry' => $vendorDir . '/egrajp/smarty-extended/src/sysplugins/smarty_internal_configfileparser.php', 'TPC_yyStackEntry' => $vendorDir . '/egrajp/smarty-extended/src/sysplugins/smarty_internal_configfileparser.php',
'TP_yyStackEntry' => $vendorDir . '/egrajp/smarty-extended/src/sysplugins/smarty_internal_templateparser.php', 'TP_yyStackEntry' => $vendorDir . '/egrajp/smarty-extended/src/sysplugins/smarty_internal_templateparser.php',
'Test\\DB\\TestDB' => $baseDir . '/lib/Test/DB/TestDB.php', 'TestCalls\\DB\\TestDB' => $baseDir . '/lib/Test/DB/TestDB.php',
'Test\\Test' => $baseDir . '/lib/Test/Test.php', 'TestCalls\\Test' => $baseDir . '/lib/Test/Test.php',
'TheSeer\\Tokenizer\\Exception' => $vendorDir . '/theseer/tokenizer/src/Exception.php', 'TheSeer\\Tokenizer\\Exception' => $vendorDir . '/theseer/tokenizer/src/Exception.php',
'TheSeer\\Tokenizer\\NamespaceUri' => $vendorDir . '/theseer/tokenizer/src/NamespaceUri.php', 'TheSeer\\Tokenizer\\NamespaceUri' => $vendorDir . '/theseer/tokenizer/src/NamespaceUri.php',
'TheSeer\\Tokenizer\\NamespaceUriException' => $vendorDir . '/theseer/tokenizer/src/NamespaceUriException.php', 'TheSeer\\Tokenizer\\NamespaceUriException' => $vendorDir . '/theseer/tokenizer/src/NamespaceUriException.php',

View File

@@ -190,6 +190,7 @@ class ComposerStaticInit10fe8fe2ec4017b8644d2b64bcf398b9
'PHPUnit\\Framework\\Constraint\\LogicalXor' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/Operator/LogicalXor.php', 'PHPUnit\\Framework\\Constraint\\LogicalXor' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/Operator/LogicalXor.php',
'PHPUnit\\Framework\\Constraint\\ObjectEquals' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/Object/ObjectEquals.php', 'PHPUnit\\Framework\\Constraint\\ObjectEquals' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/Object/ObjectEquals.php',
'PHPUnit\\Framework\\Constraint\\ObjectHasAttribute' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/Object/ObjectHasAttribute.php', 'PHPUnit\\Framework\\Constraint\\ObjectHasAttribute' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/Object/ObjectHasAttribute.php',
'PHPUnit\\Framework\\Constraint\\ObjectHasProperty' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/Object/ObjectHasProperty.php',
'PHPUnit\\Framework\\Constraint\\Operator' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/Operator/Operator.php', 'PHPUnit\\Framework\\Constraint\\Operator' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/Operator/Operator.php',
'PHPUnit\\Framework\\Constraint\\RegularExpression' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/String/RegularExpression.php', 'PHPUnit\\Framework\\Constraint\\RegularExpression' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/String/RegularExpression.php',
'PHPUnit\\Framework\\Constraint\\SameSize' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/Cardinality/SameSize.php', 'PHPUnit\\Framework\\Constraint\\SameSize' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/Cardinality/SameSize.php',
@@ -420,8 +421,8 @@ class ComposerStaticInit10fe8fe2ec4017b8644d2b64bcf398b9
'PHPUnit\\TextUI\\XmlConfiguration\\Migrator' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrator.php', 'PHPUnit\\TextUI\\XmlConfiguration\\Migrator' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrator.php',
'PHPUnit\\TextUI\\XmlConfiguration\\MoveAttributesFromFilterWhitelistToCoverage' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveAttributesFromFilterWhitelistToCoverage.php', 'PHPUnit\\TextUI\\XmlConfiguration\\MoveAttributesFromFilterWhitelistToCoverage' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveAttributesFromFilterWhitelistToCoverage.php',
'PHPUnit\\TextUI\\XmlConfiguration\\MoveAttributesFromRootToCoverage' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveAttributesFromRootToCoverage.php', 'PHPUnit\\TextUI\\XmlConfiguration\\MoveAttributesFromRootToCoverage' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveAttributesFromRootToCoverage.php',
'PHPUnit\\TextUI\\XmlConfiguration\\MoveWhitelistDirectoriesToCoverage' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveWhitelistDirectoriesToCoverage.php',
'PHPUnit\\TextUI\\XmlConfiguration\\MoveWhitelistExcludesToCoverage' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveWhitelistExcludesToCoverage.php', 'PHPUnit\\TextUI\\XmlConfiguration\\MoveWhitelistExcludesToCoverage' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveWhitelistExcludesToCoverage.php',
'PHPUnit\\TextUI\\XmlConfiguration\\MoveWhitelistIncludesToCoverage' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveWhitelistIncludesToCoverage.php',
'PHPUnit\\TextUI\\XmlConfiguration\\PHPUnit' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/PHPUnit/PHPUnit.php', 'PHPUnit\\TextUI\\XmlConfiguration\\PHPUnit' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/PHPUnit/PHPUnit.php',
'PHPUnit\\TextUI\\XmlConfiguration\\Php' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/Php.php', 'PHPUnit\\TextUI\\XmlConfiguration\\Php' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/Php.php',
'PHPUnit\\TextUI\\XmlConfiguration\\PhpHandler' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/PhpHandler.php', 'PHPUnit\\TextUI\\XmlConfiguration\\PhpHandler' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/PhpHandler.php',
@@ -927,8 +928,8 @@ class ComposerStaticInit10fe8fe2ec4017b8644d2b64bcf398b9
'Smarty_Variable' => __DIR__ . '/..' . '/egrajp/smarty-extended/src/sysplugins/smarty_variable.php', 'Smarty_Variable' => __DIR__ . '/..' . '/egrajp/smarty-extended/src/sysplugins/smarty_variable.php',
'TPC_yyStackEntry' => __DIR__ . '/..' . '/egrajp/smarty-extended/src/sysplugins/smarty_internal_configfileparser.php', 'TPC_yyStackEntry' => __DIR__ . '/..' . '/egrajp/smarty-extended/src/sysplugins/smarty_internal_configfileparser.php',
'TP_yyStackEntry' => __DIR__ . '/..' . '/egrajp/smarty-extended/src/sysplugins/smarty_internal_templateparser.php', 'TP_yyStackEntry' => __DIR__ . '/..' . '/egrajp/smarty-extended/src/sysplugins/smarty_internal_templateparser.php',
'Test\\DB\\TestDB' => __DIR__ . '/../..' . '/lib/Test/DB/TestDB.php', 'TestCalls\\DB\\TestDB' => __DIR__ . '/../..' . '/lib/Test/DB/TestDB.php',
'Test\\Test' => __DIR__ . '/../..' . '/lib/Test/Test.php', 'TestCalls\\Test' => __DIR__ . '/../..' . '/lib/Test/Test.php',
'TheSeer\\Tokenizer\\Exception' => __DIR__ . '/..' . '/theseer/tokenizer/src/Exception.php', 'TheSeer\\Tokenizer\\Exception' => __DIR__ . '/..' . '/theseer/tokenizer/src/Exception.php',
'TheSeer\\Tokenizer\\NamespaceUri' => __DIR__ . '/..' . '/theseer/tokenizer/src/NamespaceUri.php', 'TheSeer\\Tokenizer\\NamespaceUri' => __DIR__ . '/..' . '/theseer/tokenizer/src/NamespaceUri.php',
'TheSeer\\Tokenizer\\NamespaceUriException' => __DIR__ . '/..' . '/theseer/tokenizer/src/NamespaceUriException.php', 'TheSeer\\Tokenizer\\NamespaceUriException' => __DIR__ . '/..' . '/theseer/tokenizer/src/NamespaceUriException.php',

View File

@@ -227,17 +227,17 @@
}, },
{ {
"name": "nikic/php-parser", "name": "nikic/php-parser",
"version": "v4.15.5", "version": "v4.17.1",
"version_normalized": "4.15.5.0", "version_normalized": "4.17.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nikic/PHP-Parser.git", "url": "https://github.com/nikic/PHP-Parser.git",
"reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e" "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/11e2663a5bc9db5d714eedb4277ee300403b4a9e", "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
"reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e", "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -248,7 +248,7 @@
"ircmaxell/php-yacc": "^0.0.7", "ircmaxell/php-yacc": "^0.0.7",
"phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
}, },
"time": "2023-05-19T20:20:00+00:00", "time": "2023-08-13T19:53:39+00:00",
"bin": [ "bin": [
"bin/php-parse" "bin/php-parse"
], ],
@@ -280,7 +280,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/nikic/PHP-Parser/issues", "issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.5" "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1"
}, },
"install-path": "../nikic/php-parser" "install-path": "../nikic/php-parser"
}, },
@@ -403,17 +403,17 @@
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
"version": "9.2.26", "version": "9.2.27",
"version_normalized": "9.2.26.0", "version_normalized": "9.2.27.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1" "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/b0a88255cb70d52653d80c890bd7f38740ea50d1",
"reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -438,7 +438,7 @@
"ext-pcov": "PHP extension that provides line coverage", "ext-pcov": "PHP extension that provides line coverage",
"ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
}, },
"time": "2023-03-06T12:58:08+00:00", "time": "2023-07-26T13:44:30+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
@@ -471,7 +471,8 @@
], ],
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26" "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.27"
}, },
"funding": [ "funding": [
{ {
@@ -736,17 +737,17 @@
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "9.6.8", "version": "9.6.11",
"version_normalized": "9.6.8.0", "version_normalized": "9.6.11.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e" "reference": "810500e92855eba8a7a5319ae913be2da6f957b0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/17d621b3aff84d0c8b62539e269e87d8d5baa76e", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/810500e92855eba8a7a5319ae913be2da6f957b0",
"reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e", "reference": "810500e92855eba8a7a5319ae913be2da6f957b0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -782,7 +783,7 @@
"ext-soap": "To be able to generate mocks based on WSDL files", "ext-soap": "To be able to generate mocks based on WSDL files",
"ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
}, },
"time": "2023-05-11T05:14:45+00:00", "time": "2023-08-19T07:10:56+00:00",
"bin": [ "bin": [
"phpunit" "phpunit"
], ],
@@ -822,7 +823,7 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues", "issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy", "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.8" "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.11"
}, },
"funding": [ "funding": [
{ {
@@ -1423,17 +1424,17 @@
}, },
{ {
"name": "sebastian/global-state", "name": "sebastian/global-state",
"version": "5.0.5", "version": "5.0.6",
"version_normalized": "5.0.5.0", "version_normalized": "5.0.6.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git", "url": "https://github.com/sebastianbergmann/global-state.git",
"reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" "reference": "bde739e7565280bda77be70044ac1047bc007e34"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34",
"reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", "reference": "bde739e7565280bda77be70044ac1047bc007e34",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1448,7 +1449,7 @@
"suggest": { "suggest": {
"ext-uopz": "*" "ext-uopz": "*"
}, },
"time": "2022-02-14T08:28:10+00:00", "time": "2023-08-02T09:26:13+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
@@ -1478,7 +1479,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues", "issues": "https://github.com/sebastianbergmann/global-state/issues",
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6"
}, },
"funding": [ "funding": [
{ {

View File

@@ -56,9 +56,9 @@
'dev_requirement' => true, 'dev_requirement' => true,
), ),
'nikic/php-parser' => array( 'nikic/php-parser' => array(
'pretty_version' => 'v4.15.5', 'pretty_version' => 'v4.17.1',
'version' => '4.15.5.0', 'version' => '4.17.1.0',
'reference' => '11e2663a5bc9db5d714eedb4277ee300403b4a9e', 'reference' => 'a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../nikic/php-parser', 'install_path' => __DIR__ . '/../nikic/php-parser',
'aliases' => array(), 'aliases' => array(),
@@ -83,9 +83,9 @@
'dev_requirement' => true, 'dev_requirement' => true,
), ),
'phpunit/php-code-coverage' => array( 'phpunit/php-code-coverage' => array(
'pretty_version' => '9.2.26', 'pretty_version' => '9.2.27',
'version' => '9.2.26.0', 'version' => '9.2.27.0',
'reference' => '443bc6912c9bd5b409254a40f4b0f4ced7c80ea1', 'reference' => 'b0a88255cb70d52653d80c890bd7f38740ea50d1',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../phpunit/php-code-coverage', 'install_path' => __DIR__ . '/../phpunit/php-code-coverage',
'aliases' => array(), 'aliases' => array(),
@@ -128,9 +128,9 @@
'dev_requirement' => true, 'dev_requirement' => true,
), ),
'phpunit/phpunit' => array( 'phpunit/phpunit' => array(
'pretty_version' => '9.6.8', 'pretty_version' => '9.6.11',
'version' => '9.6.8.0', 'version' => '9.6.11.0',
'reference' => '17d621b3aff84d0c8b62539e269e87d8d5baa76e', 'reference' => '810500e92855eba8a7a5319ae913be2da6f957b0',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../phpunit/phpunit', 'install_path' => __DIR__ . '/../phpunit/phpunit',
'aliases' => array(), 'aliases' => array(),
@@ -218,9 +218,9 @@
'dev_requirement' => true, 'dev_requirement' => true,
), ),
'sebastian/global-state' => array( 'sebastian/global-state' => array(
'pretty_version' => '5.0.5', 'pretty_version' => '5.0.6',
'version' => '5.0.5.0', 'version' => '5.0.6.0',
'reference' => '0ca8db5a5fc9c8646244e629625ac486fa286bf2', 'reference' => 'bde739e7565280bda77be70044ac1047bc007e34',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../sebastian/global-state', 'install_path' => __DIR__ . '/../sebastian/global-state',
'aliases' => array(), 'aliases' => array(),

View File

@@ -1008,7 +1008,7 @@ array_pair:
| expr { $$ = Expr\ArrayItem[$1, null, false]; } | expr { $$ = Expr\ArrayItem[$1, null, false]; }
| expr T_DOUBLE_ARROW ampersand variable { $$ = Expr\ArrayItem[$4, $1, true]; } | expr T_DOUBLE_ARROW ampersand variable { $$ = Expr\ArrayItem[$4, $1, true]; }
| ampersand variable { $$ = Expr\ArrayItem[$2, null, true]; } | ampersand variable { $$ = Expr\ArrayItem[$2, null, true]; }
| T_ELLIPSIS expr { $$ = Expr\ArrayItem[$2, null, false, attributes(), true]; } | T_ELLIPSIS expr { $$ = new Expr\ArrayItem($2, null, false, attributes(), true); }
; ;
encaps_list: encaps_list:

View File

@@ -221,7 +221,10 @@ non_empty_class_const_list:
; ;
class_const: class_const:
identifier_maybe_reserved '=' expr { $$ = Node\Const_[$1, $3]; } T_STRING '=' expr
{ $$ = Node\Const_[new Node\Identifier($1, stackAttributes(#1)), $3]; }
| semi_reserved '=' expr
{ $$ = Node\Const_[new Node\Identifier($1, stackAttributes(#1)), $3]; }
; ;
inner_statement_list_ex: inner_statement_list_ex:
@@ -722,6 +725,9 @@ class_statement:
| optional_attributes method_modifiers T_CONST class_const_list semi | optional_attributes method_modifiers T_CONST class_const_list semi
{ $$ = new Stmt\ClassConst($4, $2, attributes(), $1); { $$ = new Stmt\ClassConst($4, $2, attributes(), $1);
$this->checkClassConst($$, #2); } $this->checkClassConst($$, #2); }
| optional_attributes method_modifiers T_CONST type_expr class_const_list semi
{ $$ = new Stmt\ClassConst($5, $2, attributes(), $1, $4);
$this->checkClassConst($$, #2); }
| optional_attributes method_modifiers T_FUNCTION optional_ref identifier_maybe_reserved '(' parameter_list ')' | optional_attributes method_modifiers T_FUNCTION optional_ref identifier_maybe_reserved '(' parameter_list ')'
optional_return_type method_body optional_return_type method_body
{ $$ = Stmt\ClassMethod[$5, ['type' => $2, 'byRef' => $4, 'params' => $7, 'returnType' => $9, 'stmts' => $10, 'attrGroups' => $1]]; { $$ = Stmt\ClassMethod[$5, ['type' => $2, 'byRef' => $4, 'params' => $7, 'returnType' => $9, 'stmts' => $10, 'attrGroups' => $1]];
@@ -943,8 +949,8 @@ expr:
; ;
anonymous_class: anonymous_class:
optional_attributes T_CLASS ctor_arguments extends_from implements_list '{' class_statement_list '}' optional_attributes class_entry_type ctor_arguments extends_from implements_list '{' class_statement_list '}'
{ $$ = array(Stmt\Class_[null, ['type' => 0, 'extends' => $4, 'implements' => $5, 'stmts' => $7, 'attrGroups' => $1]], $3); { $$ = array(Stmt\Class_[null, ['type' => $2, 'extends' => $4, 'implements' => $5, 'stmts' => $7, 'attrGroups' => $1]], $3);
$this->checkClass($$[0], -1); } $this->checkClass($$[0], -1); }
; ;
@@ -1040,6 +1046,8 @@ constant:
class_constant: class_constant:
class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier_maybe_reserved class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier_maybe_reserved
{ $$ = Expr\ClassConstFetch[$1, $3]; } { $$ = Expr\ClassConstFetch[$1, $3]; }
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM '{' expr '}'
{ $$ = Expr\ClassConstFetch[$1, $4]; }
/* We interpret an isolated FOO:: as an unfinished class constant fetch. It could also be /* We interpret an isolated FOO:: as an unfinished class constant fetch. It could also be
an unfinished static property fetch or unfinished scoped call. */ an unfinished static property fetch or unfinished scoped call. */
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM error | class_name_or_var T_PAAMAYIM_NEKUDOTAYIM error
@@ -1194,7 +1202,7 @@ array_pair:
| expr T_DOUBLE_ARROW expr { $$ = Expr\ArrayItem[$3, $1, false]; } | expr T_DOUBLE_ARROW expr { $$ = Expr\ArrayItem[$3, $1, false]; }
| expr T_DOUBLE_ARROW ampersand variable { $$ = Expr\ArrayItem[$4, $1, true]; } | expr T_DOUBLE_ARROW ampersand variable { $$ = Expr\ArrayItem[$4, $1, true]; }
| expr T_DOUBLE_ARROW list_expr { $$ = Expr\ArrayItem[$3, $1, false]; } | expr T_DOUBLE_ARROW list_expr { $$ = Expr\ArrayItem[$3, $1, false]; }
| T_ELLIPSIS expr { $$ = Expr\ArrayItem[$2, null, false, attributes(), true]; } | T_ELLIPSIS expr { $$ = new Expr\ArrayItem($2, null, false, attributes(), true); }
| /* empty */ { $$ = null; } | /* empty */ { $$ = null; }
; ;

View File

@@ -19,6 +19,8 @@ class ClassConst implements PhpParser\Builder
/** @var Node\AttributeGroup[] */ /** @var Node\AttributeGroup[] */
protected $attributeGroups = []; protected $attributeGroups = [];
/** @var Identifier|Node\Name|Node\ComplexType */
protected $type;
/** /**
* Creates a class constant builder * Creates a class constant builder
@@ -116,6 +118,19 @@ class ClassConst implements PhpParser\Builder
return $this; return $this;
} }
/**
* Sets the constant type.
*
* @param string|Node\Name|Identifier|Node\ComplexType $type
*
* @return $this
*/
public function setType($type) {
$this->type = BuilderHelpers::normalizeType($type);
return $this;
}
/** /**
* Returns the built class node. * Returns the built class node.
* *
@@ -126,7 +141,8 @@ class ClassConst implements PhpParser\Builder
$this->constants, $this->constants,
$this->flags, $this->flags,
$this->attributes, $this->attributes,
$this->attributeGroups $this->attributeGroups,
$this->type
); );
} }
} }

View File

@@ -349,15 +349,15 @@ class BuilderFactory
/** /**
* Creates a class constant fetch node. * Creates a class constant fetch node.
* *
* @param string|Name|Expr $class Class name * @param string|Name|Expr $class Class name
* @param string|Identifier $name Constant name * @param string|Identifier|Expr $name Constant name
* *
* @return Expr\ClassConstFetch * @return Expr\ClassConstFetch
*/ */
public function classConstFetch($class, $name): Expr\ClassConstFetch { public function classConstFetch($class, $name): Expr\ClassConstFetch {
return new Expr\ClassConstFetch( return new Expr\ClassConstFetch(
BuilderHelpers::normalizeNameOrExpr($class), BuilderHelpers::normalizeNameOrExpr($class),
BuilderHelpers::normalizeIdentifier($name) BuilderHelpers::normalizeIdentifierOrExpr($name)
); );
} }

View File

@@ -19,6 +19,8 @@ class PrintableNewAnonClassNode extends Expr
{ {
/** @var Node\AttributeGroup[] PHP attribute groups */ /** @var Node\AttributeGroup[] PHP attribute groups */
public $attrGroups; public $attrGroups;
/** @var int Modifiers */
public $flags;
/** @var Node\Arg[] Arguments */ /** @var Node\Arg[] Arguments */
public $args; public $args;
/** @var null|Node\Name Name of extended class */ /** @var null|Node\Name Name of extended class */
@@ -29,11 +31,12 @@ class PrintableNewAnonClassNode extends Expr
public $stmts; public $stmts;
public function __construct( public function __construct(
array $attrGroups, array $args, Node\Name $extends = null, array $implements, array $attrGroups, int $flags, array $args, Node\Name $extends = null, array $implements,
array $stmts, array $attributes array $stmts, array $attributes
) { ) {
parent::__construct($attributes); parent::__construct($attributes);
$this->attrGroups = $attrGroups; $this->attrGroups = $attrGroups;
$this->flags = $flags;
$this->args = $args; $this->args = $args;
$this->extends = $extends; $this->extends = $extends;
$this->implements = $implements; $this->implements = $implements;
@@ -46,7 +49,7 @@ class PrintableNewAnonClassNode extends Expr
// We don't assert that $class->name is null here, to allow consumers to assign unique names // We don't assert that $class->name is null here, to allow consumers to assign unique names
// to anonymous classes for their own purposes. We simplify ignore the name here. // to anonymous classes for their own purposes. We simplify ignore the name here.
return new self( return new self(
$class->attrGroups, $newNode->args, $class->extends, $class->implements, $class->attrGroups, $class->flags, $newNode->args, $class->extends, $class->implements,
$class->stmts, $newNode->getAttributes() $class->stmts, $newNode->getAttributes()
); );
} }
@@ -56,6 +59,6 @@ class PrintableNewAnonClassNode extends Expr
} }
public function getSubNodeNames() : array { public function getSubNodeNames() : array {
return ['attrGroups', 'args', 'extends', 'implements', 'stmts']; return ['attrGroups', 'flags', 'args', 'extends', 'implements', 'stmts'];
} }
} }

Some files were not shown because too many files have changed in this diff Show More