Compare commits

...

23 Commits

Author SHA1 Message Date
Clemens Schwaighofer
f90bd193d9 Change setError to setMessage to make it clear what is the corret name 2023-09-08 18:54:44 +09:00
Clemens Schwaighofer
0e31180868 Rename setErrorMsgLevel to setError for backend calls 2023-09-08 18:47:44 +09:00
Clemens Schwaighofer
68c9164eaa New ErrorMessage class for frontend return error messages 2023-09-08 18:30:05 +09:00
Clemens Schwaighofer
c2389db1c9 Composer updates 2023-09-08 18:30:02 +09:00
Clemens Schwaighofer
f9558cd3aa Fix for the SetVarType / SetVarTypeNull
string: if it is stringable in anyway, set string (it converts)
this is not check IF it is a string value as it was before
int/float: same, if it is numerc it will be convert to int or float
All other stay the same

Note "set ..." imply to set, and not to convert to 0 if it is int
string that can be covnerted to int
2023-09-05 14:26:57 +09:00
Clemens Schwaighofer
ae3011fe22 php unit test fix for DB\IO 2023-09-01 18:29:00 +09:00
Clemens Schwaighofer
9b9dfeac69 phan error supress 2023-09-01 18:21:25 +09:00
Clemens Schwaighofer
33cb05a002 Update to Exceptions: add codes, update phpunit tests
DB Class throws Exception if on init it fails to connect to the DB,
will not throw Exception if failed connection during execution but
will do the normal retry and soft failure run
DB\ArrayIO will throw Exception on missing table array and table name

All Exceptions have a code set
2023-09-01 08:37:15 +09:00
Clemens Schwaighofer
ec110499a8 phan fixs 2023-08-31 19:06:16 +09:00
Clemens Schwaighofer
09839f3451 phpstan fixes 2023-08-31 19:04:45 +09:00
Clemens Schwaighofer
067e0aed5d L10n change Exception to RuntimeException 2023-08-31 18:08:34 +09:00
Clemens Schwaighofer
545de5c4a1 Fixed more Exceptions to be not Errors but Exceptions
DateTime, Session, FileWrite, Image, SymmetricEncryption

phpunit tests updated, run checks added
2023-08-31 18:06:02 +09:00
Clemens Schwaighofer
2fe37bf92a Exceptions change in Check\Colors, add in Cmbined\ArrayHandler
Chech\Colors now throws correct exceptions for wrong values
Combined\ArrayHandler will throw errors and not return false
2023-08-31 12:07:28 +09:00
Clemens Schwaighofer
cd81d15d9a Convert\Color methods will throw Exception instead of false on error
All Color methods will throw Exceptions:
LengthException,
InvalidArgumentException,
UnexpectedValueException

instead of returning bool: false

All methods will return valid color data as expected only
2023-08-31 10:45:33 +09:00
Clemens Schwaighofer
8a33ee5c15 Slight update for ACL\Login class exit codes
exit will add message as first parameter (string) next to code (int)
Log this to info or critical.
3000 -> 100: info
rest >=1000: critical
previous 4000 = 3000 (options not set)

update unit tests for this

Possible change idea: critical abort throw error?
2023-08-31 10:41:44 +09:00
Clemens Schwaighofer
46e1419ef5 phan checks and updates 2023-08-30 19:26:13 +09:00
Clemens Schwaighofer
c441063437 Composer updates 2023-08-30 19:25:48 +09:00
Clemens Schwaighofer
5290d5f351 Update db class tests in admin run 2023-08-28 09:28:17 +09:00
Clemens Schwaighofer
2635ccb82b edit.css: rename animation, Bug fix in DB\IO cursor_ext access and others
Make sure cursor_ext is set before we access it, else return null for
not set yet.
false for errors, else data value

Other class var access checks to be sure to never fail
2023-08-28 07:40:41 +09:00
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
337 changed files with 7200 additions and 4823 deletions

View File

@@ -132,6 +132,8 @@ return [
// start ignore annotations // start ignore annotations
'PhanUnextractableAnnotationElementName', 'PhanUnextractableAnnotationElementName',
'PhanUnextractableAnnotationSuffix', 'PhanUnextractableAnnotationSuffix',
// enum problems in comments
'PhanCommentObjectInClassConstantType'
], ],
// Override to hardcode existence and types of (non-builtin) globals in the global scope. // Override to hardcode existence and types of (non-builtin) globals in the global scope.

View File

@@ -167,8 +167,10 @@ final class CoreLibsACLLoginTest extends TestCase
// change_password, pw_username, pw_old_password, pw_new_password, // change_password, pw_username, pw_old_password, pw_new_password,
// pw_new_password_confirm // pw_new_password_confirm
// 3[session]: override session set // 3[session]: override session set
// 4[error] : expected error code, 0 for all ok, 3000 for login page view // 4[error] : expected error code, 0 for all ok, 100 for login page view
// note that 1000 (no db), 2000 (no session) must be tested too // note that 1000 (no db), 2000 (no session), 3000 (options set error)
// must be tested too
// <1000 info, >=1000 critical error
// 5[return] : expected return array, eg login_error code, // 5[return] : expected return array, eg login_error code,
// or other info data to match // or other info data to match
$tests = [ $tests = [
@@ -180,7 +182,7 @@ final class CoreLibsACLLoginTest extends TestCase
[], [],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 0, 'login_error' => 0,
'error_string' => 'Success: <b>No error</b>', 'error_string' => 'Success: <b>No error</b>',
@@ -198,7 +200,7 @@ final class CoreLibsACLLoginTest extends TestCase
[], [],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 0, 'login_error' => 0,
'error_string' => 'Success: <b>No error</b>', 'error_string' => 'Success: <b>No error</b>',
@@ -221,7 +223,7 @@ final class CoreLibsACLLoginTest extends TestCase
[], [],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 0, 'login_error' => 0,
'error_string' => 'Success: <b>No error</b>', 'error_string' => 'Success: <b>No error</b>',
@@ -308,7 +310,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => '', 'login_password' => '',
], ],
[], [],
3000, 100,
[ [
'login_error' => 102, 'login_error' => 102,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -329,7 +331,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'abc', 'login_password' => 'abc',
], ],
[], [],
3000, 100,
[ [
'login_error' => 102, 'login_error' => 102,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -350,7 +352,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => '', 'login_password' => '',
], ],
[], [],
3000, 100,
[ [
'login_error' => 102, 'login_error' => 102,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -371,7 +373,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'abc', 'login_password' => 'abc',
], ],
[], [],
3000, 100,
[ [
'login_error' => 1010, 'login_error' => 1010,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -395,7 +397,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'abc', 'login_password' => 'abc',
], ],
[], [],
3000, 100,
[ [
// default password is plain text // default password is plain text
'login_error' => 1012, 'login_error' => 1012,
@@ -421,7 +423,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin', 'login_password' => 'admin',
], ],
[], [],
3000, 100,
[ [
'login_error' => 106, 'login_error' => 106,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -446,7 +448,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin', 'login_password' => 'admin',
], ],
[], [],
3000, 100,
[ [
'login_error' => 104, 'login_error' => 104,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -471,7 +473,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin', 'login_password' => 'admin',
], ],
[], [],
3000, 100,
[ [
'login_error' => 105, 'login_error' => 105,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -520,7 +522,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin', 'login_password' => 'admin',
], ],
[], [],
3000, 100,
[ [
'login_error' => 107, 'login_error' => 107,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -574,7 +576,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin', 'login_password' => 'admin',
], ],
[], [],
3000, 100,
[ [
'login_error' => 107, 'login_error' => 107,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -600,7 +602,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin', 'login_password' => 'admin',
], ],
[], [],
3000, 100,
[ [
'login_error' => 107, 'login_error' => 107,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -625,7 +627,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin', 'login_password' => 'admin',
], ],
[], [],
3000, 100,
[ [
'login_error' => 108, 'login_error' => 108,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -761,7 +763,7 @@ final class CoreLibsACLLoginTest extends TestCase
], ],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 1010, 'login_error' => 1010,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -853,7 +855,7 @@ final class CoreLibsACLLoginTest extends TestCase
], ],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 1101, 'login_error' => 1101,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -909,7 +911,7 @@ final class CoreLibsACLLoginTest extends TestCase
], ],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 1102, 'login_error' => 1102,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -965,7 +967,7 @@ final class CoreLibsACLLoginTest extends TestCase
], ],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 1102, 'login_error' => 1102,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -992,7 +994,7 @@ final class CoreLibsACLLoginTest extends TestCase
], ],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 1102, 'login_error' => 1102,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -1133,7 +1135,7 @@ final class CoreLibsACLLoginTest extends TestCase
$login_mock->expects($this->any()) $login_mock->expects($this->any())
->method('loginTerminate') ->method('loginTerminate')
->will( ->will(
$this->returnCallback(function ($code) { $this->returnCallback(function ($message, $code) {
throw new \Exception('', $code); throw new \Exception('', $code);
}) })
); );
@@ -1227,7 +1229,11 @@ final class CoreLibsACLLoginTest extends TestCase
$login_mock->loginSetMaxLoginErrorCount($mock_settings['max_login_error_count']); $login_mock->loginSetMaxLoginErrorCount($mock_settings['max_login_error_count']);
// temporary wrong password // temporary wrong password
$_POST['login_password'] = 'wrong'; $_POST['login_password'] = 'wrong';
for ($run = 1, $max_run = $login_mock->loginGetMaxLoginErrorCount(); $run <= $max_run; $run++) { for (
$run = 1, $max_run = $login_mock->loginGetMaxLoginErrorCount();
$run <= $max_run;
$run++
) {
try { try {
$login_mock->loginMainCall(); $login_mock->loginMainCall();
} catch (\Exception $e) { } catch (\Exception $e) {
@@ -1475,10 +1481,10 @@ final class CoreLibsACLLoginTest extends TestCase
// print "AJAX: " . $login_mock->loginGetAjaxFlag() . "\n"; // print "AJAX: " . $login_mock->loginGetAjaxFlag() . "\n";
// print "AJAX GLOBAL: " . ($GLOBALS['AJAX_PAGE'] ?? '{f}') . "\n"; // print "AJAX GLOBAL: " . ($GLOBALS['AJAX_PAGE'] ?? '{f}') . "\n";
// print "Login error expext: " . ($expected['login_error'] ?? '{0}') . "\n"; // print "Login error expext: " . ($expected['login_error'] ?? '{0}') . "\n";
// if this is 3000, then we do further error checks // if this is 100, then we do further error checks
if ( if (
$e->getCode() == 3000 || $e->getCode() == 100 ||
!empty($_POST['login_exit']) && $_POST['login_exit'] == 3000 !empty($_POST['login_exit']) && $_POST['login_exit'] == 100
) { ) {
$this->assertEquals( $this->assertEquals(
$expected['login_error'], $expected['login_error'],
@@ -1816,7 +1822,7 @@ final class CoreLibsACLLoginTest extends TestCase
$login_mock->expects($this->any()) $login_mock->expects($this->any())
->method('loginTerminate') ->method('loginTerminate')
->will( ->will(
$this->returnCallback(function ($code) { $this->returnCallback(function ($message, $code) {
throw new \Exception('', $code); throw new \Exception('', $code);
}) })
); );
@@ -1930,7 +1936,7 @@ final class CoreLibsACLLoginTest extends TestCase
$login_mock->expects($this->any()) $login_mock->expects($this->any())
->method('loginTerminate') ->method('loginTerminate')
->will( ->will(
$this->returnCallback(function ($code) { $this->returnCallback(function ($message, $code) {
throw new \Exception('', $code); throw new \Exception('', $code);
}) })
); );
@@ -2018,7 +2024,7 @@ final class CoreLibsACLLoginTest extends TestCase
$login_mock->expects($this->any()) $login_mock->expects($this->any())
->method('loginTerminate') ->method('loginTerminate')
->will( ->will(
$this->returnCallback(function ($code) { $this->returnCallback(function ($message, $code) {
throw new \Exception('', $code); throw new \Exception('', $code);
}) })
); );
@@ -2114,7 +2120,7 @@ final class CoreLibsACLLoginTest extends TestCase
$login_mock->expects($this->any()) $login_mock->expects($this->any())
->method('loginTerminate') ->method('loginTerminate')
->will( ->will(
$this->returnCallback(function ($code) { $this->returnCallback(function ($message, $code) {
throw new \Exception('', $code); throw new \Exception('', $code);
}) })
); );

View File

@@ -13,6 +13,11 @@ use PHPUnit\Framework\TestCase;
*/ */
final class CoreLibsCheckColorsTest extends TestCase final class CoreLibsCheckColorsTest extends TestCase
{ {
/**
* Undocumented function
*
* @return array<mixed>
*/
public function validateColorProvider(): array public function validateColorProvider(): array
{ {
/* /*
@@ -321,7 +326,7 @@ final class CoreLibsCheckColorsTest extends TestCase
*/ */
public function testValidateColorException(int $flag): void public function testValidateColorException(int $flag): void
{ {
$this->expectException(\Exception::class); $this->expectException(\UnexpectedValueException::class);
\CoreLibs\Check\Colors::validateColor('#ffffff', $flag); \CoreLibs\Check\Colors::validateColor('#ffffff', $flag);
} }
} }

View File

@@ -518,17 +518,20 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
return [ return [
// error <2 arguments // error <2 arguments
'too view arguments' => [ 'too view arguments' => [
'ArgumentCountError',
'arrayMergeRecursive needs two or more array arguments', 'arrayMergeRecursive needs two or more array arguments',
[1] [1]
], ],
// error <2 arrays // error <2 arrays
'only one array' => [ 'only one array' => [
'ArgumentCountError',
'arrayMergeRecursive needs two or more array arguments', 'arrayMergeRecursive needs two or more array arguments',
[1], [1],
true, true,
], ],
// error element is not array // error element is not array
'non array between array' => [ 'non array between array' => [
'TypeError',
'arrayMergeRecursive encountered a non array argument', 'arrayMergeRecursive encountered a non array argument',
[1], [1],
'string', 'string',
@@ -947,18 +950,20 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
*/ */
public function testArrayMergeRecursiveWarningA(): void public function testArrayMergeRecursiveWarningA(): void
{ {
set_error_handler( // set_error_handler(
static function (int $errno, string $errstr): never { // static function (int $errno, string $errstr): never {
throw new Exception($errstr, $errno); // throw new Exception($errstr, $errno);
}, // },
E_USER_WARNING // E_USER_WARNING
); // );
$arrays = func_get_args(); $arrays = func_get_args();
// first is expected warning // first is expected warning
$exception = array_shift($arrays);
$warning = array_shift($arrays); $warning = array_shift($arrays);
// phpunit 10.0 compatible // phpunit 10.0 compatible
$this->expectException($exception);
$this->expectExceptionMessage($warning); $this->expectExceptionMessage($warning);
\CoreLibs\Combined\ArrayHandler::arrayMergeRecursive(...$arrays); \CoreLibs\Combined\ArrayHandler::arrayMergeRecursive(...$arrays);

View File

@@ -309,45 +309,73 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
'2020-12-12', '2020-12-12',
'2021-12-12', '2021-12-12',
-1, -1,
null,
null,
], ],
'dates equal' => [ 'dates equal' => [
'2020-12-12', '2020-12-12',
'2020-12-12', '2020-12-12',
0, 0,
null,
null,
], ],
'second date smaller' => [ 'second date smaller' => [
'2021-12-12', '2021-12-12',
'2020-12-12', '2020-12-12',
1 1,
null,
null,
], ],
'dates equal with different time' => [ 'dates equal with different time' => [
'2020-12-12 12:12:12', '2020-12-12 12:12:12',
'2020-12-12 13:13:13', '2020-12-12 13:13:13',
0, 0,
null,
null,
], ],
'invalid dates --' => [ 'invalid dates --' => [
'--', '--',
'--', '--',
false false,
'UnexpectedValueException',
1,
], ],
'empty dates' => [ 'empty dates' => [
'', '',
'', '',
false false,
'UnexpectedValueException',
1
], ],
'invalid dates' => [ 'invalid dates' => [
'not a date', 'not a date',
'not a date either', 'not a date either',
false, false,
'UnexpectedValueException',
2
],
'invalid end date' => [
'1990-01-01',
'not a date either',
false,
'UnexpectedValueException',
3
], ],
'out of bound dates' => [ 'out of bound dates' => [
'1900-1-1', '1900-1-1',
'9999-12-31', '9999-12-31',
-1 -1,
null,
null,
] ]
]; ];
} }
/**
* Undocumented function
*
* @return array<mixed>
*/
public function dateTimeCompareProvider(): array public function dateTimeCompareProvider(): array
{ {
return [ return [
@@ -355,51 +383,85 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
'2020-12-12', '2020-12-12',
'2021-12-12', '2021-12-12',
-1, -1,
null,
null,
], ],
'dates equal no timestamp' => [ 'dates equal no timestamp' => [
'2020-12-12', '2020-12-12',
'2020-12-12', '2020-12-12',
0, 0,
null,
null,
], ],
'second date smaller no timestamp' => [ 'second date smaller no timestamp' => [
'2021-12-12', '2021-12-12',
'2020-12-12', '2020-12-12',
1 1,
null,
null,
], ],
'date equal first time smaller' => [ 'date equal first time smaller' => [
'2020-12-12 12:12:12', '2020-12-12 12:12:12',
'2020-12-12 13:13:13', '2020-12-12 13:13:13',
-1, -1,
null,
null,
], ],
'date equal time equal' => [ 'date equal time equal' => [
'2020-12-12 12:12:12', '2020-12-12 12:12:12',
'2020-12-12 12:12:12', '2020-12-12 12:12:12',
0, 0,
null,
null,
], ],
'date equal second time smaller' => [ 'date equal second time smaller' => [
'2020-12-12 13:13:13', '2020-12-12 13:13:13',
'2020-12-12 12:12:12', '2020-12-12 12:12:12',
1, 1,
null,
null,
], ],
'valid date invalid time' => [ 'valid date invalid time' => [
'2020-12-12 13:99:13', '2020-12-12 13:99:13',
'2020-12-12 12:12:99', '2020-12-12 12:12:99',
false, false,
'UnexpectedValueException',
2
],
'valid date invalid end time' => [
'2020-12-12 13:12:13',
'2020-12-12 12:12:99',
false,
'UnexpectedValueException',
3
], ],
'invalid datetimes --' => [ 'invalid datetimes --' => [
'--', '--',
'--', '--',
false, false,
'UnexpectedValueException',
1
], ],
'empty datetimess' => [ 'empty datetimess' => [
'', '',
'', '',
false, false,
'UnexpectedValueException',
1
], ],
'invalid datetimes' => [ 'invalid date times' => [
'not a date', 'not a date',
'not a date either', 'not a date either',
false, false,
'UnexpectedValueException',
2
],
'invalid end date time' => [
'1990-01-01 12:12:12',
'not a date either',
false,
'UnexpectedValueException',
3
], ],
]; ];
} }
@@ -614,10 +676,21 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
* @param string $input_a * @param string $input_a
* @param string $input_b * @param string $input_b
* @param int|bool $expected * @param int|bool $expected
* @param string|null $exception
* @param int|null $exception_code
* @return void * @return void
*/ */
public function testCompareDate(string $input_a, string $input_b, $expected): void public function testCompareDate(
{ string $input_a,
string $input_b,
int|bool $expected,
?string $exception,
?int $exception_code
): void {
if ($expected === false) {
$this->expectException($exception);
$this->expectExceptionCode($exception_code);
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Combined\DateTime::compareDate($input_a, $input_b) \CoreLibs\Combined\DateTime::compareDate($input_a, $input_b)
@@ -634,10 +707,21 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
* @param string $input_a * @param string $input_a
* @param string $input_b * @param string $input_b
* @param int|bool $expected * @param int|bool $expected
* @param string|null $exception
* @param int|null $exception_code
* @return void * @return void
*/ */
public function testCompareDateTime(string $input_a, string $input_b, $expected): void public function testCompareDateTime(
{ string $input_a,
string $input_b,
int|bool $expected,
?string $exception,
?int $exception_code
): void {
if ($expected === false) {
$this->expectException($exception);
$this->expectExceptionCode($exception_code);
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Combined\DateTime::compareDateTime($input_a, $input_b) \CoreLibs\Combined\DateTime::compareDateTime($input_a, $input_b)

View File

@@ -59,6 +59,27 @@ final class CoreLibsConvertColorsTest extends TestCase
3 => false, 3 => false,
4 => false 4 => false
], ],
'invalid color red ' => [
0 => -12,
1 => 12,
2 => 12,
3 => false,
4 => false
],
'invalid color green ' => [
0 => 12,
1 => -12,
2 => 12,
3 => false,
4 => false
],
'invalid color blue ' => [
0 => 12,
1 => 12,
2 => -12,
3 => false,
4 => false
],
]; ];
} }
@@ -150,10 +171,40 @@ final class CoreLibsConvertColorsTest extends TestCase
'valid' => true, 'valid' => true,
], ],
// invalid values // invalid values
'invalid color' => [ 'invalid color r/h/h low' => [
'rgb' => [-12, 300, 12], 'rgb' => [-1, 12, 12],
'hsb' => [-12, 300, 12], 'hsb' => [-1, 50, 50],
'hsl' => [-12, 300, 12], 'hsl' => [-1, 50, 50],
'valid' => false,
],
'invalid color r/h/h high' => [
'rgb' => [256, 12, 12],
'hsb' => [361, 50, 50],
'hsl' => [361, 50, 50],
'valid' => false,
],
'invalid color g/s/s low' => [
'rgb' => [12, -1, 12],
'hsb' => [1, -1, 50],
'hsl' => [1, -1, 50],
'valid' => false,
],
'invalid color g/s/s high' => [
'rgb' => [12, 256, 12],
'hsb' => [1, 101, 50],
'hsl' => [1, 101, 50],
'valid' => false,
],
'invalid color b/b/l low' => [
'rgb' => [12, 12, -1],
'hsb' => [1, 50, -1],
'hsl' => [1, 50, -1],
'valid' => false,
],
'invalid color b/b/l high' => [
'rgb' => [12, 12, 256],
'hsb' => [1, 50, 101],
'hsl' => [1, 50, 101],
'valid' => false, 'valid' => false,
], ],
]; ];
@@ -246,11 +297,22 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param int $input_r * @param int $input_r
* @param int $input_g * @param int $input_g
* @param int $input_b * @param int $input_b
* @param string|bool $expected_hash
* @param string|bool $expected * @param string|bool $expected
* @return void * @return void
*/ */
public function testRgb2hex(int $input_r, int $input_g, int $input_b, $expected_hash, $expected) public function testRgb2hex(
{ int $input_r,
int $input_g,
int $input_b,
string|bool $expected_hash,
string|bool $expected
) {
// if expected hash is or expected is false, we need to check for
// LengthException
if ($expected_hash === false || $expected === false) {
$this->expectException(\LengthException::class);
}
// with # // with #
$this->assertEquals( $this->assertEquals(
$expected_hash, $expected_hash,
@@ -292,11 +354,19 @@ final class CoreLibsConvertColorsTest extends TestCase
*/ */
public function testHex2rgb( public function testHex2rgb(
string $input, string $input,
$expected, array|bool $expected,
$expected_str, string|bool $expected_str,
string $separator, string $separator,
$expected_str_sep string|bool $expected_str_sep
): void { ): void {
if ($expected === false || $expected_str === false || $expected_str_sep === false) {
$hex_string = preg_replace("/[^0-9A-Fa-f]/", '', $input);
if (!is_string($hex_string)) {
$this->expectException(\InvalidArgumentException::class);
} else {
$this->expectException(\UnexpectedValueException::class);
}
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Convert\Colors::hex2rgb($input) \CoreLibs\Convert\Colors::hex2rgb($input)
@@ -324,8 +394,11 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param array|bool $expected * @param array|bool $expected
* @return void * @return void
*/ */
public function testRgb2hsb(int $input_r, int $input_g, int $input_b, $expected): void public function testRgb2hsb(int $input_r, int $input_g, int $input_b, array|bool $expected): void
{ {
if ($expected === false) {
$this->expectException(\LengthException::class);
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Convert\Colors::rgb2hsb($input_r, $input_g, $input_b) \CoreLibs\Convert\Colors::rgb2hsb($input_r, $input_g, $input_b)
@@ -345,8 +418,12 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param array|bool $expected * @param array|bool $expected
* @return void * @return void
*/ */
public function testHsb2rgb(float $input_h, float $input_s, float $input_b, $expected): void public function testHsb2rgb(float $input_h, float $input_s, float $input_b, array|bool $expected): void
{ {
if ($expected === false) {
$this->expectException(\LengthException::class);
$expected = [];
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Convert\Colors::hsb2rgb($input_h, $input_s, $input_b) \CoreLibs\Convert\Colors::hsb2rgb($input_h, $input_s, $input_b)
@@ -366,8 +443,11 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param array|bool $expected * @param array|bool $expected
* @return void * @return void
*/ */
public function testRgb2hsl(int $input_r, int $input_g, int $input_b, $expected): void public function testRgb2hsl(int $input_r, int $input_g, int $input_b, array|bool $expected): void
{ {
if ($expected === false) {
$this->expectException(\LengthException::class);
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Convert\Colors::rgb2hsl($input_r, $input_g, $input_b) \CoreLibs\Convert\Colors::rgb2hsl($input_r, $input_g, $input_b)
@@ -387,8 +467,11 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param array|bool $expected * @param array|bool $expected
* @return void * @return void
*/ */
public function testHsl2rgb($input_h, float $input_s, float $input_l, $expected): void public function testHsl2rgb(int|float $input_h, float $input_s, float $input_l, array|bool $expected): void
{ {
if ($expected === false) {
$this->expectException(\LengthException::class);
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Convert\Colors::hsl2rgb($input_h, $input_s, $input_l) \CoreLibs\Convert\Colors::hsl2rgb($input_h, $input_s, $input_l)
@@ -406,11 +489,11 @@ final class CoreLibsConvertColorsTest extends TestCase
*/ */
public function testHslHsb360hue(): void public function testHslHsb360hue(): void
{ {
$this->assertNotFalse( $this->assertIsArray(
\CoreLibs\Convert\Colors::hsl2rgb(360.0, 90.5, 41.2), \CoreLibs\Convert\Colors::hsl2rgb(360.0, 90.5, 41.2),
'HSL to RGB with 360 hue' 'HSL to RGB with 360 hue'
); );
$this->assertNotFalse( $this->assertIsArray(
\CoreLibs\Convert\Colors::hsb2rgb(360, 95, 78.0), \CoreLibs\Convert\Colors::hsb2rgb(360, 95, 78.0),
'HSB to RGB with 360 hue' 'HSB to RGB with 360 hue'
); );

View File

@@ -43,12 +43,17 @@ final class CoreLibsConvertSetVarTypeNullTest extends TestCase
'int, no override' => [ 'int, no override' => [
1, 1,
null, null,
null '1'
], ],
'int, override set' => [ 'int, override set' => [
1, 1,
'not int', 'not int',
'not int' '1'
],
'array, override set' => [
[1, 2],
null,
null
] ]
]; ];
} }
@@ -201,7 +206,7 @@ final class CoreLibsConvertSetVarTypeNullTest extends TestCase
'float' => [ 'float' => [
1.5, 1.5,
null, null,
null 1
] ]
]; ];
} }
@@ -349,7 +354,7 @@ final class CoreLibsConvertSetVarTypeNullTest extends TestCase
'int' => [ 'int' => [
1, 1,
null, null,
null 1.0
] ]
]; ];
} }

View File

@@ -43,11 +43,16 @@ final class CoreLibsConvertSetVarTypeTest extends TestCase
'int, no override' => [ 'int, no override' => [
1, 1,
null, null,
'' '1'
], ],
'int, override set' => [ 'int, override set' => [
1, 1,
'not int', 'not int',
'1'
],
'array, override set' => [
[1, 2],
'not int',
'not int' 'not int'
] ]
]; ];
@@ -189,7 +194,7 @@ final class CoreLibsConvertSetVarTypeTest extends TestCase
'float' => [ 'float' => [
1.5, 1.5,
null, null,
0 1
] ]
]; ];
} }
@@ -330,7 +335,7 @@ final class CoreLibsConvertSetVarTypeTest extends TestCase
'int' => [ 'int' => [
1, 1,
null, null,
0.0 1.0
] ]
]; ];
} }
@@ -341,7 +346,7 @@ final class CoreLibsConvertSetVarTypeTest extends TestCase
* @dataProvider varSetTypeFloatProvider * @dataProvider varSetTypeFloatProvider
* @testdox setFloat $input with override $default will be $expected [$_dataName] * @testdox setFloat $input with override $default will be $expected [$_dataName]
* *
* @param mixed $input * @param mixed $input
* @param float|null $default * @param float|null $default
* @param float $expected * @param float $expected
* @return void * @return void

View File

@@ -30,8 +30,10 @@ final class CoreLibsCreateSessionTest extends TestCase
// setSessionName: true/false, // setSessionName: true/false,
// checkActiveSession: true/false, [1st call, 2nd call] // checkActiveSession: true/false, [1st call, 2nd call]
// getSessionId: string or false // getSessionId: string or false
// 3: exepcted name (session) // 3: exepcted name (session)]
// 4: expected error string // 4: Exception thrown on error
// 5: exception code, null for none
// 6: expected error string
return [ return [
'session parameter' => [ 'session parameter' => [
'sessionNameParameter', 'sessionNameParameter',
@@ -44,7 +46,9 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'sessionNameParameter', 'sessionNameParameter',
'' null,
null,
'',
], ],
'session globals' => [ 'session globals' => [
'sessionNameGlobals', 'sessionNameGlobals',
@@ -57,7 +61,9 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'sessionNameGlobals', 'sessionNameGlobals',
'' null,
null,
'',
], ],
'session name default' => [ 'session name default' => [
'', '',
@@ -70,7 +76,9 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'', '',
'' null,
null,
'',
], ],
// error checks // error checks
// 1: we are in cli // 1: we are in cli
@@ -85,6 +93,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'', '',
'RuntimeException',
1,
'[SESSION] No sessions in php cli' '[SESSION] No sessions in php cli'
], ],
// 2: session disabled // 2: session disabled
@@ -99,6 +109,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'', '',
'RuntimeException',
2,
'[SESSION] Sessions are disabled' '[SESSION] Sessions are disabled'
], ],
// 3: invalid session name: string // 3: invalid session name: string
@@ -113,6 +125,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'', '',
'UnexpectedValueException',
3,
'[SESSION] Invalid session name: 1invalid$session#;' '[SESSION] Invalid session name: 1invalid$session#;'
], ],
// 3: invalid session name: only numbers // 3: invalid session name: only numbers
@@ -127,6 +141,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'', '',
'UnexpectedValueException',
3,
'[SESSION] Invalid session name: 123' '[SESSION] Invalid session name: 123'
], ],
// 3: invalid session name: invalid name short // 3: invalid session name: invalid name short
@@ -143,6 +159,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'', '',
'RuntimeException',
4,
'[SESSION] Failed to activate session' '[SESSION] Failed to activate session'
], ],
// 5: get session id return false // 5: get session id return false
@@ -157,6 +175,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => false 'getSessionId' => false
], ],
'', '',
'UnexpectedValueException',
5,
'[SESSION] getSessionId did not return a session id' '[SESSION] getSessionId did not return a session id'
], ],
]; ];
@@ -173,6 +193,7 @@ final class CoreLibsCreateSessionTest extends TestCase
* @param string $type * @param string $type
* @param array<mixed> $mock_data * @param array<mixed> $mock_data
* @param string $expected * @param string $expected
* @param string|null $exception
* @param string $expected_error * @param string $expected_error
* @return void * @return void
*/ */
@@ -181,6 +202,8 @@ final class CoreLibsCreateSessionTest extends TestCase
string $type, string $type,
array $mock_data, array $mock_data,
string $expected, string $expected,
?string $exception,
?int $exception_code,
string $expected_error string $expected_error
): void { ): void {
// override expected // override expected
@@ -224,6 +247,11 @@ final class CoreLibsCreateSessionTest extends TestCase
// regex for session id // regex for session id
$ression_id_regex = "/^\w+$/"; $ression_id_regex = "/^\w+$/";
if ($exception !== null) {
$this->expectException($exception);
$this->expectExceptionCode($exception_code);
}
unset($GLOBALS['SET_SESSION_NAME']); unset($GLOBALS['SET_SESSION_NAME']);
$session_id = ''; $session_id = '';
switch ($type) { switch ($type) {
@@ -253,13 +281,6 @@ final class CoreLibsCreateSessionTest extends TestCase
$expected, $expected,
$session_mock->getSessionName() $session_mock->getSessionName()
); );
} else {
// false checks
$this->assertEquals(
$expected_error,
$session_mock->getErrorStr(),
'error assert'
);
} }
} }

View File

@@ -445,12 +445,14 @@ final class CoreLibsDBIOTest extends TestCase
{ {
// 0: connection array // 0: connection array
// 1: status after connection // 1: status after connection
// 2: exception name
// 2: info string // 2: info string
// 3: ??? // 3: ???
return [ return [
'invalid connection' => [ 'invalid connection' => [
self::$db_config['invalid'], self::$db_config['invalid'],
false, false,
'RuntimeException',
"-DB-info-> Connected to db '' with schema 'public' as user " "-DB-info-> Connected to db '' with schema 'public' as user "
. "'' at host '' on port '5432' with ssl mode 'allow' **** " . "'' at host '' on port '5432' with ssl mode 'allow' **** "
. "-DB-info-> DB IO Class debug output: Yes **** ", . "-DB-info-> DB IO Class debug output: Yes **** ",
@@ -459,6 +461,7 @@ final class CoreLibsDBIOTest extends TestCase
'valid connection' => [ 'valid connection' => [
self::$db_config['valid'], self::$db_config['valid'],
true, true,
'',
"-DB-info-> Connected to db 'corelibs_db_io_test' with " "-DB-info-> Connected to db 'corelibs_db_io_test' with "
. "schema 'public' as user 'corelibs_db_io_test' at host " . "schema 'public' as user 'corelibs_db_io_test' at host "
. "'localhost' on port '5432' with ssl mode 'allow' **** " . "'localhost' on port '5432' with ssl mode 'allow' **** "
@@ -475,13 +478,21 @@ final class CoreLibsDBIOTest extends TestCase
* @dataProvider connectionProvider * @dataProvider connectionProvider
* @testdox Connection will be $expected [$_dataName] * @testdox Connection will be $expected [$_dataName]
* *
* @param array $connection
* @param bool $expected_status
* @param string $exception
* @param string $expected_string
* @return void * @return void
*/ */
public function testConnection( public function testConnection(
array $connection, array $connection,
bool $expected_status, bool $expected_status,
string $exception,
string $expected_string string $expected_string
): void { ): void {
if ($expected_status === false) {
$this->expectException($exception);
}
$db = new \CoreLibs\DB\IO( $db = new \CoreLibs\DB\IO(
$connection, $connection,
self::$log self::$log
@@ -722,6 +733,10 @@ final class CoreLibsDBIOTest extends TestCase
*/ */
public function testGetSetting(string $connection, array $settings): void public function testGetSetting(string $connection, array $settings): void
{ {
// if settings are all empty -> assume exception
if (empty($settings['db_name']) && empty($settings['db_user'])) {
$this->expectException('RuntimeException');
}
$db = new \CoreLibs\DB\IO( $db = new \CoreLibs\DB\IO(
self::$db_config[$connection], self::$db_config[$connection],
self::$log self::$log

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

@@ -0,0 +1,284 @@
<?php
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
use CoreLibs\Logging\Logger\Level;
/**
* Test class for Logging
* @coversDefaultClass \CoreLibs\Logging\ErrorMessages
* @testdox \CoreLibs\Logging\ErrorMEssages method tests
*/
final class CoreLibsLoggingErrorMessagesTest extends TestCase
{
private const LOG_FOLDER = __DIR__ . DIRECTORY_SEPARATOR . 'log' . DIRECTORY_SEPARATOR;
/**
* tear down and remove log data
*
* @return void
*/
public static function tearDownAfterClass(): void
{
array_map('unlink', glob(self::LOG_FOLDER . '*.log'));
}
/**
* for checking level only
*
* @return array
*/
public function providerErrorMessageLevel(): array
{
return [
'ok' => [
'level' => 'ok',
'str' => 'OK',
'expected' => 'ok',
],
'info' => [
'level' => 'info',
'str' => 'INFO',
'expected' => 'info',
],
'warn' => [
'level' => 'warn',
'str' => 'WARN',
'expected' => 'warn'
],
'warning' => [
'level' => 'warning',
'str' => 'WARN',
'expected' => 'warn'
],
'error' => [
'level' => 'error',
'str' => 'ERROR',
'expected' => 'error'
],
'abort' => [
'level' => 'abort',
'str' => 'ABORT',
'expected' => 'abort'
],
'crash' => [
'level' => 'crash',
'str' => 'CRASH',
'expected' => 'crash'
],
'wrong level' => [
'level' => 'wrong',
'str' => 'WRONG',
'expected' => 'unknown'
]
];
}
/**
* Undocumented function
*
* @dataProvider providerErrorMessageLevel
* @testdox error message level: $level will be $expected [$_dataName]
*
* @param string $level
* @param string $str
* @param string $expected
* @return void
*/
public function testErrorMessageLevelOk(string $level, string $str, string $expected): void
{
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testErrorMessages',
'log_folder' => self::LOG_FOLDER,
'log_level' => Level::Debug,
]);
$em = new \CoreLibs\Logging\ErrorMessage($log);
$em->setMessage(
$level,
$str
);
$this->assertEquals(
[
'level' => $expected,
'str' => $str,
'id' => '',
'target' => '',
'highlight' => [],
],
$em->getLastErrorMsg()
);
}
/**
* Undocumented function
*
* @testdox Test of all methods for n messages [$_dataName]
*
* @return void
*/
public function testErrorMessageOk(): void
{
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testErrorMessages',
'log_folder' => self::LOG_FOLDER,
'log_level' => Level::Debug
]);
$em = new \CoreLibs\Logging\ErrorMessage($log);
$em->setErrorMsg(
'100',
'info',
'INFO MESSAGE'
);
$this->assertEquals(
[
'id' => '100',
'level' => 'info',
'str' => 'INFO MESSAGE',
'target' => '',
'highlight' => [],
],
$em->getLastErrorMsg()
);
$this->assertEquals(
['100'],
$em->getErrorIds()
);
$this->assertEquals(
[
[
'id' => '100',
'level' => 'info',
'str' => 'INFO MESSAGE',
'target' => '',
'highlight' => [],
]
],
$em->getErrorMsg()
);
$em->setErrorMsg(
'200',
'error',
'ERROR MESSAGE'
);
$this->assertEquals(
[
'id' => '200',
'level' => 'error',
'str' => 'ERROR MESSAGE',
'target' => '',
'highlight' => [],
],
$em->getLastErrorMsg()
);
$this->assertEquals(
['100', '200'],
$em->getErrorIds()
);
$this->assertEquals(
[
[
'id' => '100',
'level' => 'info',
'str' => 'INFO MESSAGE',
'target' => '',
'highlight' => [],
],
[
'id' => '200',
'level' => 'error',
'str' => 'ERROR MESSAGE',
'target' => '',
'highlight' => [],
]
],
$em->getErrorMsg()
);
}
public function providerErrorMessageLog(): array
{
return [
'crash' => [
'id' => '300',
'level' => 'crash',
'str' => 'CRASH MESSAGE',
'message' => null,
'expected' => '<ALERT> CRASH MESSAGE',
],
'crash, message' => [
'id' => '300',
'level' => 'crash',
'str' => 'CRASH MESSAGE',
'message' => 'OTHER CRASH MESSAGE',
'expected' => '<ALERT> OTHER CRASH MESSAGE',
],
'abort' => [
'id' => '200',
'level' => 'abort',
'str' => 'ABORT MESSAGE',
'message' => null,
'expected' => '<CRITICAL> ABORT MESSAGE',
],
'abort, message' => [
'id' => '200',
'level' => 'abort',
'str' => 'ABORT MESSAGE',
'message' => 'OTHER ABORT MESSAGE',
'expected' => '<CRITICAL> OTHER ABORT MESSAGE',
],
'unknown' => [
'id' => '400',
'level' => 'wrong level',
'str' => 'WRONG LEVEL MESSAGE',
'message' => null,
'expected' => '<EMERGENCY> WRONG LEVEL MESSAGE',
],
'unknown, message' => [
'id' => '400',
'level' => 'wrong level',
'str' => 'WRONG LEVEL MESSAGE',
'message' => 'OTHER WRONG LEVEL MESSAGE',
'expected' => '<EMERGENCY> OTHER WRONG LEVEL MESSAGE',
],
];
}
/**
* Undocumented function
*
* @dataProvider providerErrorMessageLog
* @testdox Test Log writing [$_dataName]
*
* @return void
*/
public function testErrorMessageLog(string $id, string $level, string $str, ?string $message, string $expected)
{
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testErrorMessages',
'log_folder' => self::LOG_FOLDER,
'log_level' => Level::Debug,
'log_per_run' => true
]);
$em = new \CoreLibs\Logging\ErrorMessage($log);
$em->setErrorMsg(
$id,
$level,
$str,
message: $message
);
$file_content = file_get_contents(
$log->getLogFolder() . $log->getLogFile()
) ?: '';
$this->assertStringContainsString(
$expected,
$file_content
);
}
}
// __END__

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
{ {

171
composer.lock generated
View File

@@ -297,16 +297,16 @@
}, },
{ {
"name": "composer/semver", "name": "composer/semver",
"version": "3.3.2", "version": "3.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/composer/semver.git", "url": "https://github.com/composer/semver.git",
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9" "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9", "url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32",
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9", "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -356,9 +356,9 @@
"versioning" "versioning"
], ],
"support": { "support": {
"irc": "irc://irc.freenode.org/composer", "irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/semver/issues", "issues": "https://github.com/composer/semver/issues",
"source": "https://github.com/composer/semver/tree/3.3.2" "source": "https://github.com/composer/semver/tree/3.4.0"
}, },
"funding": [ "funding": [
{ {
@@ -374,7 +374,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-04-01T19:23:25+00:00" "time": "2023-08-31T09:50:34+00:00"
}, },
{ {
"name": "composer/xdebug-handler", "name": "composer/xdebug-handler",
@@ -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.24.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": "3510b0a6274cc42f7219367cb3abfc123ffa09d6"
}, },
"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/3510b0a6274cc42f7219367cb3abfc123ffa09d6",
"reference": "a2b24135c35852b348894320d47b3902a94bc494", "reference": "3510b0a6274cc42f7219367cb3abfc123ffa09d6",
"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.24.0"
}, },
"time": "2023-07-23T22:17:56+00:00" "time": "2023-09-07T20:46:32+00:00"
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "1.10.26", "version": "1.10.33",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "5d660cbb7e1b89253a47147ae44044f49832351f" "reference": "03b1cf9f814ba0863c4e9affea49a4d1ed9a2ed1"
}, },
"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/03b1cf9f814ba0863c4e9affea49a4d1ed9a2ed1",
"reference": "5d660cbb7e1b89253a47147ae44044f49832351f", "reference": "03b1cf9f814ba0863c4e9affea49a4d1ed9a2ed1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1238,25 +1238,25 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-07-19T12:44:37+00:00" "time": "2023-09-04T12:20:53+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",
@@ -1539,16 +1539,16 @@
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v6.3.2", "version": "v6.3.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "aa5d64ad3f63f2e48964fc81ee45cb318a723898" "reference": "eca495f2ee845130855ddf1cf18460c38966c8b6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/aa5d64ad3f63f2e48964fc81ee45cb318a723898", "url": "https://api.github.com/repos/symfony/console/zipball/eca495f2ee845130855ddf1cf18460c38966c8b6",
"reference": "aa5d64ad3f63f2e48964fc81ee45cb318a723898", "reference": "eca495f2ee845130855ddf1cf18460c38966c8b6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1609,7 +1609,7 @@
"terminal" "terminal"
], ],
"support": { "support": {
"source": "https://github.com/symfony/console/tree/v6.3.2" "source": "https://github.com/symfony/console/tree/v6.3.4"
}, },
"funding": [ "funding": [
{ {
@@ -1625,7 +1625,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-07-19T20:17:28+00:00" "time": "2023-08-16T10:10:12+00:00"
}, },
{ {
"name": "symfony/deprecation-contracts", "name": "symfony/deprecation-contracts",
@@ -1759,16 +1759,16 @@
}, },
{ {
"name": "symfony/polyfill-ctype", "name": "symfony/polyfill-ctype",
"version": "v1.27.0", "version": "v1.28.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git", "url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a" "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a", "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1783,7 +1783,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "1.27-dev" "dev-main": "1.28-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
@@ -1821,7 +1821,7 @@
"portable" "portable"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0"
}, },
"funding": [ "funding": [
{ {
@@ -1837,20 +1837,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-11-03T14:55:06+00:00" "time": "2023-01-26T09:26:14+00:00"
}, },
{ {
"name": "symfony/polyfill-intl-grapheme", "name": "symfony/polyfill-intl-grapheme",
"version": "v1.27.0", "version": "v1.28.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
"reference": "511a08c03c1960e08a883f4cffcacd219b758354" "reference": "875e90aeea2777b6f135677f618529449334a612"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354", "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612",
"reference": "511a08c03c1960e08a883f4cffcacd219b758354", "reference": "875e90aeea2777b6f135677f618529449334a612",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1862,7 +1862,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "1.27-dev" "dev-main": "1.28-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
@@ -1902,7 +1902,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0" "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0"
}, },
"funding": [ "funding": [
{ {
@@ -1918,20 +1918,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-11-03T14:55:06+00:00" "time": "2023-01-26T09:26:14+00:00"
}, },
{ {
"name": "symfony/polyfill-intl-normalizer", "name": "symfony/polyfill-intl-normalizer",
"version": "v1.27.0", "version": "v1.28.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1943,7 +1943,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "1.27-dev" "dev-main": "1.28-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
@@ -1986,7 +1986,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0"
}, },
"funding": [ "funding": [
{ {
@@ -2002,20 +2002,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-11-03T14:55:06+00:00" "time": "2023-01-26T09:26:14+00:00"
}, },
{ {
"name": "symfony/polyfill-mbstring", "name": "symfony/polyfill-mbstring",
"version": "v1.27.0", "version": "v1.28.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git", "url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" "reference": "42292d99c55abe617799667f454222c54c60e229"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", "reference": "42292d99c55abe617799667f454222c54c60e229",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2030,7 +2030,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "1.27-dev" "dev-main": "1.28-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
@@ -2069,7 +2069,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
}, },
"funding": [ "funding": [
{ {
@@ -2085,20 +2085,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-11-03T14:55:06+00:00" "time": "2023-07-28T09:04:16+00:00"
}, },
{ {
"name": "symfony/polyfill-php80", "name": "symfony/polyfill-php80",
"version": "v1.27.0", "version": "v1.28.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-php80.git", "url": "https://github.com/symfony/polyfill-php80.git",
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2107,7 +2107,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "1.27-dev" "dev-main": "1.28-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
@@ -2152,7 +2152,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0"
}, },
"funding": [ "funding": [
{ {
@@ -2168,7 +2168,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-11-03T14:55:06+00:00" "time": "2023-01-26T09:26:14+00:00"
}, },
{ {
"name": "symfony/service-contracts", "name": "symfony/service-contracts",
@@ -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

@@ -248,17 +248,17 @@
}, },
{ {
"name": "composer/semver", "name": "composer/semver",
"version": "3.3.2", "version": "3.4.0",
"version_normalized": "3.3.2.0", "version_normalized": "3.4.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/composer/semver.git", "url": "https://github.com/composer/semver.git",
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9" "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9", "url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32",
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9", "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -268,7 +268,7 @@
"phpstan/phpstan": "^1.4", "phpstan/phpstan": "^1.4",
"symfony/phpunit-bridge": "^4.2 || ^5" "symfony/phpunit-bridge": "^4.2 || ^5"
}, },
"time": "2022-04-01T19:23:25+00:00", "time": "2023-08-31T09:50:34+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
@@ -310,9 +310,9 @@
"versioning" "versioning"
], ],
"support": { "support": {
"irc": "irc://irc.freenode.org/composer", "irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/semver/issues", "issues": "https://github.com/composer/semver/issues",
"source": "https://github.com/composer/semver/tree/3.3.2" "source": "https://github.com/composer/semver/tree/3.4.0"
}, },
"funding": [ "funding": [
{ {
@@ -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.24.0",
"version_normalized": "1.23.0.0", "version_normalized": "1.24.0.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": "3510b0a6274cc42f7219367cb3abfc123ffa09d6"
}, },
"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/3510b0a6274cc42f7219367cb3abfc123ffa09d6",
"reference": "a2b24135c35852b348894320d47b3902a94bc494", "reference": "3510b0a6274cc42f7219367cb3abfc123ffa09d6",
"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-09-07T20:46:32+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.24.0"
}, },
"install-path": "../phpstan/phpdoc-parser" "install-path": "../phpstan/phpdoc-parser"
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "1.10.26", "version": "1.10.33",
"version_normalized": "1.10.26.0", "version_normalized": "1.10.33.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "5d660cbb7e1b89253a47147ae44044f49832351f" "reference": "03b1cf9f814ba0863c4e9affea49a4d1ed9a2ed1"
}, },
"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/03b1cf9f814ba0863c4e9affea49a4d1ed9a2ed1",
"reference": "5d660cbb7e1b89253a47147ae44044f49832351f", "reference": "03b1cf9f814ba0863c4e9affea49a4d1ed9a2ed1",
"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-09-04T12:20:53+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"
}, },
@@ -1609,17 +1609,17 @@
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v6.3.2", "version": "v6.3.4",
"version_normalized": "6.3.2.0", "version_normalized": "6.3.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "aa5d64ad3f63f2e48964fc81ee45cb318a723898" "reference": "eca495f2ee845130855ddf1cf18460c38966c8b6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/aa5d64ad3f63f2e48964fc81ee45cb318a723898", "url": "https://api.github.com/repos/symfony/console/zipball/eca495f2ee845130855ddf1cf18460c38966c8b6",
"reference": "aa5d64ad3f63f2e48964fc81ee45cb318a723898", "reference": "eca495f2ee845130855ddf1cf18460c38966c8b6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1648,7 +1648,7 @@
"symfony/process": "^5.4|^6.0", "symfony/process": "^5.4|^6.0",
"symfony/var-dumper": "^5.4|^6.0" "symfony/var-dumper": "^5.4|^6.0"
}, },
"time": "2023-07-19T20:17:28+00:00", "time": "2023-08-16T10:10:12+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@@ -1682,7 +1682,7 @@
"terminal" "terminal"
], ],
"support": { "support": {
"source": "https://github.com/symfony/console/tree/v6.3.2" "source": "https://github.com/symfony/console/tree/v6.3.4"
}, },
"funding": [ "funding": [
{ {
@@ -1838,17 +1838,17 @@
}, },
{ {
"name": "symfony/polyfill-ctype", "name": "symfony/polyfill-ctype",
"version": "v1.27.0", "version": "v1.28.0",
"version_normalized": "1.27.0.0", "version_normalized": "1.28.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git", "url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a" "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a", "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1860,11 +1860,11 @@
"suggest": { "suggest": {
"ext-ctype": "For best performance" "ext-ctype": "For best performance"
}, },
"time": "2022-11-03T14:55:06+00:00", "time": "2023-01-26T09:26:14+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "1.27-dev" "dev-main": "1.28-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
@@ -1903,7 +1903,7 @@
"portable" "portable"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0"
}, },
"funding": [ "funding": [
{ {
@@ -1923,17 +1923,17 @@
}, },
{ {
"name": "symfony/polyfill-intl-grapheme", "name": "symfony/polyfill-intl-grapheme",
"version": "v1.27.0", "version": "v1.28.0",
"version_normalized": "1.27.0.0", "version_normalized": "1.28.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
"reference": "511a08c03c1960e08a883f4cffcacd219b758354" "reference": "875e90aeea2777b6f135677f618529449334a612"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354", "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612",
"reference": "511a08c03c1960e08a883f4cffcacd219b758354", "reference": "875e90aeea2777b6f135677f618529449334a612",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1942,11 +1942,11 @@
"suggest": { "suggest": {
"ext-intl": "For best performance" "ext-intl": "For best performance"
}, },
"time": "2022-11-03T14:55:06+00:00", "time": "2023-01-26T09:26:14+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "1.27-dev" "dev-main": "1.28-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
@@ -1987,7 +1987,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0" "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0"
}, },
"funding": [ "funding": [
{ {
@@ -2007,17 +2007,17 @@
}, },
{ {
"name": "symfony/polyfill-intl-normalizer", "name": "symfony/polyfill-intl-normalizer",
"version": "v1.27.0", "version": "v1.28.0",
"version_normalized": "1.27.0.0", "version_normalized": "1.28.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2026,11 +2026,11 @@
"suggest": { "suggest": {
"ext-intl": "For best performance" "ext-intl": "For best performance"
}, },
"time": "2022-11-03T14:55:06+00:00", "time": "2023-01-26T09:26:14+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "1.27-dev" "dev-main": "1.28-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
@@ -2074,7 +2074,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0"
}, },
"funding": [ "funding": [
{ {
@@ -2094,17 +2094,17 @@
}, },
{ {
"name": "symfony/polyfill-mbstring", "name": "symfony/polyfill-mbstring",
"version": "v1.27.0", "version": "v1.28.0",
"version_normalized": "1.27.0.0", "version_normalized": "1.28.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git", "url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" "reference": "42292d99c55abe617799667f454222c54c60e229"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", "reference": "42292d99c55abe617799667f454222c54c60e229",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2116,11 +2116,11 @@
"suggest": { "suggest": {
"ext-mbstring": "For best performance" "ext-mbstring": "For best performance"
}, },
"time": "2022-11-03T14:55:06+00:00", "time": "2023-07-28T09:04:16+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "1.27-dev" "dev-main": "1.28-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
@@ -2160,7 +2160,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
}, },
"funding": [ "funding": [
{ {
@@ -2180,27 +2180,27 @@
}, },
{ {
"name": "symfony/polyfill-php80", "name": "symfony/polyfill-php80",
"version": "v1.27.0", "version": "v1.28.0",
"version_normalized": "1.27.0.0", "version_normalized": "1.28.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-php80.git", "url": "https://github.com/symfony/polyfill-php80.git",
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=7.1" "php": ">=7.1"
}, },
"time": "2022-11-03T14:55:06+00:00", "time": "2023-01-26T09:26:14+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "1.27-dev" "dev-main": "1.28-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
@@ -2246,7 +2246,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0"
}, },
"funding": [ "funding": [
{ {
@@ -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

@@ -38,9 +38,9 @@
'dev_requirement' => true, 'dev_requirement' => true,
), ),
'composer/semver' => array( 'composer/semver' => array(
'pretty_version' => '3.3.2', 'pretty_version' => '3.4.0',
'version' => '3.3.2.0', 'version' => '3.4.0.0',
'reference' => '3953f23262f2bff1919fc82183ad9acb13ff62c9', 'reference' => '35e8d0af4486141bc745f23a29cc2091eb624a32',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/./semver', 'install_path' => __DIR__ . '/./semver',
'aliases' => array(), 'aliases' => array(),
@@ -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.24.0',
'version' => '1.23.0.0', 'version' => '1.24.0.0',
'reference' => 'a2b24135c35852b348894320d47b3902a94bc494', 'reference' => '3510b0a6274cc42f7219367cb3abfc123ffa09d6',
'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.33',
'version' => '1.10.26.0', 'version' => '1.10.33.0',
'reference' => '5d660cbb7e1b89253a47147ae44044f49832351f', 'reference' => '03b1cf9f814ba0863c4e9affea49a4d1ed9a2ed1',
'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(
@@ -266,9 +266,9 @@
'dev_requirement' => true, 'dev_requirement' => true,
), ),
'symfony/console' => array( 'symfony/console' => array(
'pretty_version' => 'v6.3.2', 'pretty_version' => 'v6.3.4',
'version' => '6.3.2.0', 'version' => '6.3.4.0',
'reference' => 'aa5d64ad3f63f2e48964fc81ee45cb318a723898', 'reference' => 'eca495f2ee845130855ddf1cf18460c38966c8b6',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/console', 'install_path' => __DIR__ . '/../symfony/console',
'aliases' => array(), 'aliases' => array(),
@@ -293,45 +293,45 @@
'dev_requirement' => true, 'dev_requirement' => true,
), ),
'symfony/polyfill-ctype' => array( 'symfony/polyfill-ctype' => array(
'pretty_version' => 'v1.27.0', 'pretty_version' => 'v1.28.0',
'version' => '1.27.0.0', 'version' => '1.28.0.0',
'reference' => '5bbc823adecdae860bb64756d639ecfec17b050a', 'reference' => 'ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-ctype', 'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
'aliases' => array(), 'aliases' => array(),
'dev_requirement' => true, 'dev_requirement' => true,
), ),
'symfony/polyfill-intl-grapheme' => array( 'symfony/polyfill-intl-grapheme' => array(
'pretty_version' => 'v1.27.0', 'pretty_version' => 'v1.28.0',
'version' => '1.27.0.0', 'version' => '1.28.0.0',
'reference' => '511a08c03c1960e08a883f4cffcacd219b758354', 'reference' => '875e90aeea2777b6f135677f618529449334a612',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-grapheme', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-grapheme',
'aliases' => array(), 'aliases' => array(),
'dev_requirement' => true, 'dev_requirement' => true,
), ),
'symfony/polyfill-intl-normalizer' => array( 'symfony/polyfill-intl-normalizer' => array(
'pretty_version' => 'v1.27.0', 'pretty_version' => 'v1.28.0',
'version' => '1.27.0.0', 'version' => '1.28.0.0',
'reference' => '19bd1e4fcd5b91116f14d8533c57831ed00571b6', 'reference' => '8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer',
'aliases' => array(), 'aliases' => array(),
'dev_requirement' => true, 'dev_requirement' => true,
), ),
'symfony/polyfill-mbstring' => array( 'symfony/polyfill-mbstring' => array(
'pretty_version' => 'v1.27.0', 'pretty_version' => 'v1.28.0',
'version' => '1.27.0.0', 'version' => '1.28.0.0',
'reference' => '8ad114f6b39e2c98a8b0e3bd907732c207c2b534', 'reference' => '42292d99c55abe617799667f454222c54c60e229',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
'aliases' => array(), 'aliases' => array(),
'dev_requirement' => true, 'dev_requirement' => true,
), ),
'symfony/polyfill-php80' => array( 'symfony/polyfill-php80' => array(
'pretty_version' => 'v1.27.0', 'pretty_version' => 'v1.28.0',
'version' => '1.27.0.0', 'version' => '1.28.0.0',
'reference' => '7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936', 'reference' => '6caa57379c4aec19c0a12a38b59b26487dcfe4b5',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php80', 'install_path' => __DIR__ . '/../symfony/polyfill-php80',
'aliases' => array(), 'aliases' => 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

@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/). This project adheres to [Semantic Versioning](http://semver.org/).
### [3.4.0] 2023-08-31
* Support larger major version numbers (#149)
### [3.3.2] 2022-04-01 ### [3.3.2] 2022-04-01
* Fixed handling of non-string values (#134) * Fixed handling of non-string values (#134)
@@ -175,6 +179,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Namespace: `Composer\Test\Package\LinkConstraint` -> `Composer\Test\Semver\Constraint` - Namespace: `Composer\Test\Package\LinkConstraint` -> `Composer\Test\Semver\Constraint`
* Changed: code style using php-cs-fixer. * Changed: code style using php-cs-fixer.
[3.4.0]: https://github.com/composer/semver/compare/3.3.2...3.4.0
[3.3.2]: https://github.com/composer/semver/compare/3.3.1...3.3.2 [3.3.2]: https://github.com/composer/semver/compare/3.3.1...3.3.2
[3.3.1]: https://github.com/composer/semver/compare/3.3.0...3.3.1 [3.3.1]: https://github.com/composer/semver/compare/3.3.0...3.3.1
[3.3.0]: https://github.com/composer/semver/compare/3.2.9...3.3.0 [3.3.0]: https://github.com/composer/semver/compare/3.2.9...3.3.0

View File

@@ -6,8 +6,9 @@ Semver (Semantic Versioning) library that offers utilities, version constraint p
Originally written as part of [composer/composer](https://github.com/composer/composer), Originally written as part of [composer/composer](https://github.com/composer/composer),
now extracted and made available as a stand-alone library. now extracted and made available as a stand-alone library.
[![Continuous Integration](https://github.com/composer/semver/workflows/Continuous%20Integration/badge.svg?branch=main)](https://github.com/composer/semver/actions) [![Continuous Integration](https://github.com/composer/semver/actions/workflows/continuous-integration.yml/badge.svg?branch=main)](https://github.com/composer/semver/actions/workflows/continuous-integration.yml)
[![PHP Lint](https://github.com/composer/semver/actions/workflows/lint.yml/badge.svg?branch=main)](https://github.com/composer/semver/actions/workflows/lint.yml)
[![PHPStan](https://github.com/composer/semver/actions/workflows/phpstan.yml/badge.svg?branch=main)](https://github.com/composer/semver/actions/workflows/phpstan.yml)
Installation Installation
------------ ------------
@@ -15,7 +16,7 @@ Installation
Install the latest version with: Install the latest version with:
```bash ```bash
$ composer require composer/semver composer require composer/semver
``` ```

View File

@@ -27,7 +27,7 @@
} }
], ],
"support": { "support": {
"irc": "irc://irc.freenode.org/composer", "irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/semver/issues" "issues": "https://github.com/composer/semver/issues"
}, },
"require": { "require": {

View File

@@ -0,0 +1,11 @@
parameters:
ignoreErrors:
-
message: "#^Parameter \\#1 \\$operator of class Composer\\\\Semver\\\\Constraint\\\\Constraint constructor expects '\\!\\='\\|'\\<'\\|'\\<\\='\\|'\\<\\>'\\|'\\='\\|'\\=\\='\\|'\\>'\\|'\\>\\=', non\\-falsy\\-string given\\.$#"
count: 1
path: src/VersionParser.php
-
message: "#^Strict comparison using \\=\\=\\= between null and non\\-empty\\-string will always evaluate to false\\.$#"
count: 2
path: src/VersionParser.php

View File

@@ -134,15 +134,15 @@ class VersionParser
} }
// match classical versioning // match classical versioning
if (preg_match('{^v?(\d{1,5})(\.\d++)?(\.\d++)?(\.\d++)?' . self::$modifierRegex . '$}i', $version, $matches)) { if (preg_match('{^v?(\d{1,5}+)(\.\d++)?(\.\d++)?(\.\d++)?' . self::$modifierRegex . '$}i', $version, $matches)) {
$version = $matches[1] $version = $matches[1]
. (!empty($matches[2]) ? $matches[2] : '.0') . (!empty($matches[2]) ? $matches[2] : '.0')
. (!empty($matches[3]) ? $matches[3] : '.0') . (!empty($matches[3]) ? $matches[3] : '.0')
. (!empty($matches[4]) ? $matches[4] : '.0'); . (!empty($matches[4]) ? $matches[4] : '.0');
$index = 5; $index = 5;
// match date(time) based versioning // match date(time) based versioning
} elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3})?)' . self::$modifierRegex . '$}i', $version, $matches)) { } elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3}){0,2})' . self::$modifierRegex . '$}i', $version, $matches)) {
$version = preg_replace('{\D}', '.', $matches[1]); $version = (string) preg_replace('{\D}', '.', $matches[1]);
$index = 2; $index = 2;
} }
@@ -260,16 +260,16 @@ class VersionParser
} }
$orGroups = array(); $orGroups = array();
foreach ($orConstraints as $constraints) { foreach ($orConstraints as $orConstraint) {
$andConstraints = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $constraints); $andConstraints = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $orConstraint);
if (false === $andConstraints) { if (false === $andConstraints) {
throw new \RuntimeException('Failed to preg_split string: '.$constraints); throw new \RuntimeException('Failed to preg_split string: '.$orConstraint);
} }
if (\count($andConstraints) > 1) { if (\count($andConstraints) > 1) {
$constraintObjects = array(); $constraintObjects = array();
foreach ($andConstraints as $constraint) { foreach ($andConstraints as $andConstraint) {
foreach ($this->parseConstraint($constraint) as $parsedConstraint) { foreach ($this->parseConstraint($andConstraint) as $parsedAndConstraint) {
$constraintObjects[] = $parsedConstraint; $constraintObjects[] = $parsedAndConstraint;
} }
} }
} else { } else {
@@ -285,11 +285,11 @@ class VersionParser
$orGroups[] = $constraint; $orGroups[] = $constraint;
} }
$constraint = MultiConstraint::create($orGroups, false); $parsedConstraint = MultiConstraint::create($orGroups, false);
$constraint->setPrettyString($prettyConstraint); $parsedConstraint->setPrettyString($prettyConstraint);
return $constraint; return $parsedConstraint;
} }
/** /**

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;
@@ -29,7 +29,7 @@ class ClassConstFetch extends Expr
public function getSubNodeNames() : array { public function getSubNodeNames() : array {
return ['class', 'name']; return ['class', 'name'];
} }
public function getType() : string { public function getType() : string {
return 'Expr_ClassConstFetch'; return 'Expr_ClassConstFetch';
} }

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;
@@ -678,24 +682,34 @@ class PhpDocParser
$tokens->dropSavePoint(); // because of ConstFetchNode $tokens->dropSavePoint(); // because of ConstFetchNode
} }
$exception = new ParserException( $currentTokenValue = $tokens->currentTokenValue();
$tokens->currentTokenValue(), $currentTokenType = $tokens->currentTokenType();
$tokens->currentTokenType(), $currentTokenOffset = $tokens->currentTokenOffset();
$tokens->currentTokenOffset(), $currentTokenLine = $tokens->currentTokenLine();
Lexer::TOKEN_IDENTIFIER,
null,
$tokens->currentTokenLine()
);
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 new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
} }
return $constExpr; return $constExpr;
} catch (LogicException $e) { } catch (LogicException $e) {
throw $exception; throw new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
} }
} }
@@ -750,14 +764,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 +801,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(),
@@ -1112,15 +1127,13 @@ class PhpDocParser
{ {
if ($tokens->isCurrentTokenType(Lexer::TOKEN_THIS_VARIABLE)) { if ($tokens->isCurrentTokenType(Lexer::TOKEN_THIS_VARIABLE)) {
$parameter = '$this'; $parameter = '$this';
$requirePropertyOrMethod = true;
$tokens->next(); $tokens->next();
} else { } else {
$parameter = $tokens->currentTokenValue(); $parameter = $tokens->currentTokenValue();
$requirePropertyOrMethod = false;
$tokens->consumeTokenType(Lexer::TOKEN_VARIABLE); $tokens->consumeTokenType(Lexer::TOKEN_VARIABLE);
} }
if ($requirePropertyOrMethod || $tokens->isCurrentTokenType(Lexer::TOKEN_ARROW)) { if ($tokens->isCurrentTokenType(Lexer::TOKEN_ARROW)) {
$tokens->consumeTokenType(Lexer::TOKEN_ARROW); $tokens->consumeTokenType(Lexer::TOKEN_ARROW);
$propertyOrMethod = $tokens->currentTokenValue(); $propertyOrMethod = $tokens->currentTokenValue();

View File

@@ -196,28 +196,45 @@ class TypeParser
$tokens->dropSavePoint(); // because of ConstFetchNode $tokens->dropSavePoint(); // because of ConstFetchNode
} }
$exception = new ParserException( $currentTokenValue = $tokens->currentTokenValue();
$tokens->currentTokenValue(), $currentTokenType = $tokens->currentTokenType();
$tokens->currentTokenType(), $currentTokenOffset = $tokens->currentTokenOffset();
$tokens->currentTokenOffset(), $currentTokenLine = $tokens->currentTokenLine();
Lexer::TOKEN_IDENTIFIER,
null,
$tokens->currentTokenLine()
);
if ($this->constExprParser === null) { if ($this->constExprParser === null) {
throw $exception; throw new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
} }
try { try {
$constExpr = $this->constExprParser->parse($tokens, true); $constExpr = $this->constExprParser->parse($tokens, true);
if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) { if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) {
throw $exception; throw new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
} }
return $this->enrichWithAttributes($tokens, new Ast\Type\ConstTypeNode($constExpr), $startLine, $startIndex); return $this->enrichWithAttributes($tokens, new Ast\Type\ConstTypeNode($constExpr), $startLine, $startIndex);
} catch (LogicException $e) { } catch (LogicException $e) {
throw $exception; throw new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
} }
} }
@@ -600,23 +617,33 @@ class TypeParser
} }
} }
$exception = new ParserException( $currentTokenValue = $tokens->currentTokenValue();
$tokens->currentTokenValue(), $currentTokenType = $tokens->currentTokenType();
$tokens->currentTokenType(), $currentTokenOffset = $tokens->currentTokenOffset();
$tokens->currentTokenOffset(), $currentTokenLine = $tokens->currentTokenLine();
Lexer::TOKEN_IDENTIFIER,
null,
$tokens->currentTokenLine()
);
if ($this->constExprParser === null) { if ($this->constExprParser === null) {
throw $exception; throw new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
} }
try { try {
$constExpr = $this->constExprParser->parse($tokens, true); $constExpr = $this->constExprParser->parse($tokens, true);
if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) { if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) {
throw $exception; throw new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
} }
$type = new Ast\Type\ConstTypeNode($constExpr); $type = new Ast\Type\ConstTypeNode($constExpr);
@@ -631,7 +658,14 @@ class TypeParser
return $type; return $type;
} catch (LogicException $e) { } catch (LogicException $e) {
throw $exception; throw new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
} }
} }

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/C5cAFAmT1y40ACgkQUcZzBf/C
5cCvmg/+JJmyX663fa+FHy7ED2SexVuChivpbp82dyLx1gRAl15rtNG4zjxNRfnW 5cDm6Q//VupQizxW3TICxhwzMDz05+nI8d72mn5vd94Niat90L1wPVHSZ9eBQSs3
6GpsysMhKqrN7p6xur18ZkLqdFKAjeNnpTunnh/ADetcrs8wzLNyAy7luQtyXAuj xMGVKJufB/3tQp6rviYk0aFnTFsKYkgwQYSDk1P9D7VrcJdpB461P3FT4MGsRk8E
SOv5f/Yitg9yvZ2GHrbzchQuSjkbUR2KroBYsRhwVTH7pMIgdvysRBYiENfbz350 SSo55EuMGpiVvgoKbiPXeYV76yEpSMpelbKDNTm7iglLFVQKAnTv17aQv/UdBoYk
n91WOCApDnVCygzEhBbhkwA/xklJnUxkRJX3AlbbCwES9K64ELyGd0BqJ1Ohy2a7 t/dOS0ovoWmjkj9837EA5o2FAkhA5njlpvRs1l5Jt/tZsZtJTcDjPYfP5kIGbOwp
4cFjwRJq9/tXf99fyncamN8xyBdvYBXSNRNMPYcjKqKIZCOePlR8Q3b7nt154w+e V6xKYW7JYht+O0si3GxGmWGOE4VbOHLpUDpLMmVu53njjeGAIkPgX53TqBRbAbVL
w2qnAevOB4dYzJaSjwJlaVQYR1YIQ7NlYkGboONq/lrtJlEejDdiRmGvgHZ8nSYW FjpDSZYC08lE4WblqXZEP6aKqVqthQ4LcGfyZDvuWDgPGHf86cTvfHQvtqRY45kU
Ob2JwqgYDfUPfsnXAwXM+whpUNJi30MDB7MSw3SiDlyw690HheT/DCKOJ9yNUiOB GhFDz6IfVlwBrfpc4hKfbhF6Q3Txm8ZSSfiVHim8JFjCqO+jn4qmaXGaOqbNUfv9
TSGkbIGW/ASett78gowjwniYdryE5ufUPwZbkSaFC3CDysHfs6Jgc+lxe3wnOHtD fLgg7Bbnu1tZdMv6JJP5Kmk0x5wp4m2vFxDd6NGfm7uz9182/LtXOjqQ0MuGfL+j
WyPl1TqDRNuLOZ26TgxI3gGEYqMcVDYQfmuiOakoebHx6j0bpvyEaP51j0/JFpu6 Dw53dl+WdUpr4Xk1m1GkYwDF9zLIwBB7dEghz6c4nbiGvh31MUk6N+4N2eGkjtWW
okKulXgC1DUluKFWMPhobPQRZ8zC29macnU74JvmJIiUhfiP2Pl16D+XcjFW++zH B1PPORcpxxXSlhtftCwsJVxRFodQu9cmI0qmw4EUEipFrkFuT7a1rNF48NFyfRMh
EDEghcCdgz0pIF6UI5j02rbNAfu7Oo685pnYeXq0DexgXjqoFOE= PcB/UcUHMCL7owhfQEEuPvqIPJS4saesCdFeJAM0MKuXB1nNGTQ=
=NF4z =HpaR
-----END PGP SIGNATURE----- -----END PGP SIGNATURE-----

View File

@@ -13,6 +13,8 @@ namespace Symfony\Component\Console\Formatter;
use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\InvalidArgumentException;
use function Symfony\Component\String\b;
/** /**
* Formatter class for console output. * Formatter class for console output.
* *
@@ -241,7 +243,7 @@ class OutputFormatter implements WrappableOutputFormatterInterface
} }
preg_match('~(\\n)$~', $text, $matches); preg_match('~(\\n)$~', $text, $matches);
$text = $prefix.preg_replace('~([^\\n]{'.$width.'})\\ *~', "\$1\n", $text); $text = $prefix.$this->addLineBreaks($text, $width);
$text = rtrim($text, "\n").($matches[1] ?? ''); $text = rtrim($text, "\n").($matches[1] ?? '');
if (!$currentLineLength && '' !== $current && !str_ends_with($current, "\n")) { if (!$currentLineLength && '' !== $current && !str_ends_with($current, "\n")) {
@@ -265,4 +267,11 @@ class OutputFormatter implements WrappableOutputFormatterInterface
return implode("\n", $lines); return implode("\n", $lines);
} }
private function addLineBreaks(string $text, int $width): string
{
$encoding = mb_detect_encoding($text, null, true) ?: 'UTF-8';
return b($text)->toCodePointString($encoding)->wordwrap($width, "\n", true)->toByteString($encoding);
}
} }

View File

@@ -48,9 +48,9 @@ class ConsoleSectionOutput extends StreamOutput
public function setMaxHeight(int $maxHeight): void public function setMaxHeight(int $maxHeight): void
{ {
// when changing max height, clear output of current section and redraw again with the new height // when changing max height, clear output of current section and redraw again with the new height
$existingContent = $this->popStreamContentUntilCurrentSection($this->maxHeight ? min($this->maxHeight, $this->lines) : $this->lines); $previousMaxHeight = $this->maxHeight;
$this->maxHeight = $maxHeight; $this->maxHeight = $maxHeight;
$existingContent = $this->popStreamContentUntilCurrentSection($previousMaxHeight ? min($previousMaxHeight, $this->lines) : $this->lines);
parent::doWrite($this->getVisibleContent(), false); parent::doWrite($this->getVisibleContent(), false);
parent::doWrite($existingContent, false); parent::doWrite($existingContent, false);
@@ -119,8 +119,7 @@ class ConsoleSectionOutput extends StreamOutput
// re-add the line break (that has been removed in the above `explode()` for // re-add the line break (that has been removed in the above `explode()` for
// - every line that is not the last line // - every line that is not the last line
// - if $newline is required, also add it to the last line // - if $newline is required, also add it to the last line
// - if it's not new line, but input ending with `\PHP_EOL` if ($i < $count || $newline) {
if ($i < $count || $newline || str_ends_with($input, \PHP_EOL)) {
$lineContent .= \PHP_EOL; $lineContent .= \PHP_EOL;
} }
@@ -168,6 +167,12 @@ class ConsoleSectionOutput extends StreamOutput
*/ */
protected function doWrite(string $message, bool $newline) protected function doWrite(string $message, bool $newline)
{ {
// Simulate newline behavior for consistent output formatting, avoiding extra logic
if (!$newline && str_ends_with($message, \PHP_EOL)) {
$message = substr($message, 0, -\strlen(\PHP_EOL));
$newline = true;
}
if (!$this->isDecorated()) { if (!$this->isDecorated()) {
parent::doWrite($message, $newline); parent::doWrite($message, $newline);
@@ -213,7 +218,7 @@ class ConsoleSectionOutput extends StreamOutput
break; break;
} }
$numberOfLinesToClear += $section->lines; $numberOfLinesToClear += $section->maxHeight ? min($section->lines, $section->maxHeight) : $section->lines;
if ('' !== $sectionContent = $section->getVisibleContent()) { if ('' !== $sectionContent = $section->getVisibleContent()) {
if (!str_ends_with($sectionContent, \PHP_EOL)) { if (!str_ends_with($sectionContent, \PHP_EOL)) {
$sectionContent .= \PHP_EOL; $sectionContent .= \PHP_EOL;

View File

@@ -1,4 +1,4 @@
Copyright (c) 2018-2019 Fabien Potencier Copyright (c) 2018-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -31,7 +31,7 @@
"minimum-stability": "dev", "minimum-stability": "dev",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "1.27-dev" "dev-main": "1.28-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",

View File

@@ -1,4 +1,4 @@
Copyright (c) 2015-2019 Fabien Potencier Copyright (c) 2015-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -28,7 +28,7 @@
"minimum-stability": "dev", "minimum-stability": "dev",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "1.27-dev" "dev-main": "1.28-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",

View File

@@ -1,4 +1,4 @@
Copyright (c) 2015-2019 Fabien Potencier Copyright (c) 2015-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -29,7 +29,7 @@
"minimum-stability": "dev", "minimum-stability": "dev",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "1.27-dev" "dev-main": "1.28-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",

View File

@@ -1,4 +1,4 @@
Copyright (c) 2015-2019 Fabien Potencier Copyright (c) 2015-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -69,7 +69,7 @@ final class Mbstring
{ {
public const MB_CASE_FOLD = \PHP_INT_MAX; public const MB_CASE_FOLD = \PHP_INT_MAX;
private const CASE_FOLD = [ private const SIMPLE_CASE_FOLD = [
['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"], ['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"],
['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'], ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'],
]; ];
@@ -301,7 +301,11 @@ final class Mbstring
$map = $upper; $map = $upper;
} else { } else {
if (self::MB_CASE_FOLD === $mode) { if (self::MB_CASE_FOLD === $mode) {
$s = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $s); static $caseFolding = null;
if (null === $caseFolding) {
$caseFolding = self::getData('caseFolding');
}
$s = strtr($s, $caseFolding);
} }
static $lower = null; static $lower = null;
@@ -406,6 +410,12 @@ final class Mbstring
public static function mb_check_encoding($var = null, $encoding = null) public static function mb_check_encoding($var = null, $encoding = null)
{ {
if (PHP_VERSION_ID < 70200 && \is_array($var)) {
trigger_error('mb_check_encoding() expects parameter 1 to be string, array given', \E_USER_WARNING);
return null;
}
if (null === $encoding) { if (null === $encoding) {
if (null === $var) { if (null === $var) {
return false; return false;
@@ -413,7 +423,21 @@ final class Mbstring
$encoding = self::$internalEncoding; $encoding = self::$internalEncoding;
} }
return self::mb_detect_encoding($var, [$encoding]) || false !== @iconv($encoding, $encoding, $var); if (!\is_array($var)) {
return self::mb_detect_encoding($var, [$encoding]) || false !== @iconv($encoding, $encoding, $var);
}
foreach ($var as $key => $value) {
if (!self::mb_check_encoding($key, $encoding)) {
return false;
}
if (!self::mb_check_encoding($value, $encoding)) {
return false;
}
}
return true;
} }
public static function mb_detect_encoding($str, $encodingList = null, $strict = false) public static function mb_detect_encoding($str, $encodingList = null, $strict = false)
@@ -638,8 +662,10 @@ final class Mbstring
public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
{ {
$haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding); [$haystack, $needle] = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], [
$needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding); self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding),
self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding),
]);
return self::mb_strpos($haystack, $needle, $offset, $encoding); return self::mb_strpos($haystack, $needle, $offset, $encoding);
} }
@@ -674,8 +700,11 @@ final class Mbstring
public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
{ {
$haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding); $haystack = self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding);
$needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding); $needle = self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding);
$haystack = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $haystack);
$needle = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $needle);
return self::mb_strrpos($haystack, $needle, $offset, $encoding); return self::mb_strrpos($haystack, $needle, $offset, $encoding);
} }
@@ -798,6 +827,50 @@ final class Mbstring
return $code; return $code;
} }
public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, string $encoding = null): string
{
if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], true)) {
throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH');
}
if (null === $encoding) {
$encoding = self::mb_internal_encoding();
}
try {
$validEncoding = @self::mb_check_encoding('', $encoding);
} catch (\ValueError $e) {
throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding));
}
// BC for PHP 7.3 and lower
if (!$validEncoding) {
throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding));
}
if (self::mb_strlen($pad_string, $encoding) <= 0) {
throw new \ValueError('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string');
}
$paddingRequired = $length - self::mb_strlen($string, $encoding);
if ($paddingRequired < 1) {
return $string;
}
switch ($pad_type) {
case \STR_PAD_LEFT:
return self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding).$string;
case \STR_PAD_RIGHT:
return $string.self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding);
default:
$leftPaddingLength = floor($paddingRequired / 2);
$rightPaddingLength = $paddingRequired - $leftPaddingLength;
return self::mb_substr(str_repeat($pad_string, $leftPaddingLength), 0, $leftPaddingLength, $encoding).$string.self::mb_substr(str_repeat($pad_string, $rightPaddingLength), 0, $rightPaddingLength, $encoding);
}
}
private static function getSubpart($pos, $part, $haystack, $encoding) private static function getSubpart($pos, $part, $haystack, $encoding)
{ {
if (false === $pos) { if (false === $pos) {

View File

@@ -0,0 +1,119 @@
<?php
return [
'İ' => 'i̇',
'µ' => 'μ',
'ſ' => 's',
'ͅ' => 'ι',
'ς' => 'σ',
'ϐ' => 'β',
'ϑ' => 'θ',
'ϕ' => 'φ',
'ϖ' => 'π',
'ϰ' => 'κ',
'ϱ' => 'ρ',
'ϵ' => 'ε',
'ẛ' => 'ṡ',
'' => 'ι',
'ß' => 'ss',
'ʼn' => 'ʼn',
'ǰ' => 'ǰ',
'ΐ' => 'ΐ',
'ΰ' => 'ΰ',
'և' => 'եւ',
'ẖ' => 'ẖ',
'ẗ' => 'ẗ',
'ẘ' => 'ẘ',
'ẙ' => 'ẙ',
'ẚ' => 'aʾ',
'ẞ' => 'ss',
'ὐ' => 'ὐ',
'ὒ' => 'ὒ',
'ὔ' => 'ὔ',
'ὖ' => 'ὖ',
'ᾀ' => 'ἀι',
'ᾁ' => 'ἁι',
'ᾂ' => 'ἂι',
'ᾃ' => 'ἃι',
'ᾄ' => 'ἄι',
'ᾅ' => 'ἅι',
'ᾆ' => 'ἆι',
'ᾇ' => 'ἇι',
'ᾈ' => 'ἀι',
'ᾉ' => 'ἁι',
'ᾊ' => 'ἂι',
'ᾋ' => 'ἃι',
'ᾌ' => 'ἄι',
'ᾍ' => 'ἅι',
'ᾎ' => 'ἆι',
'ᾏ' => 'ἇι',
'ᾐ' => 'ἠι',
'ᾑ' => 'ἡι',
'ᾒ' => 'ἢι',
'ᾓ' => 'ἣι',
'ᾔ' => 'ἤι',
'ᾕ' => 'ἥι',
'ᾖ' => 'ἦι',
'ᾗ' => 'ἧι',
'ᾘ' => 'ἠι',
'ᾙ' => 'ἡι',
'ᾚ' => 'ἢι',
'ᾛ' => 'ἣι',
'ᾜ' => 'ἤι',
'ᾝ' => 'ἥι',
'ᾞ' => 'ἦι',
'ᾟ' => 'ἧι',
'ᾠ' => 'ὠι',
'ᾡ' => 'ὡι',
'ᾢ' => 'ὢι',
'ᾣ' => 'ὣι',
'ᾤ' => 'ὤι',
'ᾥ' => 'ὥι',
'ᾦ' => 'ὦι',
'ᾧ' => 'ὧι',
'ᾨ' => 'ὠι',
'ᾩ' => 'ὡι',
'ᾪ' => 'ὢι',
'ᾫ' => 'ὣι',
'ᾬ' => 'ὤι',
'ᾭ' => 'ὥι',
'ᾮ' => 'ὦι',
'ᾯ' => 'ὧι',
'ᾲ' => 'ὰι',
'ᾳ' => 'αι',
'ᾴ' => 'άι',
'ᾶ' => 'ᾶ',
'ᾷ' => 'ᾶι',
'ᾼ' => 'αι',
'ῂ' => 'ὴι',
'ῃ' => 'ηι',
'ῄ' => 'ήι',
'ῆ' => 'ῆ',
'ῇ' => 'ῆι',
'ῌ' => 'ηι',
'ῒ' => 'ῒ',
'ῖ' => 'ῖ',
'ῗ' => 'ῗ',
'ῢ' => 'ῢ',
'ῤ' => 'ῤ',
'ῦ' => 'ῦ',
'ῧ' => 'ῧ',
'ῲ' => 'ὼι',
'ῳ' => 'ωι',
'ῴ' => 'ώι',
'ῶ' => 'ῶ',
'ῷ' => 'ῶι',
'ῼ' => 'ωι',
'ff' => 'ff',
'fi' => 'fi',
'fl' => 'fl',
'ffi' => 'ffi',
'ffl' => 'ffl',
'ſt' => 'st',
'st' => 'st',
'ﬓ' => 'մն',
'ﬔ' => 'մե',
'ﬕ' => 'մի',
'ﬖ' => 'վն',
'ﬗ' => 'մխ',
];

View File

@@ -132,6 +132,10 @@ if (!function_exists('mb_str_split')) {
function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $length, $encoding); } function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $length, $encoding); }
} }
if (!function_exists('mb_str_pad')) {
function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }
}
if (extension_loaded('mbstring')) { if (extension_loaded('mbstring')) {
return; return;
} }

View File

@@ -128,6 +128,10 @@ if (!function_exists('mb_str_split')) {
function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = null): array { return p\Mbstring::mb_str_split((string) $string, (int) $length, $encoding); } function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = null): array { return p\Mbstring::mb_str_split((string) $string, (int) $length, $encoding); }
} }
if (!function_exists('mb_str_pad')) {
function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }
}
if (extension_loaded('mbstring')) { if (extension_loaded('mbstring')) {
return; return;
} }

View File

@@ -31,7 +31,7 @@
"minimum-stability": "dev", "minimum-stability": "dev",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "1.27-dev" "dev-main": "1.28-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",

View File

@@ -1,4 +1,4 @@
Copyright (c) 2020 Fabien Potencier Copyright (c) 2020-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -30,7 +30,7 @@
"minimum-stability": "dev", "minimum-stability": "dev",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "1.27-dev" "dev-main": "1.28-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",

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.

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