composer update

This commit is contained in:
2026-07-29 16:32:25 +02:00
parent 1ede9cc3af
commit 8ad8d279e6
1156 changed files with 22791 additions and 22591 deletions
+7
View File
@@ -2,6 +2,12 @@
All notable changes are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles.
## [2.0.1] - 2024-03-02
### Changed
* Do not use implicitly nullable parameters
## [2.0.0] - 2023-02-03
### Removed
@@ -18,6 +24,7 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt
* Initial release
[2.0.1]: https://github.com/sebastianbergmann/cli-parser/compare/2.0.0...2.0.1
[2.0.0]: https://github.com/sebastianbergmann/cli-parser/compare/1.0.1...2.0.0
[1.0.1]: https://github.com/sebastianbergmann/cli-parser/compare/1.0.0...1.0.1
[1.0.0]: https://github.com/sebastianbergmann/cli-parser/compare/bb7bb3297957927962b0a3335befe7b66f7462e9...1.0.0
+1 -1
View File
@@ -1,6 +1,6 @@
BSD 3-Clause License
Copyright (c) 2020-2023, Sebastian Bergmann
Copyright (c) 2020-2024, Sebastian Bergmann
All rights reserved.
Redistribution and use in source and binary forms, with or without
+25 -4
View File
@@ -1,9 +1,30 @@
# Security Policy
This library is intended to be used in development environments only. For instance, it is used by the testing framework PHPUnit. There is no reason why this library should be installed on a webserver.
If you believe you have found a security vulnerability in the library that is developed in this repository, please report it to us through coordinated disclosure.
**If you upload this library to a webserver then your deployment process is broken. On a more general note, if your `vendor` directory is publicly accessible on your webserver then your deployment process is also broken.**
**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.**
## Security Contact Information
Instead, please email `sebastian@phpunit.de`.
Please include as much of the information listed below as you can to help us better understand and resolve the issue:
* The type of issue
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
## Web Context
The library that is developed in this repository was either extracted from [PHPUnit](https://github.com/sebastianbergmann/phpunit) or developed specifically as a dependency for PHPUnit.
The library is developed with a focus on development environments and the command-line. No specific testing or hardening with regard to using the library in an HTTP or web context or with untrusted input data is performed. The library might also contain functionality that intentionally exposes internal application data for debugging purposes.
If the library is used in a web application, the application developer is responsible for filtering inputs or escaping outputs as necessary and for verifying that the used functionality is safe for use within the intended context.
Vulnerabilities specific to the use outside a development context will be fixed as applicable, provided that the fix does not have an averse effect on the primary use case for development purposes.
After the above, if you still would like to report a security vulnerability, please email `sebastian@phpunit.de`.
+2 -1
View File
@@ -12,7 +12,8 @@
}
],
"support": {
"issues": "https://github.com/sebastianbergmann/cli-parser/issues"
"issues": "https://github.com/sebastianbergmann/cli-parser/issues",
"security": "https://github.com/sebastianbergmann/cli-parser/security/policy"
},
"prefer-stable": true,
"require": {
+3 -3
View File
@@ -44,7 +44,7 @@ final class Parser
* @throws RequiredOptionArgumentMissingException
* @throws UnknownOptionException
*/
public function parse(array $argv, string $shortOptions, array $longOptions = null): array
public function parse(array $argv, string $shortOptions, ?array $longOptions = null): array
{
if (empty($argv)) {
return [[], []];
@@ -93,7 +93,7 @@ final class Parser
substr($arg, 2),
$longOptions,
$options,
$argv
$argv,
);
continue;
@@ -103,7 +103,7 @@ final class Parser
substr($arg, 1),
$shortOptions,
$options,
$argv
$argv,
);
}
@@ -19,8 +19,8 @@ final class AmbiguousOptionException extends RuntimeException implements Excepti
parent::__construct(
sprintf(
'Option "%s" is ambiguous',
$option
)
$option,
),
);
}
}
@@ -19,8 +19,8 @@ final class OptionDoesNotAllowArgumentException extends RuntimeException impleme
parent::__construct(
sprintf(
'Option "%s" does not allow an argument',
$option
)
$option,
),
);
}
}
@@ -19,8 +19,8 @@ final class RequiredOptionArgumentMissingException extends RuntimeException impl
parent::__construct(
sprintf(
'Required argument for option "%s" is missing',
$option
)
$option,
),
);
}
}
@@ -19,8 +19,8 @@ final class UnknownOptionException extends RuntimeException implements Exception
parent::__construct(
sprintf(
'Unknown option "%s"',
$option
)
$option,
),
);
}
}
+42 -2
View File
@@ -2,6 +2,37 @@
All notable changes are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles.
## [5.0.5] - 2026-01-24
### Changed
* [#134](https://github.com/sebastianbergmann/comparator/issues/134): Suppress warning introduced in PHP 8.5
## [5.0.4] - 2025-09-07
### Changed
* Do not use `SplObjectStorage` methods that will be deprecated in PHP 8.5
## [5.0.3] - 2024-10-18
### Fixed
* Reverted [#113](https://github.com/sebastianbergmann/comparator/pull/113) as it broke backward compatibility
## [5.0.2] - 2024-08-12
### Fixed
* [#112](https://github.com/sebastianbergmann/comparator/issues/112): Arrays with different keys and the same values are considered equal in canonicalize mode
## [5.0.1] - 2023-08-14
### Fixed
* `MockObjectComparator` only works on instances of `PHPUnit\Framework\MockObject\MockObject`, but not on instances of `PHPUnit\Framework\MockObject\Stub`
* `MockObjectComparator` only ignores the `$__phpunit_invocationMocker` property, but not other properties with names prefixed with `__phpunit_`
## [5.0.0] - 2023-02-03
### Changed
@@ -137,7 +168,14 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt
* Added `SebastianBergmann\Comparator\Factory::reset()` to unregister all non-default comparators
* Added support for `phpunit/phpunit-mock-objects` version `^5.0`
[5.0.0]: https://github.com/sebastianbergmann/comparator/compare/4.0.8...5.0.0
[5.0.5]: https://github.com/sebastianbergmann/comparator/compare/5.0.4...5.0.5
[5.0.4]: https://github.com/sebastianbergmann/comparator/compare/5.0.3...5.0.4
[5.0.3]: https://github.com/sebastianbergmann/comparator/compare/5.0.2...5.0.3
[5.0.2]: https://github.com/sebastianbergmann/comparator/compare/5.0.1...5.0.2
[5.0.1]: https://github.com/sebastianbergmann/comparator/compare/5.0.0...5.0.1
[5.0.0]: https://github.com/sebastianbergmann/comparator/compare/4.0...5.0.0
[4.0.10]: https://github.com/sebastianbergmann/comparator/compare/4.0.9...4.0.10
[4.0.9]: https://github.com/sebastianbergmann/comparator/compare/4.0.8...4.0.9
[4.0.8]: https://github.com/sebastianbergmann/comparator/compare/4.0.7...4.0.8
[4.0.7]: https://github.com/sebastianbergmann/comparator/compare/4.0.6...4.0.7
[4.0.6]: https://github.com/sebastianbergmann/comparator/compare/4.0.5...4.0.6
@@ -146,7 +184,9 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt
[4.0.3]: https://github.com/sebastianbergmann/comparator/compare/4.0.2...4.0.3
[4.0.2]: https://github.com/sebastianbergmann/comparator/compare/4.0.1...4.0.2
[4.0.1]: https://github.com/sebastianbergmann/comparator/compare/4.0.0...4.0.1
[4.0.0]: https://github.com/sebastianbergmann/comparator/compare/3.0.5...4.0.0
[4.0.0]: https://github.com/sebastianbergmann/comparator/compare/3.0...4.0.0
[3.0.7]: https://github.com/sebastianbergmann/comparator/compare/3.0.6...3.0.7
[3.0.6]: https://github.com/sebastianbergmann/comparator/compare/3.0.5...3.0.6
[3.0.5]: https://github.com/sebastianbergmann/comparator/compare/3.0.4...3.0.5
[3.0.4]: https://github.com/sebastianbergmann/comparator/compare/3.0.3...3.0.4
[3.0.3]: https://github.com/sebastianbergmann/comparator/compare/3.0.2...3.0.3
+1 -1
View File
@@ -1,6 +1,6 @@
BSD 3-Clause License
Copyright (c) 2002-2023, Sebastian Bergmann
Copyright (c) 2002-2025, Sebastian Bergmann
All rights reserved.
Redistribution and use in source and binary forms, with or without
+25 -4
View File
@@ -1,9 +1,30 @@
# Security Policy
This library is intended to be used in development environments only. For instance, it is used by the testing framework PHPUnit. There is no reason why this library should be installed on a webserver.
If you believe you have found a security vulnerability in the library that is developed in this repository, please report it to us through coordinated disclosure.
**If you upload this library to a webserver then your deployment process is broken. On a more general note, if your `vendor` directory is publicly accessible on your webserver then your deployment process is also broken.**
**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.**
## Security Contact Information
Instead, please email `sebastian@phpunit.de`.
Please include as much of the information listed below as you can to help us better understand and resolve the issue:
* The type of issue
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
## Web Context
The library that is developed in this repository was either extracted from [PHPUnit](https://github.com/sebastianbergmann/phpunit) or developed specifically as a dependency for PHPUnit.
The library is developed with a focus on development environments and the command-line. No specific testing or hardening with regard to using the library in an HTTP or web context or with untrusted input data is performed. The library might also contain functionality that intentionally exposes internal application data for debugging purposes.
If the library is used in a web application, the application developer is responsible for filtering inputs or escaping outputs as necessary and for verifying that the used functionality is safe for use within the intended context.
Vulnerabilities specific to the use outside a development context will be fixed as applicable, provided that the fix does not have an averse effect on the primary use case for development purposes.
After the above, if you still would like to report a security vulnerability, please email `sebastian@phpunit.de`.
+5 -1
View File
@@ -22,6 +22,10 @@
"email": "bschussek@2bepublished.at"
}
],
"support": {
"issues": "https://github.com/sebastianbergmann/comparator/issues",
"security": "https://github.com/sebastianbergmann/comparator/security/policy"
},
"prefer-stable": true,
"require": {
"php": ">=8.1",
@@ -31,7 +35,7 @@
"ext-mbstring": "*"
},
"require-dev": {
"phpunit/phpunit": "^10.0"
"phpunit/phpunit": "^10.5"
},
"config": {
"platform": {
+7 -7
View File
@@ -56,7 +56,7 @@ class ArrayComparator extends Comparator
$expectedAsString .= sprintf(
" %s => %s\n",
$exporter->export($key),
$exporter->shortenedExport($value)
$exporter->shortenedExport($value),
);
$equal = false;
@@ -71,25 +71,25 @@ class ArrayComparator extends Comparator
$expectedAsString .= sprintf(
" %s => %s\n",
$exporter->export($key),
$exporter->shortenedExport($value)
$exporter->shortenedExport($value),
);
$actualAsString .= sprintf(
" %s => %s\n",
$exporter->export($key),
$exporter->shortenedExport($actual[$key])
$exporter->shortenedExport($actual[$key]),
);
} catch (ComparisonFailure $e) {
$expectedAsString .= sprintf(
" %s => %s\n",
$exporter->export($key),
$e->getExpectedAsString() ? $this->indent($e->getExpectedAsString()) : $exporter->shortenedExport($e->getExpected())
$e->getExpectedAsString() ? $this->indent($e->getExpectedAsString()) : $exporter->shortenedExport($e->getExpected()),
);
$actualAsString .= sprintf(
" %s => %s\n",
$exporter->export($key),
$e->getActualAsString() ? $this->indent($e->getActualAsString()) : $exporter->shortenedExport($e->getActual())
$e->getActualAsString() ? $this->indent($e->getActualAsString()) : $exporter->shortenedExport($e->getActual()),
);
$equal = false;
@@ -100,7 +100,7 @@ class ArrayComparator extends Comparator
$actualAsString .= sprintf(
" %s => %s\n",
$exporter->export($key),
$exporter->shortenedExport($value)
$exporter->shortenedExport($value),
);
$equal = false;
@@ -115,7 +115,7 @@ class ArrayComparator extends Comparator
$actual,
$expectedAsString,
$actualAsString,
'Failed asserting that two arrays are equal.'
'Failed asserting that two arrays are equal.',
);
}
}
+1 -1
View File
@@ -42,7 +42,7 @@ final class DOMNodeComparator extends ObjectComparator
$actual,
$expectedAsString,
$actualAsString,
sprintf("Failed asserting that two DOM %s are equal.\n", $type)
sprintf("Failed asserting that two DOM %s are equal.\n", $type),
);
}
}
+1 -1
View File
@@ -54,7 +54,7 @@ final class DateTimeComparator extends ObjectComparator
$actual,
$this->dateTimeToString($expected),
$this->dateTimeToString($actual),
'Failed asserting that two DateTime objects are equal.'
'Failed asserting that two DateTime objects are equal.',
);
}
}
+1 -7
View File
@@ -17,12 +17,6 @@ use Exception;
*/
final class ExceptionComparator extends ObjectComparator
{
/**
* Returns whether the comparator can compare two values.
*
* @param mixed $expected The first value to compare
* @param mixed $actual The second value to compare
*/
public function accepts(mixed $expected, mixed $actual): bool
{
return $expected instanceof Exception && $actual instanceof Exception;
@@ -39,7 +33,7 @@ final class ExceptionComparator extends ObjectComparator
$array['line'],
$array['trace'],
$array['string'],
$array['xdebug_message']
$array['xdebug_message'],
);
return $array;
+12 -10
View File
@@ -9,32 +9,34 @@
*/
namespace SebastianBergmann\Comparator;
use function array_keys;
use function assert;
use PHPUnit\Framework\MockObject\MockObject;
use function str_starts_with;
use PHPUnit\Framework\MockObject\Stub;
/**
* Compares PHPUnit\Framework\MockObject\MockObject instances for equality.
*/
final class MockObjectComparator extends ObjectComparator
{
/**
* Returns whether the comparator can compare two values.
*
* @param mixed $expected The first value to compare
* @param mixed $actual The second value to compare
*/
public function accepts(mixed $expected, mixed $actual): bool
{
return $expected instanceof MockObject && $actual instanceof MockObject;
return $expected instanceof Stub && $actual instanceof Stub;
}
protected function toArray(object $object): array
{
assert($object instanceof MockObject);
assert($object instanceof Stub);
$array = parent::toArray($object);
unset($array['__phpunit_invocationMocker']);
foreach (array_keys($array) as $key) {
if (!str_starts_with($key, '__phpunit_')) {
continue;
}
unset($array[$key]);
}
return $array;
}
+2 -2
View File
@@ -49,8 +49,8 @@ final class NumericComparator extends ScalarComparator
sprintf(
'Failed asserting that %s matches expected %s.',
$exporter->export($actual),
$exporter->export($expected)
)
$exporter->export($expected),
),
);
}
}
+4 -4
View File
@@ -42,8 +42,8 @@ class ObjectComparator extends ArrayComparator
sprintf(
'%s is not instance of expected class "%s".',
$exporter->export($actual),
$expected::class
)
$expected::class,
),
);
}
@@ -66,7 +66,7 @@ class ObjectComparator extends ArrayComparator
$delta,
$canonicalize,
$ignoreCase,
$processed
$processed,
);
} catch (ComparisonFailure $e) {
throw new ComparisonFailure(
@@ -75,7 +75,7 @@ class ObjectComparator extends ArrayComparator
// replace "Array" with "MyClass object"
substr_replace($e->getExpectedAsString(), $expected::class . ' Object', 0, 5),
substr_replace($e->getActualAsString(), $actual::class . ' Object', 0, 5),
'Failed asserting that two objects are equal.'
'Failed asserting that two objects are equal.',
);
}
}
+1 -1
View File
@@ -35,7 +35,7 @@ final class ResourceComparator extends Comparator
$expected,
$actual,
$exporter->export($expected),
$exporter->export($actual)
$exporter->export($actual),
);
}
}
+5 -5
View File
@@ -44,8 +44,8 @@ class ScalarComparator extends Comparator
// always compare as strings to avoid strange behaviour
// otherwise 0 == 'Foobar'
if ((is_string($expected) && !is_bool($actual)) || (is_string($actual) && !is_bool($expected))) {
$expectedToCompare = (string) $expectedToCompare;
$actualToCompare = (string) $actualToCompare;
$expectedToCompare = @(string) $expectedToCompare;
$actualToCompare = @(string) $actualToCompare;
if ($ignoreCase) {
$expectedToCompare = mb_strtolower($expectedToCompare, 'UTF-8');
@@ -59,7 +59,7 @@ class ScalarComparator extends Comparator
$actual,
$exporter->export($expected),
$exporter->export($actual),
'Failed asserting that two strings are equal.'
'Failed asserting that two strings are equal.',
);
}
@@ -73,8 +73,8 @@ class ScalarComparator extends Comparator
sprintf(
'Failed asserting that %s matches expected %s.',
$exporter->export($actual),
$exporter->export($expected)
)
$exporter->export($expected),
),
);
}
}
@@ -31,25 +31,25 @@ final class SplObjectStorageComparator extends Comparator
$exporter = new Exporter;
foreach ($actual as $object) {
if (!$expected->contains($object)) {
if (!$expected->offsetExists($object)) {
throw new ComparisonFailure(
$expected,
$actual,
$exporter->export($expected),
$exporter->export($actual),
'Failed asserting that two objects are equal.'
'Failed asserting that two objects are equal.',
);
}
}
foreach ($expected as $object) {
if (!$actual->contains($object)) {
if (!$actual->offsetExists($object)) {
throw new ComparisonFailure(
$expected,
$actual,
$exporter->export($expected),
$exporter->export($actual),
'Failed asserting that two objects are equal.'
'Failed asserting that two objects are equal.',
);
}
}
+2 -2
View File
@@ -35,8 +35,8 @@ final class TypeComparator extends Comparator
sprintf(
'%s does not match expected type "%s".',
(new Exporter)->shortenedExport($actual),
gettype($expected)
)
gettype($expected),
),
);
}
}
+31
View File
@@ -2,6 +2,34 @@
All notable changes are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles.
## [3.2.0] - 2023-12-21
### Added
* `ComplexityCollection::sortByDescendingCyclomaticComplexity()`
### Changed
* This component is now compatible with `nikic/php-parser` 5.0
## [3.1.0] - 2023-09-28
### Added
* `Complexity::isFunction()` and `Complexity::isMethod()`
* `ComplexityCollection::isFunction()` and `ComplexityCollection::isMethod()`
* `ComplexityCollection::mergeWith()`
### Fixed
* Anonymous classes are not processed correctly
## [3.0.1] - 2023-08-31
### Fixed
* [#7](https://github.com/sebastianbergmann/complexity/pull/7): `ComplexityCalculatingVisitor` tries to process interface methods
## [3.0.0] - 2023-02-03
### Removed
@@ -30,6 +58,9 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt
* Initial release
[3.2.0]: https://github.com/sebastianbergmann/complexity/compare/3.1.0...3.2.0
[3.1.0]: https://github.com/sebastianbergmann/complexity/compare/3.0.1...3.1.0
[3.0.1]: https://github.com/sebastianbergmann/complexity/compare/3.0.0...3.0.1
[3.0.0]: https://github.com/sebastianbergmann/complexity/compare/2.0.2...3.0.0
[2.0.2]: https://github.com/sebastianbergmann/complexity/compare/2.0.1...2.0.2
[2.0.1]: https://github.com/sebastianbergmann/complexity/compare/2.0.0...2.0.1
+25 -4
View File
@@ -1,9 +1,30 @@
# Security Policy
This library is intended to be used in development environments only. For instance, it is used by the testing framework PHPUnit. There is no reason why this library should be installed on a webserver.
If you believe you have found a security vulnerability in the library that is developed in this repository, please report it to us through coordinated disclosure.
**If you upload this library to a webserver then your deployment process is broken. On a more general note, if your `vendor` directory is publicly accessible on your webserver then your deployment process is also broken.**
**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.**
## Security Contact Information
Instead, please email `sebastian@phpunit.de`.
Please include as much of the information listed below as you can to help us better understand and resolve the issue:
* The type of issue
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
## Web Context
The library that is developed in this repository was either extracted from [PHPUnit](https://github.com/sebastianbergmann/phpunit) or developed specifically as a dependency for PHPUnit.
The library is developed with a focus on development environments and the command-line. No specific testing or hardening with regard to using the library in an HTTP or web context or with untrusted input data is performed. The library might also contain functionality that intentionally exposes internal application data for debugging purposes.
If the library is used in a web application, the application developer is responsible for filtering inputs or escaping outputs as necessary and for verifying that the used functionality is safe for use within the intended context.
Vulnerabilities specific to the use outside a development context will be fixed as applicable, provided that the fix does not have an averse effect on the primary use case for development purposes.
After the above, if you still would like to report a security vulnerability, please email `sebastian@phpunit.de`.
+4 -3
View File
@@ -12,12 +12,13 @@
}
],
"support": {
"issues": "https://github.com/sebastianbergmann/complexity/issues"
"issues": "https://github.com/sebastianbergmann/complexity/issues",
"security": "https://github.com/sebastianbergmann/complexity/security/policy"
},
"prefer-stable": true,
"require": {
"php": ">=8.1",
"nikic/php-parser": "^4.10"
"nikic/php-parser": "^4.18 || ^5.0"
},
"require-dev": {
"phpunit/phpunit": "^10.0"
@@ -36,7 +37,7 @@
},
"extra": {
"branch-alias": {
"dev-main": "3.0-dev"
"dev-main": "3.2-dev"
}
}
}
+3 -10
View File
@@ -12,12 +12,10 @@ namespace SebastianBergmann\Complexity;
use function assert;
use function file_get_contents;
use PhpParser\Error;
use PhpParser\Lexer;
use PhpParser\Node;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\NameResolver;
use PhpParser\NodeVisitor\ParentConnectingVisitor;
use PhpParser\Parser;
use PhpParser\ParserFactory;
final class Calculator
@@ -36,7 +34,7 @@ final class Calculator
public function calculateForSourceString(string $source): ComplexityCollection
{
try {
$nodes = $this->parser()->parse($source);
$nodes = (new ParserFactory)->createForHostVersion()->parse($source);
assert($nodes !== null);
@@ -47,7 +45,7 @@ final class Calculator
throw new RuntimeException(
$error->getMessage(),
$error->getCode(),
$error
$error,
);
}
// @codeCoverageIgnoreEnd
@@ -75,16 +73,11 @@ final class Calculator
throw new RuntimeException(
$error->getMessage(),
$error->getCode(),
$error
$error,
);
}
// @codeCoverageIgnoreEnd
return $complexityCalculatingVisitor->result();
}
private function parser(): Parser
{
return (new ParserFactory)->create(ParserFactory::PREFER_PHP7, new Lexer);
}
}
+30 -1
View File
@@ -9,27 +9,56 @@
*/
namespace SebastianBergmann\Complexity;
use function str_contains;
/**
* @psalm-immutable
*/
final class Complexity
{
private string $name;
/**
* @psalm-var non-empty-string
*/
private readonly string $name;
/**
* @psalm-var positive-int
*/
private int $cyclomaticComplexity;
/**
* @psalm-param non-empty-string $name
* @psalm-param positive-int $cyclomaticComplexity
*/
public function __construct(string $name, int $cyclomaticComplexity)
{
$this->name = $name;
$this->cyclomaticComplexity = $cyclomaticComplexity;
}
/**
* @psalm-return non-empty-string
*/
public function name(): string
{
return $this->name;
}
/**
* @psalm-return positive-int
*/
public function cyclomaticComplexity(): int
{
return $this->cyclomaticComplexity;
}
public function isFunction(): bool
{
return !$this->isMethod();
}
public function isMethod(): bool
{
return str_contains($this->name, '::');
}
}
@@ -9,7 +9,12 @@
*/
namespace SebastianBergmann\Complexity;
use function array_filter;
use function array_merge;
use function array_reverse;
use function array_values;
use function count;
use function usort;
use Countable;
use IteratorAggregate;
@@ -21,7 +26,7 @@ final class ComplexityCollection implements Countable, IteratorAggregate
/**
* @psalm-var list<Complexity>
*/
private array $items;
private readonly array $items;
public static function fromList(Complexity ...$items): self
{
@@ -49,6 +54,9 @@ final class ComplexityCollection implements Countable, IteratorAggregate
return new ComplexityCollectionIterator($this);
}
/**
* @psalm-return non-negative-int
*/
public function count(): int
{
return count($this->items);
@@ -59,6 +67,9 @@ final class ComplexityCollection implements Countable, IteratorAggregate
return empty($this->items);
}
/**
* @psalm-return non-negative-int
*/
public function cyclomaticComplexity(): int
{
$cyclomaticComplexity = 0;
@@ -69,4 +80,53 @@ final class ComplexityCollection implements Countable, IteratorAggregate
return $cyclomaticComplexity;
}
public function isFunction(): self
{
return new self(
array_values(
array_filter(
$this->items,
static fn (Complexity $complexity): bool => $complexity->isFunction(),
),
),
);
}
public function isMethod(): self
{
return new self(
array_values(
array_filter(
$this->items,
static fn (Complexity $complexity): bool => $complexity->isMethod(),
),
),
);
}
public function mergeWith(self $other): self
{
return new self(
array_merge(
$this->asArray(),
$other->asArray(),
),
);
}
public function sortByDescendingCyclomaticComplexity(): self
{
$items = $this->items;
usort(
$items,
static function (Complexity $a, Complexity $b): int
{
return $a->cyclomaticComplexity() <=> $b->cyclomaticComplexity();
},
);
return new self(array_reverse($items));
}
}
@@ -16,7 +16,7 @@ final class ComplexityCollectionIterator implements Iterator
/**
* @psalm-var list<Complexity>
*/
private array $items;
private readonly array $items;
private int $position = 0;
public function __construct(ComplexityCollection $items)
@@ -12,11 +12,13 @@ namespace SebastianBergmann\Complexity;
use function assert;
use function is_array;
use PhpParser\Node;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\Trait_;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitorAbstract;
@@ -41,6 +43,14 @@ final class ComplexityCalculatingVisitor extends NodeVisitorAbstract
}
if ($node instanceof ClassMethod) {
if ($node->getAttribute('parent') instanceof Interface_) {
return null;
}
if ($node->isAbstract()) {
return null;
}
$name = $this->classMethodName($node);
} else {
$name = $this->functionName($node);
@@ -52,7 +62,7 @@ final class ComplexityCalculatingVisitor extends NodeVisitorAbstract
$this->result[] = new Complexity(
$name,
$this->cyclomaticComplexity($statements)
$this->cyclomaticComplexity($statements),
);
if ($this->shortCircuitTraversal) {
@@ -69,6 +79,8 @@ final class ComplexityCalculatingVisitor extends NodeVisitorAbstract
/**
* @param Stmt[] $statements
*
* @psalm-return positive-int
*/
private function cyclomaticComplexity(array $statements): int
{
@@ -84,22 +96,37 @@ final class ComplexityCalculatingVisitor extends NodeVisitorAbstract
return $cyclomaticComplexityCalculatingVisitor->cyclomaticComplexity();
}
/**
* @psalm-return non-empty-string
*/
private function classMethodName(ClassMethod $node): string
{
$parent = $node->getAttribute('parent');
assert($parent instanceof Class_ || $parent instanceof Trait_);
if ($parent->getAttribute('parent') instanceof New_) {
return 'anonymous class';
}
assert(isset($parent->namespacedName));
assert($parent->namespacedName instanceof Name);
return $parent->namespacedName->toString() . '::' . $node->name->toString();
}
/**
* @psalm-return non-empty-string
*/
private function functionName(Function_ $node): string
{
assert(isset($node->namespacedName));
assert($node->namespacedName instanceof Name);
return $node->namespacedName->toString();
$functionName = $node->namespacedName->toString();
assert($functionName !== '');
return $functionName;
}
}
@@ -26,6 +26,9 @@ use PhpParser\NodeVisitorAbstract;
final class CyclomaticComplexityCalculatingVisitor extends NodeVisitorAbstract
{
/**
* @psalm-var positive-int
*/
private int $cyclomaticComplexity = 1;
public function enterNode(Node $node): void
@@ -47,6 +50,9 @@ final class CyclomaticComplexityCalculatingVisitor extends NodeVisitorAbstract
}
}
/**
* @psalm-return positive-int
*/
public function cyclomaticComplexity(): int
{
return $this->cyclomaticComplexity;
+50 -1
View File
@@ -2,7 +2,51 @@
All notable changes are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles.
## [5.0.0] - 2022-02-03
## [5.1.1] - 2024-03-02
### Changed
* Do not use implicitly nullable parameters
## [5.1.0] - 2023-12-22
### Added
* `SebastianBergmann\Diff\Chunk::start()`, `SebastianBergmann\Diff\Chunk::startRange()`, `SebastianBergmann\Diff\Chunk::end()`, `SebastianBergmann\Diff\Chunk::endRange()`, and `SebastianBergmann\Diff\Chunk::lines()`
* `SebastianBergmann\Diff\Diff::from()`, `SebastianBergmann\Diff\Diff::to()`, and `SebastianBergmann\Diff\Diff::chunks()`
* `SebastianBergmann\Diff\Line::content()` and `SebastianBergmann\Diff\Diff::type()`
* `SebastianBergmann\Diff\Line::isAdded()`,`SebastianBergmann\Diff\Line::isRemoved()`, and `SebastianBergmann\Diff\Line::isUnchanged()`
### Changed
* `SebastianBergmann\Diff\Diff` now implements `IteratorAggregate`, iterating over it yields the aggregated `SebastianBergmann\Diff\Chunk` objects
* `SebastianBergmann\Diff\Chunk` now implements `IteratorAggregate`, iterating over it yields the aggregated `SebastianBergmann\Diff\Line` objects
### Deprecated
* `SebastianBergmann\Diff\Chunk::getStart()`, `SebastianBergmann\Diff\Chunk::getStartRange()`, `SebastianBergmann\Diff\Chunk::getEnd()`, `SebastianBergmann\Diff\Chunk::getEndRange()`, and `SebastianBergmann\Diff\Chunk::getLines()`
* `SebastianBergmann\Diff\Diff::getFrom()`, `SebastianBergmann\Diff\Diff::getTo()`, and `SebastianBergmann\Diff\Diff::getChunks()`
* `SebastianBergmann\Diff\Line::getContent()` and `SebastianBergmann\Diff\Diff::getType()`
## [5.0.3] - 2023-05-01
### Changed
* [#119](https://github.com/sebastianbergmann/diff/pull/119): Improve performance of `TimeEfficientLongestCommonSubsequenceCalculator`
## [5.0.2] - 2023-05-01
### Changed
* [#118](https://github.com/sebastianbergmann/diff/pull/118): Improve performance of `MemoryEfficientLongestCommonSubsequenceCalculator`
## [5.0.1] - 2023-03-23
### Fixed
* [#115](https://github.com/sebastianbergmann/diff/pull/115): `Parser::parseFileDiff()` does not handle diffs correctly that only add lines or only remove lines
## [5.0.0] - 2023-02-03
### Changed
@@ -86,6 +130,11 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt
* This component is no longer supported on PHP 5.6
[5.1.1]: https://github.com/sebastianbergmann/diff/compare/5.1.0...5.1.1
[5.1.0]: https://github.com/sebastianbergmann/diff/compare/5.0.3...5.1.0
[5.0.3]: https://github.com/sebastianbergmann/diff/compare/5.0.2...5.0.3
[5.0.2]: https://github.com/sebastianbergmann/diff/compare/5.0.1...5.0.2
[5.0.1]: https://github.com/sebastianbergmann/diff/compare/5.0.0...5.0.1
[5.0.0]: https://github.com/sebastianbergmann/diff/compare/4.0.4...5.0.0
[4.0.4]: https://github.com/sebastianbergmann/diff/compare/4.0.3...4.0.4
[4.0.3]: https://github.com/sebastianbergmann/diff/compare/4.0.2...4.0.3
+1 -1
View File
@@ -1,6 +1,6 @@
BSD 3-Clause License
Copyright (c) 2002-2023, Sebastian Bergmann
Copyright (c) 2002-2024, Sebastian Bergmann
All rights reserved.
Redistribution and use in source and binary forms, with or without
+2
View File
@@ -202,3 +202,5 @@ The code above yields the output below:
)
)
)
Note: If the chunk size is 0 lines, i.e., `getStartRange()` or `getEndRange()` return 0, the number of line returned by `getStart()` or `getEnd()` is one lower than one would expect. It is the line number after which the chunk should be inserted or deleted; in all other cases, it gives the first line number of the replaced range of lines.
+25 -4
View File
@@ -1,9 +1,30 @@
# Security Policy
This library is intended to be used in development environments only. For instance, it is used by the testing framework PHPUnit. There is no reason why this library should be installed on a webserver.
If you believe you have found a security vulnerability in the library that is developed in this repository, please report it to us through coordinated disclosure.
**If you upload this library to a webserver then your deployment process is broken. On a more general note, if your `vendor` directory is publicly accessible on your webserver then your deployment process is also broken.**
**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.**
## Security Contact Information
Instead, please email `sebastian@phpunit.de`.
Please include as much of the information listed below as you can to help us better understand and resolve the issue:
* The type of issue
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
## Web Context
The library that is developed in this repository was either extracted from [PHPUnit](https://github.com/sebastianbergmann/phpunit) or developed specifically as a dependency for PHPUnit.
The library is developed with a focus on development environments and the command-line. No specific testing or hardening with regard to using the library in an HTTP or web context or with untrusted input data is performed. The library might also contain functionality that intentionally exposes internal application data for debugging purposes.
If the library is used in a web application, the application developer is responsible for filtering inputs or escaping outputs as necessary and for verifying that the used functionality is safe for use within the intended context.
Vulnerabilities specific to the use outside a development context will be fixed as applicable, provided that the fix does not have an averse effect on the primary use case for development purposes.
After the above, if you still would like to report a security vulnerability, please email `sebastian@phpunit.de`.
+6 -2
View File
@@ -14,6 +14,10 @@
"email": "mail@kore-nordmann.de"
}
],
"support": {
"issues": "https://github.com/sebastianbergmann/diff/issues",
"security": "https://github.com/sebastianbergmann/diff/security/policy"
},
"prefer-stable": true,
"config": {
"platform": {
@@ -27,7 +31,7 @@
},
"require-dev": {
"phpunit/phpunit": "^10.0",
"symfony/process": "^4.2 || ^5"
"symfony/process": "^6.4"
},
"autoload": {
"classmap": [
@@ -41,7 +45,7 @@
},
"extra": {
"branch-alias": {
"dev-main": "5.0-dev"
"dev-main": "5.1-dev"
}
}
}
+60 -6
View File
@@ -9,7 +9,14 @@
*/
namespace SebastianBergmann\Diff;
final class Chunk
use ArrayIterator;
use IteratorAggregate;
use Traversable;
/**
* @template-implements IteratorAggregate<int, Line>
*/
final class Chunk implements IteratorAggregate
{
private int $start;
private int $startRange;
@@ -26,22 +33,22 @@ final class Chunk
$this->lines = $lines;
}
public function getStart(): int
public function start(): int
{
return $this->start;
}
public function getStartRange(): int
public function startRange(): int
{
return $this->startRange;
}
public function getEnd(): int
public function end(): int
{
return $this->end;
}
public function getEndRange(): int
public function endRange(): int
{
return $this->endRange;
}
@@ -49,7 +56,7 @@ final class Chunk
/**
* @psalm-return list<Line>
*/
public function getLines(): array
public function lines(): array
{
return $this->lines;
}
@@ -67,4 +74,51 @@ final class Chunk
$this->lines = $lines;
}
/**
* @deprecated Use start() instead
*/
public function getStart(): int
{
return $this->start;
}
/**
* @deprecated Use startRange() instead
*/
public function getStartRange(): int
{
return $this->startRange;
}
/**
* @deprecated Use end() instead
*/
public function getEnd(): int
{
return $this->end;
}
/**
* @deprecated Use endRange() instead
*/
public function getEndRange(): int
{
return $this->endRange;
}
/**
* @psalm-return list<Line>
*
* @deprecated Use lines() instead
*/
public function getLines(): array
{
return $this->lines;
}
public function getIterator(): Traversable
{
return new ArrayIterator($this->lines);
}
}
+61 -4
View File
@@ -9,9 +9,23 @@
*/
namespace SebastianBergmann\Diff;
final class Diff
use ArrayIterator;
use IteratorAggregate;
use Traversable;
/**
* @template-implements IteratorAggregate<int, Chunk>
*/
final class Diff implements IteratorAggregate
{
/**
* @psalm-var non-empty-string
*/
private string $from;
/**
* @psalm-var non-empty-string
*/
private string $to;
/**
@@ -20,6 +34,8 @@ final class Diff
private array $chunks;
/**
* @psalm-param non-empty-string $from
* @psalm-param non-empty-string $to
* @psalm-param list<Chunk> $chunks
*/
public function __construct(string $from, string $to, array $chunks = [])
@@ -29,12 +45,18 @@ final class Diff
$this->chunks = $chunks;
}
public function getFrom(): string
/**
* @psalm-return non-empty-string
*/
public function from(): string
{
return $this->from;
}
public function getTo(): string
/**
* @psalm-return non-empty-string
*/
public function to(): string
{
return $this->to;
}
@@ -42,7 +64,7 @@ final class Diff
/**
* @psalm-return list<Chunk>
*/
public function getChunks(): array
public function chunks(): array
{
return $this->chunks;
}
@@ -54,4 +76,39 @@ final class Diff
{
$this->chunks = $chunks;
}
/**
* @psalm-return non-empty-string
*
* @deprecated
*/
public function getFrom(): string
{
return $this->from;
}
/**
* @psalm-return non-empty-string
*
* @deprecated
*/
public function getTo(): string
{
return $this->to;
}
/**
* @psalm-return list<Chunk>
*
* @deprecated
*/
public function getChunks(): array
{
return $this->chunks;
}
public function getIterator(): Traversable
{
return new ArrayIterator($this->chunks);
}
}
+6 -10
View File
@@ -30,14 +30,10 @@ use SebastianBergmann\Diff\Output\DiffOutputBuilderInterface;
final class Differ
{
public const OLD = 0;
public const ADDED = 1;
public const REMOVED = 2;
public const DIFF_LINE_END_WARNING = 3;
public const OLD = 0;
public const ADDED = 1;
public const REMOVED = 2;
public const DIFF_LINE_END_WARNING = 3;
public const NO_LINE_END_EOF_WARNING = 4;
private DiffOutputBuilderInterface $outputBuilder;
@@ -46,14 +42,14 @@ final class Differ
$this->outputBuilder = $outputBuilder;
}
public function diff(array|string $from, array|string $to, LongestCommonSubsequenceCalculator $lcs = null): string
public function diff(array|string $from, array|string $to, ?LongestCommonSubsequenceCalculator $lcs = null): string
{
$diff = $this->diffToArray($from, $to, $lcs);
return $this->outputBuilder->getDiff($diff);
}
public function diffToArray(array|string $from, array|string $to, LongestCommonSubsequenceCalculator $lcs = null): array
public function diffToArray(array|string $from, array|string $to, ?LongestCommonSubsequenceCalculator $lcs = null): array
{
if (is_string($from)) {
$from = $this->splitStringByLines($from);
@@ -21,17 +21,17 @@ final class ConfigurationException extends InvalidArgumentException
string $expected,
$value,
int $code = 0,
Exception $previous = null
?Exception $previous = null
) {
parent::__construct(
sprintf(
'Option "%s" must be %s, got "%s".',
$option,
$expected,
is_object($value) ? $value::class : (null === $value ? '<null>' : gettype($value) . '#' . $value)
is_object($value) ? $value::class : (null === $value ? '<null>' : gettype($value) . '#' . $value),
),
$code,
$previous
$previous,
);
}
}
+33 -4
View File
@@ -11,10 +11,8 @@ namespace SebastianBergmann\Diff;
final class Line
{
public const ADDED = 1;
public const REMOVED = 2;
public const ADDED = 1;
public const REMOVED = 2;
public const UNCHANGED = 3;
private int $type;
private string $content;
@@ -25,11 +23,42 @@ final class Line
$this->content = $content;
}
public function content(): string
{
return $this->content;
}
public function type(): int
{
return $this->type;
}
public function isAdded(): bool
{
return $this->type === self::ADDED;
}
public function isRemoved(): bool
{
return $this->type === self::REMOVED;
}
public function isUnchanged(): bool
{
return $this->type === self::UNCHANGED;
}
/**
* @deprecated
*/
public function getContent(): string
{
return $this->content;
}
/**
* @deprecated
*/
public function getType(): int
{
return $this->type;
@@ -61,7 +61,7 @@ final class MemoryEfficientLongestCommonSubsequenceCalculator implements Longest
return array_merge(
$this->calculate($fromStart, $toStart),
$this->calculate($fromEnd, $toEnd)
$this->calculate($fromEnd, $toEnd),
);
}
@@ -78,7 +78,16 @@ final class MemoryEfficientLongestCommonSubsequenceCalculator implements Longest
if ($from[$i] === $to[$j]) {
$current[$j + 1] = $prev[$j] + 1;
} else {
$current[$j + 1] = max($current[$j], $prev[$j + 1]);
/**
* @noinspection PhpConditionCanBeReplacedWithMinMaxCallInspection
*
* We do not use max() here to avoid the function call overhead
*/
if ($current[$j] > $prev[$j + 1]) {
$current[$j + 1] = $current[$j];
} else {
$current[$j + 1] = $prev[$j + 1];
}
}
}
}
@@ -82,7 +82,7 @@ final class StrictUnifiedDiffOutputBuilder implements DiffOutputBuilderInterface
$options['fromFile'],
null === $options['fromFileDate'] ? '' : "\t" . $options['fromFileDate'],
$options['toFile'],
null === $options['toFileDate'] ? '' : "\t" . $options['toFileDate']
null === $options['toFileDate'] ? '' : "\t" . $options['toFileDate'],
);
$this->collapseRanges = $options['collapseRanges'];
@@ -201,11 +201,11 @@ final class StrictUnifiedDiffOutputBuilder implements DiffOutputBuilderInterface
$fromRange - $cutOff + $contextStartOffset + $this->contextLines,
$toStart - $contextStartOffset,
$toRange - $cutOff + $contextStartOffset + $this->contextLines,
$output
$output,
);
$fromStart += $fromRange;
$toStart += $toRange;
$toStart += $toRange;
$hunkCapture = false;
$sameCount = $toRange = $fromRange = 0;
@@ -251,7 +251,7 @@ final class StrictUnifiedDiffOutputBuilder implements DiffOutputBuilderInterface
$contextEndOffset = min($sameCount, $this->contextLines);
$fromRange -= $sameCount;
$toRange -= $sameCount;
$toRange -= $sameCount;
$this->writeHunk(
$diff,
@@ -261,7 +261,7 @@ final class StrictUnifiedDiffOutputBuilder implements DiffOutputBuilderInterface
$fromRange + $contextStartOffset + $contextEndOffset,
$toStart - $contextStartOffset,
$toRange + $contextStartOffset + $contextEndOffset,
$output
$output,
);
}
@@ -302,11 +302,11 @@ final class StrictUnifiedDiffOutputBuilder implements DiffOutputBuilderInterface
$this->changed = true;
fwrite($output, $diff[$i][0]);
}
//} elseif ($diff[$i][1] === Differ::DIFF_LINE_END_WARNING) { // custom comment inserted by PHPUnit/diff package
// } elseif ($diff[$i][1] === Differ::DIFF_LINE_END_WARNING) { // custom comment inserted by PHPUnit/diff package
// skip
//} else {
// } else {
// unknown/invalid
//}
// }
}
}
@@ -18,7 +18,6 @@ use function max;
use function min;
use function str_ends_with;
use function stream_get_contents;
use function strlen;
use function substr;
use SebastianBergmann\Diff\Differ;
@@ -67,7 +66,7 @@ final class UnifiedDiffOutputBuilder extends AbstractChunkOutputBuilder
// This might happen when both the `from` and `to` do not have a trailing linebreak
$last = substr($diff, -1);
return 0 !== strlen($diff) && "\n" !== $last && "\r" !== $last
return '' !== $diff && "\n" !== $last && "\r" !== $last
? $diff . "\n"
: $diff;
}
@@ -151,11 +150,11 @@ final class UnifiedDiffOutputBuilder extends AbstractChunkOutputBuilder
$fromRange - $cutOff + $contextStartOffset + $this->contextLines,
$toStart - $contextStartOffset,
$toRange - $cutOff + $contextStartOffset + $this->contextLines,
$output
$output,
);
$fromStart += $fromRange;
$toStart += $toRange;
$toStart += $toRange;
$hunkCapture = false;
$sameCount = $toRange = $fromRange = 0;
@@ -199,7 +198,7 @@ final class UnifiedDiffOutputBuilder extends AbstractChunkOutputBuilder
$contextEndOffset = min($sameCount, $this->contextLines);
$fromRange -= $sameCount;
$toRange -= $sameCount;
$toRange -= $sameCount;
$this->writeHunk(
$diff,
@@ -209,7 +208,7 @@ final class UnifiedDiffOutputBuilder extends AbstractChunkOutputBuilder
$fromRange + $contextStartOffset + $contextEndOffset,
$toStart - $contextStartOffset,
$toRange + $contextStartOffset + $contextEndOffset,
$output
$output,
);
}
+7 -3
View File
@@ -10,6 +10,7 @@
namespace SebastianBergmann\Diff;
use function array_pop;
use function assert;
use function count;
use function max;
use function preg_match;
@@ -46,6 +47,9 @@ final class Parser
$collected = [];
}
assert(!empty($fromMatch['file']));
assert(!empty($toMatch['file']));
$diff = new Diff($fromMatch['file'], $toMatch['file']);
$i++;
@@ -74,12 +78,12 @@ final class Parser
$diffLines = [];
foreach ($lines as $line) {
if (preg_match('/^@@\s+-(?P<start>\d+)(?:,\s*(?P<startrange>\d+))?\s+\+(?P<end>\d+)(?:,\s*(?P<endrange>\d+))?\s+@@/', $line, $match)) {
if (preg_match('/^@@\s+-(?P<start>\d+)(?:,\s*(?P<startrange>\d+))?\s+\+(?P<end>\d+)(?:,\s*(?P<endrange>\d+))?\s+@@/', $line, $match, PREG_UNMATCHED_AS_NULL)) {
$chunk = new Chunk(
(int) $match['start'],
isset($match['startrange']) ? max(1, (int) $match['startrange']) : 1,
isset($match['startrange']) ? max(0, (int) $match['startrange']) : 1,
(int) $match['end'],
isset($match['endrange']) ? max(1, (int) $match['endrange']) : 1
isset($match['endrange']) ? max(0, (int) $match['endrange']) : 1,
);
$chunks[] = $chunk;
@@ -37,12 +37,24 @@ final class TimeEfficientLongestCommonSubsequenceCalculator implements LongestCo
for ($i = 1; $i <= $fromLength; $i++) {
for ($j = 1; $j <= $toLength; $j++) {
$o = ($j * $width) + $i;
$matrix[$o] = max(
$matrix[$o - 1],
$matrix[$o - $width],
$from[$i - 1] === $to[$j - 1] ? $matrix[$o - $width - 1] + 1 : 0
);
$o = ($j * $width) + $i;
// don't use max() to avoid function call overhead
$firstOrLast = $from[$i - 1] === $to[$j - 1] ? $matrix[$o - $width - 1] + 1 : 0;
if ($matrix[$o - 1] > $matrix[$o - $width]) {
if ($firstOrLast > $matrix[$o - 1]) {
$matrix[$o] = $firstOrLast;
} else {
$matrix[$o] = $matrix[$o - 1];
}
} else {
if ($firstOrLast > $matrix[$o - $width]) {
$matrix[$o] = $firstOrLast;
} else {
$matrix[$o] = $matrix[$o - $width];
}
}
}
}
+15
View File
@@ -2,6 +2,19 @@
All notable changes in `sebastianbergmann/environment` are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles.
## [6.1.0] - 2024-03-23
### Added
* [#72](https://github.com/sebastianbergmann/environment/pull/72): `Runtime::getRawBinary()`
## [6.0.1] - 2023-04-11
### Fixed
* [#68](https://github.com/sebastianbergmann/environment/pull/68): The Just-in-Time compiler is disabled when `opcache.jit_buffer_size` is set to `0`
* [#70](https://github.com/sebastianbergmann/environment/pull/70): The first `0` of `opcache.jit` only disables CPU-specific optimizations, not the Just-in-Time compiler itself
## [6.0.0] - 2023-02-03
### Removed
@@ -165,6 +178,8 @@ All notable changes in `sebastianbergmann/environment` are documented in this fi
* This component is no longer supported on PHP 5.6
[6.1.0]: https://github.com/sebastianbergmann/environment/compare/6.0.1...6.1.0
[6.0.1]: https://github.com/sebastianbergmann/environment/compare/6.0.0...6.0.1
[6.0.0]: https://github.com/sebastianbergmann/environment/compare/5.1.5...6.0.0
[5.1.5]: https://github.com/sebastianbergmann/environment/compare/5.1.4...5.1.5
[5.1.4]: https://github.com/sebastianbergmann/environment/compare/5.1.3...5.1.4
+1 -1
View File
@@ -1,6 +1,6 @@
BSD 3-Clause License
Copyright (c) 2014-2023, Sebastian Bergmann
Copyright (c) 2014-2024, Sebastian Bergmann
All rights reserved.
Redistribution and use in source and binary forms, with or without
+25 -4
View File
@@ -1,9 +1,30 @@
# Security Policy
This library is intended to be used in development environments only. For instance, it is used by the testing framework PHPUnit. There is no reason why this library should be installed on a webserver.
If you believe you have found a security vulnerability in the library that is developed in this repository, please report it to us through coordinated disclosure.
**If you upload this library to a webserver then your deployment process is broken. On a more general note, if your `vendor` directory is publicly accessible on your webserver then your deployment process is also broken.**
**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.**
## Security Contact Information
Instead, please email `sebastian@phpunit.de`.
Please include as much of the information listed below as you can to help us better understand and resolve the issue:
* The type of issue
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
## Web Context
The library that is developed in this repository was either extracted from [PHPUnit](https://github.com/sebastianbergmann/phpunit) or developed specifically as a dependency for PHPUnit.
The library is developed with a focus on development environments and the command-line. No specific testing or hardening with regard to using the library in an HTTP or web context or with untrusted input data is performed. The library might also contain functionality that intentionally exposes internal application data for debugging purposes.
If the library is used in a web application, the application developer is responsible for filtering inputs or escaping outputs as necessary and for verifying that the used functionality is safe for use within the intended context.
Vulnerabilities specific to the use outside a development context will be fixed as applicable, provided that the fix does not have an averse effect on the primary use case for development purposes.
After the above, if you still would like to report a security vulnerability, please email `sebastian@phpunit.de`.
+5 -1
View File
@@ -10,6 +10,10 @@
"email": "sebastian@phpunit.de"
}
],
"support": {
"issues": "https://github.com/sebastianbergmann/environment/issues",
"security": "https://github.com/sebastianbergmann/environment/security/policy"
},
"config": {
"platform": {
"php": "8.1.0"
@@ -34,7 +38,7 @@
},
"extra": {
"branch-alias": {
"dev-main": "6.0-dev"
"dev-main": "6.1-dev"
}
}
}
+3 -3
View File
@@ -97,7 +97,7 @@ final class Console
/**
* Returns if the file descriptor is an interactive terminal or not.
*
* Normally, we want to use a resource as a parameter, yet sadly it's not always awailable,
* Normally, we want to use a resource as a parameter, yet sadly it's not always available,
* eg when running code in interactive console (`php -a`), STDIN/STDOUT/STDERR constants are not defined.
*
* @param int|resource $fileDescriptor
@@ -112,7 +112,7 @@ final class Console
if (function_exists('fstat')) {
$stat = @fstat(STDOUT);
return $stat && 0020000 === ($stat['mode'] & 0170000);
return $stat && 0o020000 === ($stat['mode'] & 0o170000);
}
return false;
@@ -166,7 +166,7 @@ final class Console
$pipes,
null,
null,
['suppress_errors' => true]
['suppress_errors' => true],
);
if (is_resource($process)) {
+35 -18
View File
@@ -26,11 +26,11 @@ use function php_ini_loaded_file;
use function php_ini_scanned_files;
use function phpversion;
use function sprintf;
use function strpos;
use function strrpos;
final class Runtime
{
private static string $binary;
private static string $rawBinary;
private static bool $initialized = false;
/**
@@ -73,7 +73,17 @@ final class Runtime
return false;
}
if (strpos(ini_get('opcache.jit'), '0') === 0) {
if (ini_get('opcache.jit_buffer_size') === '0') {
return false;
}
$jit = ini_get('opcache.jit');
if (($jit === 'disable') || ($jit === 'off')) {
return false;
}
if (strrpos($jit, '0') === 3) {
return false;
}
@@ -81,19 +91,19 @@ final class Runtime
}
/**
* Returns the path to the binary of the current runtime.
* Returns the raw path to the binary of the current runtime.
*/
public function getBinary(): string
public function getRawBinary(): string
{
if (self::$initialized) {
return self::$binary;
return self::$rawBinary;
}
if (PHP_BINARY !== '') {
self::$binary = escapeshellarg(PHP_BINARY);
self::$rawBinary = PHP_BINARY;
self::$initialized = true;
return self::$binary;
return self::$rawBinary;
}
// @codeCoverageIgnoreStart
@@ -105,19 +115,26 @@ final class Runtime
foreach ($possibleBinaryLocations as $binary) {
if (is_readable($binary)) {
self::$binary = escapeshellarg($binary);
self::$rawBinary = $binary;
self::$initialized = true;
return self::$binary;
return self::$rawBinary;
}
}
// @codeCoverageIgnoreStart
self::$binary = 'php';
self::$rawBinary = 'php';
self::$initialized = true;
// @codeCoverageIgnoreEnd
return self::$binary;
return self::$rawBinary;
// @codeCoverageIgnoreEnd
}
/**
* Returns the escaped path to the binary of the current runtime.
*/
public function getBinary(): string
{
return escapeshellarg($this->getRawBinary());
}
public function getNameWithVersion(): string
@@ -131,7 +148,7 @@ final class Runtime
return sprintf(
'%s with PCOV %s',
$this->getNameWithVersion(),
phpversion('pcov')
phpversion('pcov'),
);
}
@@ -139,7 +156,7 @@ final class Runtime
return sprintf(
'%s with Xdebug %s',
$this->getNameWithVersion(),
phpversion('xdebug')
phpversion('xdebug'),
);
}
@@ -234,8 +251,8 @@ final class Runtime
$files,
array_map(
'trim',
explode(",\n", $scanned)
)
explode(",\n", $scanned),
),
);
}
+15 -65
View File
@@ -2,88 +2,38 @@
All notable changes are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles.
## [5.0.0] - 2023-02-03
## [5.1.4] - 2025-09-24
### Changed
* [#42](https://github.com/sebastianbergmann/exporter/pull/42): Improve export of enumerations
* Suppress `unexpected NAN value was coerced to string` warning triggered on PHP 8.5
### Removed
* This component is no longer supported on PHP 7.3, PHP 7.4 and PHP 8.0
## [4.0.5] - 2022-09-14
### Fixed
* [#47](https://github.com/sebastianbergmann/exporter/pull/47): Fix `float` export precision
## [4.0.4] - 2021-11-11
## [5.1.3] - 2025-09-22
### Changed
* [#37](https://github.com/sebastianbergmann/exporter/pull/37): Improve export of closed resources
* Suppress `not representable as an int, cast occurred` warning triggered on PHP 8.5
## [4.0.3] - 2020-09-28
## [5.1.2] - 2024-03-02
### Changed
* Changed PHP version constraint in `composer.json` from `^7.3 || ^8.0` to `>=7.3`
* Do not use implicitly nullable parameters
## [4.0.2] - 2020-06-26
### Added
* This component is now supported on PHP 8
## [4.0.1] - 2020-06-15
## [5.1.1] - 2023-09-24
### Changed
* Tests etc. are now ignored for archive exports
* [#52](https://github.com/sebastianbergmann/exporter/pull/52): Optimize export of large arrays and object graphs
## [4.0.0] - 2020-02-07
### Removed
* This component is no longer supported on PHP 7.0, PHP 7.1, and PHP 7.2
## [3.1.5] - 2022-09-14
### Fixed
* [#47](https://github.com/sebastianbergmann/exporter/pull/47): Fix `float` export precision
## [3.1.4] - 2021-11-11
## [5.1.0] - 2023-09-18
### Changed
* [#38](https://github.com/sebastianbergmann/exporter/pull/38): Improve export of closed resources
* [#51](https://github.com/sebastianbergmann/exporter/pull/51): Export arrays using short array syntax
## [3.1.3] - 2020-11-30
### Changed
* Changed PHP version constraint in `composer.json` from `^7.0` to `>=7.0`
## [3.1.2] - 2019-09-14
### Fixed
* [#29](https://github.com/sebastianbergmann/exporter/pull/29): Second parameter for `str_repeat()` must be an integer
### Removed
* Remove HHVM-specific code that is no longer needed
[5.0.0]: https://github.com/sebastianbergmann/exporter/compare/4.0.5...5.0.0
[4.0.5]: https://github.com/sebastianbergmann/exporter/compare/4.0.4...4.0.5
[4.0.4]: https://github.com/sebastianbergmann/exporter/compare/4.0.3...4.0.4
[4.0.3]: https://github.com/sebastianbergmann/exporter/compare/4.0.2...4.0.3
[4.0.2]: https://github.com/sebastianbergmann/exporter/compare/4.0.1...4.0.2
[4.0.1]: https://github.com/sebastianbergmann/exporter/compare/4.0.0...4.0.1
[4.0.0]: https://github.com/sebastianbergmann/exporter/compare/3.1.2...4.0.0
[3.1.5]: https://github.com/sebastianbergmann/exporter/compare/3.1.4...3.1.5
[3.1.4]: https://github.com/sebastianbergmann/exporter/compare/3.1.3...3.1.4
[3.1.3]: https://github.com/sebastianbergmann/exporter/compare/3.1.2...3.1.3
[3.1.2]: https://github.com/sebastianbergmann/exporter/compare/3.1.1...3.1.2
[5.1.4]: https://github.com/sebastianbergmann/exporter/compare/5.1.3...5.1.4
[5.1.3]: https://github.com/sebastianbergmann/exporter/compare/5.1.2...5.1.3
[5.1.2]: https://github.com/sebastianbergmann/exporter/compare/5.1.1...5.1.2
[5.1.1]: https://github.com/sebastianbergmann/exporter/compare/5.1.0...5.1.1
[5.1.0]: https://github.com/sebastianbergmann/exporter/compare/5.0.1...5.1.0
+1 -1
View File
@@ -1,6 +1,6 @@
BSD 3-Clause License
Copyright (c) 2002-2023, Sebastian Bergmann
Copyright (c) 2002-2025, Sebastian Bergmann
All rights reserved.
Redistribution and use in source and binary forms, with or without
+25 -4
View File
@@ -1,9 +1,30 @@
# Security Policy
This library is intended to be used in development environments only. For instance, it is used by the testing framework PHPUnit. There is no reason why this library should be installed on a webserver.
If you believe you have found a security vulnerability in the library that is developed in this repository, please report it to us through coordinated disclosure.
**If you upload this library to a webserver then your deployment process is broken. On a more general note, if your `vendor` directory is publicly accessible on your webserver then your deployment process is also broken.**
**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.**
## Security Contact Information
Instead, please email `sebastian@phpunit.de`.
Please include as much of the information listed below as you can to help us better understand and resolve the issue:
* The type of issue
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
## Web Context
The library that is developed in this repository was either extracted from [PHPUnit](https://github.com/sebastianbergmann/phpunit) or developed specifically as a dependency for PHPUnit.
The library is developed with a focus on development environments and the command-line. No specific testing or hardening with regard to using the library in an HTTP or web context or with untrusted input data is performed. The library might also contain functionality that intentionally exposes internal application data for debugging purposes.
If the library is used in a web application, the application developer is responsible for filtering inputs or escaping outputs as necessary and for verifying that the used functionality is safe for use within the intended context.
Vulnerabilities specific to the use outside a development context will be fixed as applicable, provided that the fix does not have an averse effect on the primary use case for development purposes.
After the above, if you still would like to report a security vulnerability, please email `sebastian@phpunit.de`.
+6 -2
View File
@@ -26,6 +26,10 @@
"email": "bschussek@gmail.com"
}
],
"support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues",
"security": "https://github.com/sebastianbergmann/exporter/security/policy"
},
"config": {
"platform": {
"php": "8.1.0"
@@ -40,7 +44,7 @@
"sebastian/recursion-context": "^5.0"
},
"require-dev": {
"phpunit/phpunit": "^10.0"
"phpunit/phpunit": "^10.5"
},
"autoload": {
"classmap": [
@@ -54,7 +58,7 @@
},
"extra": {
"branch-alias": {
"dev-main": "5.0-dev"
"dev-main": "5.1-dev"
}
}
}
+46 -64
View File
@@ -17,6 +17,7 @@ use function implode;
use function ini_get;
use function ini_set;
use function is_array;
use function is_bool;
use function is_float;
use function is_object;
use function is_resource;
@@ -34,17 +35,6 @@ use SebastianBergmann\RecursionContext\Context;
use SplObjectStorage;
use UnitEnum;
/**
* A nifty utility for visualizing PHP variables.
*
* <code>
* <?php
* use SebastianBergmann\Exporter\Exporter;
*
* $exporter = new Exporter;
* print $exporter->export(new Exception);
* </code>
*/
final class Exporter
{
/**
@@ -65,7 +55,7 @@ final class Exporter
return $this->recursiveExport($value, $indentation);
}
public function shortenedRecursiveExport(array &$data, Context $context = null): string
public function shortenedRecursiveExport(array &$data, ?Context $context = null): string
{
$result = [];
$exporter = new self;
@@ -84,10 +74,7 @@ final class Exporter
if ($context->contains($data[$key]) !== false) {
$result[] = '*RECURSION*';
} else {
$result[] = sprintf(
'array(%s)',
$this->shortenedRecursiveExport($data[$key], $context)
);
$result[] = sprintf('[%s]', $this->shortenedRecursiveExport($data[$key], $context));
}
} else {
$result[] = $exporter->shortenedExport($value);
@@ -123,7 +110,7 @@ final class Exporter
'%s Enum (%s, %s)',
$value::class,
$value->name,
$this->export($value->value)
$this->export($value->value),
);
}
@@ -131,7 +118,7 @@ final class Exporter
return sprintf(
'%s Enum (%s)',
$value::class,
$value->name
$value->name,
);
}
@@ -139,14 +126,14 @@ final class Exporter
return sprintf(
'%s Object (%s)',
$value::class,
count($this->toArray($value)) > 0 ? '...' : ''
count($this->toArray($value)) > 0 ? '...' : '',
);
}
if (is_array($value)) {
return sprintf(
'Array (%s)',
count($value) > 0 ? '...' : ''
'[%s]',
count($value) > 0 ? '...' : '',
);
}
@@ -174,10 +161,10 @@ final class Exporter
}
// properties are transformed to keys in the following way:
// private $property => "\0Classname\0property"
// protected $property => "\0*\0property"
// public $property => "property"
if (preg_match('/^\0.+\0(.+)$/', (string) $key, $matches)) {
// private $propertyName => "\0ClassName\0propertyName"
// protected $propertyName => "\0*\0propertyName"
// public $propertyName => "propertyName"
if (preg_match('/\0.+\0(.+)/', (string) $key, $matches)) {
$key = $matches[1];
}
@@ -189,7 +176,7 @@ final class Exporter
$array[$key] = $val;
}
// Some internal classes like SplObjectStorage don't work with the
// Some internal classes like SplObjectStorage do not work with the
// above (fast) mechanism nor with reflection in Zend.
// Format the output similarly to print_r() in this case
if ($value instanceof SplObjectStorage) {
@@ -199,26 +186,21 @@ final class Exporter
'inf' => $value->getInfo(),
];
}
$value->rewind();
}
return $array;
}
/**
* Recursive implementation of export.
*/
private function recursiveExport(mixed &$value, int $indentation, ?Context $processed = null): string
{
if ($value === null) {
return 'null';
}
if ($value === true) {
return 'true';
}
if ($value === false) {
return 'false';
if (is_bool($value)) {
return $value ? 'true' : 'false';
}
if (is_float($value)) {
@@ -226,17 +208,15 @@ final class Exporter
ini_set('precision', '-1');
try {
$valueStr = (string) $value;
$valueAsString = @(string) $value;
if ((string) (int) $value === $valueStr) {
return $valueStr . '.0';
}
ini_set('precision', $precisionBackup);
return $valueStr;
} finally {
ini_set('precision', $precisionBackup);
if ((string) @(int) $value === $valueAsString) {
return $valueAsString . '.0';
}
return $valueAsString;
}
if (gettype($value) === 'resource (closed)') {
@@ -246,8 +226,8 @@ final class Exporter
if (is_resource($value)) {
return sprintf(
'resource(%d) of type (%s)',
$value,
get_resource_type($value)
(int) $value,
get_resource_type($value),
);
}
@@ -257,7 +237,7 @@ final class Exporter
$value::class,
spl_object_id($value),
$value->name,
$this->export($value->value, $indentation)
$this->export($value->value, $indentation),
);
}
@@ -266,12 +246,12 @@ final class Exporter
'%s Enum #%d (%s)',
$value::class,
spl_object_id($value),
$value->name
$value->name,
);
}
if (is_string($value)) {
// Match for most non printable chars somewhat taking multibyte chars into account
// Match for most non-printable chars somewhat taking multibyte chars into account
if (preg_match('/[^\x09-\x0d\x1b\x20-\xff]/', $value)) {
return 'Binary String: 0x' . bin2hex($value);
}
@@ -283,8 +263,8 @@ final class Exporter
str_replace(
["\r\n", "\n\r", "\r", "\n"],
['\r\n<lf>', '\n\r<lf>', '\r<lf>', '\n<lf>'],
$value
)
$value,
),
) .
"'";
}
@@ -306,25 +286,26 @@ final class Exporter
if (count($array) > 0) {
foreach ($array as $k => $v) {
$values .= sprintf(
'%s %s => %s' . "\n",
$whitespace,
$this->recursiveExport($k, $indentation),
$values .=
$whitespace
. ' ' .
$this->recursiveExport($k, $indentation)
. ' => ' .
$this->recursiveExport($value[$k], $indentation + 1, $processed)
);
. ",\n";
}
$values = "\n" . $values . $whitespace;
}
return sprintf('Array &%s (%s)', $key, $values);
return 'Array &' . (string) $key . ' [' . $values . ']';
}
if (is_object($value)) {
$class = $value::class;
if ($processed->contains($value)) {
return sprintf('%s Object #%d', $class, spl_object_id($value));
if ($processed->contains($value) !== false) {
return $class . ' Object #' . spl_object_id($value);
}
$processed->add($value);
@@ -333,18 +314,19 @@ final class Exporter
if (count($array) > 0) {
foreach ($array as $k => $v) {
$values .= sprintf(
'%s %s => %s' . "\n",
$whitespace,
$this->recursiveExport($k, $indentation),
$values .=
$whitespace
. ' ' .
$this->recursiveExport($k, $indentation)
. ' => ' .
$this->recursiveExport($v, $indentation + 1, $processed)
);
. ",\n";
}
$values = "\n" . $values . $whitespace;
}
return sprintf('%s Object #%d (%s)', $class, spl_object_id($value), $values);
return $class . ' Object #' . spl_object_id($value) . ' (' . $values . ')';
}
return var_export($value, true);
+14
View File
@@ -2,6 +2,18 @@
All notable changes in `sebastian/global-state` are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles.
## [6.0.2] - 2024-03-02
### Changed
* Do not use implicitly nullable parameters
## [6.0.1] - 2023-07-19
### Changed
* Changed usage of `ReflectionProperty::setValue()` to be compatible with PHP 8.3
## [6.0.0] - 2023-02-03
### Changed
@@ -80,6 +92,8 @@ All notable changes in `sebastian/global-state` are documented in this file usin
* This component is no longer supported on PHP 7.0 and PHP 7.1
[6.0.2]: https://github.com/sebastianbergmann/global-state/compare/6.0.1...6.0.2
[6.0.1]: https://github.com/sebastianbergmann/global-state/compare/6.0.0...6.0.1
[6.0.0]: https://github.com/sebastianbergmann/global-state/compare/5.0.5...6.0.0
[5.0.5]: https://github.com/sebastianbergmann/global-state/compare/5.0.4...5.0.5
[5.0.4]: https://github.com/sebastianbergmann/global-state/compare/5.0.3...5.0.4
+1 -1
View File
@@ -1,6 +1,6 @@
BSD 3-Clause License
Copyright (c) 2001-2023, Sebastian Bergmann
Copyright (c) 2001-2024, Sebastian Bergmann
All rights reserved.
Redistribution and use in source and binary forms, with or without
+25 -4
View File
@@ -1,9 +1,30 @@
# Security Policy
This library is intended to be used in development environments only. For instance, it is used by the testing framework PHPUnit. There is no reason why this library should be installed on a webserver.
If you believe you have found a security vulnerability in the library that is developed in this repository, please report it to us through coordinated disclosure.
**If you upload this library to a webserver then your deployment process is broken. On a more general note, if your `vendor` directory is publicly accessible on your webserver then your deployment process is also broken.**
**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.**
## Security Contact Information
Instead, please email `sebastian@phpunit.de`.
Please include as much of the information listed below as you can to help us better understand and resolve the issue:
* The type of issue
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
## Web Context
The library that is developed in this repository was either extracted from [PHPUnit](https://github.com/sebastianbergmann/phpunit) or developed specifically as a dependency for PHPUnit.
The library is developed with a focus on development environments and the command-line. No specific testing or hardening with regard to using the library in an HTTP or web context or with untrusted input data is performed. The library might also contain functionality that intentionally exposes internal application data for debugging purposes.
If the library is used in a web application, the application developer is responsible for filtering inputs or escaping outputs as necessary and for verifying that the used functionality is safe for use within the intended context.
Vulnerabilities specific to the use outside a development context will be fixed as applicable, provided that the fix does not have an averse effect on the primary use case for development purposes.
After the above, if you still would like to report a security vulnerability, please email `sebastian@phpunit.de`.
+5 -1
View File
@@ -2,7 +2,7 @@
"name": "sebastian/global-state",
"description": "Snapshotting of global state",
"keywords": ["global state"],
"homepage": "http://www.github.com/sebastianbergmann/global-state",
"homepage": "https://www.github.com/sebastianbergmann/global-state",
"license": "BSD-3-Clause",
"authors": [
{
@@ -10,6 +10,10 @@
"email": "sebastian@phpunit.de"
}
],
"support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues",
"security": "https://github.com/sebastianbergmann/global-state/security/policy"
},
"prefer-stable": true,
"config": {
"platform": {
+3 -3
View File
@@ -27,7 +27,7 @@ final class CodeExporter
'if (!defined(\'%s\')) define(\'%s\', %s);' . "\n",
$name,
$name,
$this->exportVariable($value)
$this->exportVariable($value),
);
}
@@ -53,7 +53,7 @@ EOT;
$result .= sprintf(
'$GLOBALS[%s] = %s;' . PHP_EOL,
$this->exportVariable($name),
$this->exportVariable($value)
$this->exportVariable($value),
);
}
@@ -68,7 +68,7 @@ EOT;
$result .= sprintf(
'@ini_set(%s, %s);' . "\n",
$this->exportVariable($key),
$this->exportVariable($value)
$this->exportVariable($value),
);
}
+2 -2
View File
@@ -10,7 +10,7 @@
namespace SebastianBergmann\GlobalState;
use function in_array;
use function strpos;
use function str_starts_with;
use ReflectionClass;
final class ExcludeList
@@ -71,7 +71,7 @@ final class ExcludeList
}
foreach ($this->classNamePrefixes as $prefix) {
if (strpos($className, $prefix) === 0) {
if (str_starts_with($className, $prefix)) {
return true;
}
}
+4 -6
View File
@@ -53,8 +53,7 @@ final class Restorer
foreach ($snapshot->staticProperties() as $className => $staticProperties) {
foreach ($staticProperties as $name => $value) {
$reflector = new ReflectionProperty($className, $name);
$reflector->setAccessible(true);
$reflector->setValue($value);
$reflector->setValue(null, $value);
}
}
@@ -77,8 +76,7 @@ final class Restorer
continue;
}
$property->setAccessible(true);
$property->setValue($defaults[$name]);
$property->setValue(null, $defaults[$name]);
}
}
}
@@ -92,8 +90,8 @@ final class Restorer
$keys = array_keys(
array_merge(
$GLOBALS[$superGlobalArray],
$superGlobalVariables[$superGlobalArray]
)
$superGlobalVariables[$superGlobalArray],
),
);
foreach ($keys as $key) {
+3 -5
View File
@@ -51,7 +51,7 @@ class Snapshot
private array $classes = [];
private array $traits = [];
public function __construct(ExcludeList $excludeList = null, bool $includeGlobalVariables = true, bool $includeStaticProperties = true, bool $includeConstants = true, bool $includeFunctions = true, bool $includeClasses = true, bool $includeInterfaces = true, bool $includeTraits = true, bool $includeIniSettings = true, bool $includeIncludedFiles = true)
public function __construct(?ExcludeList $excludeList = null, bool $includeGlobalVariables = true, bool $includeStaticProperties = true, bool $includeConstants = true, bool $includeFunctions = true, bool $includeClasses = true, bool $includeInterfaces = true, bool $includeTraits = true, bool $includeIniSettings = true, bool $includeIncludedFiles = true)
{
$this->excludeList = $excludeList ?: new ExcludeList;
@@ -244,8 +244,6 @@ class Snapshot
continue;
}
$property->setAccessible(true);
if (!$property->isInitialized()) {
continue;
}
@@ -342,7 +340,7 @@ class Snapshot
/** @noinspection SlowArrayOperationsInLoopInspection */
$result = array_merge(
$result,
$this->enumerateObjectsAndResources($element, $processed)
$this->enumerateObjectsAndResources($element, $processed),
);
} else {
$result[] = $element;
@@ -360,7 +358,7 @@ class Snapshot
/** @noinspection SlowArrayOperationsInLoopInspection */
$result = array_merge(
$result,
$this->enumerateObjectsAndResources($value, $processed)
$this->enumerateObjectsAndResources($value, $processed),
);
} else {
$result[] = $value;
+14
View File
@@ -2,6 +2,18 @@
All notable changes are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles.
## [2.0.2] - 2023-12-21
### Changed
* This component is now compatible with `nikic/php-parser` 5.0
## [2.0.1] - 2023-08-31
### Changed
* Improved type information
## [2.0.0] - 2023-02-03
### Removed
@@ -34,6 +46,8 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt
* Initial release
[2.0.2]: https://github.com/sebastianbergmann/lines-of-code/compare/2.0.1...2.0.2
[2.0.1]: https://github.com/sebastianbergmann/lines-of-code/compare/2.0.0...2.0.1
[2.0.0]: https://github.com/sebastianbergmann/lines-of-code/compare/1.0.3...2.0.0
[1.0.3]: https://github.com/sebastianbergmann/lines-of-code/compare/1.0.2...1.0.3
[1.0.2]: https://github.com/sebastianbergmann/lines-of-code/compare/1.0.1...1.0.2
+25 -4
View File
@@ -1,9 +1,30 @@
# Security Policy
This library is intended to be used in development environments only. For instance, it is used by the testing framework PHPUnit. There is no reason why this library should be installed on a webserver.
If you believe you have found a security vulnerability in the library that is developed in this repository, please report it to us through coordinated disclosure.
**If you upload this library to a webserver then your deployment process is broken. On a more general note, if your `vendor` directory is publicly accessible on your webserver then your deployment process is also broken.**
**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.**
## Security Contact Information
Instead, please email `sebastian@phpunit.de`.
Please include as much of the information listed below as you can to help us better understand and resolve the issue:
* The type of issue
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
## Web Context
The library that is developed in this repository was either extracted from [PHPUnit](https://github.com/sebastianbergmann/phpunit) or developed specifically as a dependency for PHPUnit.
The library is developed with a focus on development environments and the command-line. No specific testing or hardening with regard to using the library in an HTTP or web context or with untrusted input data is performed. The library might also contain functionality that intentionally exposes internal application data for debugging purposes.
If the library is used in a web application, the application developer is responsible for filtering inputs or escaping outputs as necessary and for verifying that the used functionality is safe for use within the intended context.
Vulnerabilities specific to the use outside a development context will be fixed as applicable, provided that the fix does not have an averse effect on the primary use case for development purposes.
After the above, if you still would like to report a security vulnerability, please email `sebastian@phpunit.de`.
+3 -2
View File
@@ -12,12 +12,13 @@
}
],
"support": {
"issues": "https://github.com/sebastianbergmann/lines-of-code/issues"
"issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
"security": "https://github.com/sebastianbergmann/lines-of-code/security/policy"
},
"prefer-stable": true,
"require": {
"php": ">=8.1",
"nikic/php-parser": "^4.10"
"nikic/php-parser": "^4.18 || ^5.0"
},
"require-dev": {
"phpunit/phpunit": "^10.0"
+7 -10
View File
@@ -13,10 +13,8 @@ use function assert;
use function file_get_contents;
use function substr_count;
use PhpParser\Error;
use PhpParser\Lexer;
use PhpParser\Node;
use PhpParser\NodeTraverser;
use PhpParser\Parser;
use PhpParser\ParserFactory;
final class Counter
@@ -40,8 +38,10 @@ final class Counter
$linesOfCode = 1;
}
assert($linesOfCode >= 0);
try {
$nodes = $this->parser()->parse($source);
$nodes = (new ParserFactory)->createForHostVersion()->parse($source);
assert($nodes !== null);
@@ -52,13 +52,15 @@ final class Counter
throw new RuntimeException(
$error->getMessage(),
$error->getCode(),
$error
$error,
);
}
// @codeCoverageIgnoreEnd
}
/**
* @psalm-param non-negative-int $linesOfCode
*
* @param Node[] $nodes
*
* @throws RuntimeException
@@ -78,16 +80,11 @@ final class Counter
throw new RuntimeException(
$error->getMessage(),
$error->getCode(),
$error
$error,
);
}
// @codeCoverageIgnoreEnd
return $visitor->result();
}
private function parser(): Parser
{
return (new ParserFactory)->create(ParserFactory::PREFER_PHP7, new Lexer);
}
}
+17 -3
View File
@@ -11,6 +11,7 @@ namespace SebastianBergmann\LinesOfCode;
use function array_merge;
use function array_unique;
use function assert;
use function count;
use PhpParser\Comment;
use PhpParser\Node;
@@ -19,7 +20,10 @@ use PhpParser\NodeVisitorAbstract;
final class LineCountingVisitor extends NodeVisitorAbstract
{
private int $linesOfCode;
/**
* @psalm-var non-negative-int
*/
private readonly int $linesOfCode;
/**
* @var Comment[]
@@ -31,6 +35,9 @@ final class LineCountingVisitor extends NodeVisitorAbstract
*/
private array $linesWithStatements = [];
/**
* @psalm-param non-negative-int $linesOfCode
*/
public function __construct(int $linesOfCode)
{
$this->linesOfCode = $linesOfCode;
@@ -55,11 +62,18 @@ final class LineCountingVisitor extends NodeVisitorAbstract
$commentLinesOfCode += ($comment->getEndLine() - $comment->getStartLine() + 1);
}
$nonCommentLinesOfCode = $this->linesOfCode - $commentLinesOfCode;
$logicalLinesOfCode = count(array_unique($this->linesWithStatements));
assert($commentLinesOfCode >= 0);
assert($nonCommentLinesOfCode >= 0);
assert($logicalLinesOfCode >= 0);
return new LinesOfCode(
$this->linesOfCode,
$commentLinesOfCode,
$this->linesOfCode - $commentLinesOfCode,
count(array_unique($this->linesWithStatements))
$nonCommentLinesOfCode,
$logicalLinesOfCode,
);
}
+40 -4
View File
@@ -14,29 +14,53 @@ namespace SebastianBergmann\LinesOfCode;
*/
final class LinesOfCode
{
private int $linesOfCode;
private int $commentLinesOfCode;
private int $nonCommentLinesOfCode;
private int $logicalLinesOfCode;
/**
* @psalm-var non-negative-int
*/
private readonly int $linesOfCode;
/**
* @psalm-var non-negative-int
*/
private readonly int $commentLinesOfCode;
/**
* @psalm-var non-negative-int
*/
private readonly int $nonCommentLinesOfCode;
/**
* @psalm-var non-negative-int
*/
private readonly int $logicalLinesOfCode;
/**
* @psalm-param non-negative-int $linesOfCode
* @psalm-param non-negative-int $commentLinesOfCode
* @psalm-param non-negative-int $nonCommentLinesOfCode
* @psalm-param non-negative-int $logicalLinesOfCode
*
* @throws IllogicalValuesException
* @throws NegativeValueException
*/
public function __construct(int $linesOfCode, int $commentLinesOfCode, int $nonCommentLinesOfCode, int $logicalLinesOfCode)
{
/** @psalm-suppress DocblockTypeContradiction */
if ($linesOfCode < 0) {
throw new NegativeValueException('$linesOfCode must not be negative');
}
/** @psalm-suppress DocblockTypeContradiction */
if ($commentLinesOfCode < 0) {
throw new NegativeValueException('$commentLinesOfCode must not be negative');
}
/** @psalm-suppress DocblockTypeContradiction */
if ($nonCommentLinesOfCode < 0) {
throw new NegativeValueException('$nonCommentLinesOfCode must not be negative');
}
/** @psalm-suppress DocblockTypeContradiction */
if ($logicalLinesOfCode < 0) {
throw new NegativeValueException('$logicalLinesOfCode must not be negative');
}
@@ -51,21 +75,33 @@ final class LinesOfCode
$this->logicalLinesOfCode = $logicalLinesOfCode;
}
/**
* @psalm-return non-negative-int
*/
public function linesOfCode(): int
{
return $this->linesOfCode;
}
/**
* @psalm-return non-negative-int
*/
public function commentLinesOfCode(): int
{
return $this->commentLinesOfCode;
}
/**
* @psalm-return non-negative-int
*/
public function nonCommentLinesOfCode(): int
{
return $this->nonCommentLinesOfCode;
}
/**
* @psalm-return non-negative-int
*/
public function logicalLinesOfCode(): int
{
return $this->logicalLinesOfCode;
+7
View File
@@ -2,6 +2,12 @@
All notable changes are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles.
## [5.0.1] - 2025-08-10
### Changed
* Do not use `SplObjectStorage` methods that will be deprecated in PHP 8.5
## [5.0.0] - 2023-02-03
### Removed
@@ -39,6 +45,7 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt
* Tests etc. are now ignored for archive exports
[5.0.1]: https://github.com/sebastianbergmann/recursion-context/compare/5.0.0...5.0.1
[5.0.0]: https://github.com/sebastianbergmann/recursion-context/compare/4.0.5...5.0.0
[4.0.5]: https://github.com/sebastianbergmann/recursion-context/compare/4.0.4...4.0.5
[4.0.4]: https://github.com/sebastianbergmann/recursion-context/compare/4.0.3...4.0.4
+1 -1
View File
@@ -1,6 +1,6 @@
BSD 3-Clause License
Copyright (c) 2002-2023, Sebastian Bergmann
Copyright (c) 2002-2025, Sebastian Bergmann
All rights reserved.
Redistribution and use in source and binary forms, with or without
+25 -4
View File
@@ -1,9 +1,30 @@
# Security Policy
This library is intended to be used in development environments only. For instance, it is used by the testing framework PHPUnit. There is no reason why this library should be installed on a webserver.
If you believe you have found a security vulnerability in the library that is developed in this repository, please report it to us through coordinated disclosure.
**If you upload this library to a webserver then your deployment process is broken. On a more general note, if your `vendor` directory is publicly accessible on your webserver then your deployment process is also broken.**
**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.**
## Security Contact Information
Instead, please email `sebastian@phpunit.de`.
Please include as much of the information listed below as you can to help us better understand and resolve the issue:
* The type of issue
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
## Web Context
The library that is developed in this repository was either extracted from [PHPUnit](https://github.com/sebastianbergmann/phpunit) or developed specifically as a dependency for PHPUnit.
The library is developed with a focus on development environments and the command-line. No specific testing or hardening with regard to using the library in an HTTP or web context or with untrusted input data is performed. The library might also contain functionality that intentionally exposes internal application data for debugging purposes.
If the library is used in a web application, the application developer is responsible for filtering inputs or escaping outputs as necessary and for verifying that the used functionality is safe for use within the intended context.
Vulnerabilities specific to the use outside a development context will be fixed as applicable, provided that the fix does not have an averse effect on the primary use case for development purposes.
After the above, if you still would like to report a security vulnerability, please email `sebastian@phpunit.de`.
+5 -1
View File
@@ -17,6 +17,10 @@
"email": "aharvey@php.net"
}
],
"support": {
"issues": "https://github.com/sebastianbergmann/recursion-context/issues",
"security": "https://github.com/sebastianbergmann/recursion-context/security/policy"
},
"prefer-stable": true,
"config": {
"platform": {
@@ -29,7 +33,7 @@
"php": ">=8.1"
},
"require-dev": {
"phpunit/phpunit": "^10.0"
"phpunit/phpunit": "^10.5"
},
"autoload": {
"classmap": [
+9 -9
View File
@@ -44,13 +44,13 @@ final class Context
}
/**
* @psalm-template T
* @psalm-template T of object|array
*
* @psalm-param T $value
*
* @param-out T $value
*/
public function add(object|array &$value): int|string|false
public function add(array|object &$value): false|int|string
{
if (is_array($value)) {
return $this->addArray($value);
@@ -60,13 +60,13 @@ final class Context
}
/**
* @psalm-template T
* @psalm-template T of object|array
*
* @psalm-param T $value
*
* @param-out T $value
*/
public function contains(object|array &$value): int|string|false
public function contains(array|object &$value): false|int|string
{
if (is_array($value)) {
return $this->containsArray($value);
@@ -116,23 +116,23 @@ final class Context
private function addObject(object $object): string
{
if (!$this->objects->contains($object)) {
$this->objects->attach($object);
if (!$this->objects->offsetExists($object)) {
$this->objects->offsetSet($object);
}
return spl_object_hash($object);
}
private function containsArray(array $array): int|false
private function containsArray(array $array): false|int
{
$end = array_slice($array, -2);
return isset($end[1]) && $end[1] === $this->objects ? $end[0] : false;
}
private function containsObject(object $value): string|false
private function containsObject(object $value): false|string
{
if ($this->objects->contains($value)) {
if ($this->objects->offsetExists($value)) {
return spl_object_hash($value);
}