One Hat Cyber Team
Your IP:
216.73.216.30
Server IP:
198.54.114.155
Server:
Linux server71.web-hosting.com 4.18.0-513.18.1.lve.el8.x86_64 #1 SMP Thu Feb 22 12:55:50 UTC 2024 x86_64
Server Software:
LiteSpeed
PHP Version:
5.6.40
Create File
|
Create Folder
Execute
Dir :
~
/
proc
/
self
/
cwd
/
View File Name :
sebastian.tar
global-state/src/exceptions/Exception.php 0000644 00000000560 15111337760 0014546 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/global-state. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\GlobalState; use Throwable; interface Exception extends Throwable { } global-state/src/exceptions/RuntimeException.php 0000644 00000000606 15111337760 0016113 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/global-state. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\GlobalState; final class RuntimeException extends \RuntimeException implements Exception { } global-state/src/exceptions/error_log 0000644 00000001362 15111337760 0014015 0 ustar 00 [20-Nov-2025 06:34:49 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\GlobalState\Exception" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/global-state/src/exceptions/RuntimeException.php:12 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/global-state/src/exceptions/RuntimeException.php on line 12 [20-Nov-2025 11:19:22 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\GlobalState\Exception" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/global-state/src/exceptions/RuntimeException.php:12 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/global-state/src/exceptions/RuntimeException.php on line 12 global-state/src/Restorer.php 0000644 00000006665 15111337760 0012250 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/global-state. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\GlobalState; use function array_diff; use function array_key_exists; use function array_keys; use function array_merge; use function in_array; use function is_array; use ReflectionClass; use ReflectionProperty; final class Restorer { public function restoreGlobalVariables(Snapshot $snapshot): void { $superGlobalArrays = $snapshot->superGlobalArrays(); foreach ($superGlobalArrays as $superGlobalArray) { $this->restoreSuperGlobalArray($snapshot, $superGlobalArray); } $globalVariables = $snapshot->globalVariables(); foreach (array_keys($GLOBALS) as $key) { if ($key !== 'GLOBALS' && !in_array($key, $superGlobalArrays, true) && !$snapshot->excludeList()->isGlobalVariableExcluded($key)) { if (array_key_exists($key, $globalVariables)) { $GLOBALS[$key] = $globalVariables[$key]; } else { unset($GLOBALS[$key]); } } } } public function restoreStaticProperties(Snapshot $snapshot): void { $current = new Snapshot($snapshot->excludeList(), false, false, false, false, true, false, false, false, false); $newClasses = array_diff($current->classes(), $snapshot->classes()); unset($current); foreach ($snapshot->staticProperties() as $className => $staticProperties) { foreach ($staticProperties as $name => $value) { $reflector = new ReflectionProperty($className, $name); $reflector->setValue(null, $value); } } foreach ($newClasses as $className) { $class = new ReflectionClass($className); $defaults = $class->getDefaultProperties(); foreach ($class->getProperties() as $property) { if (!$property->isStatic()) { continue; } $name = $property->getName(); if ($snapshot->excludeList()->isStaticPropertyExcluded($className, $name)) { continue; } if (!isset($defaults[$name])) { continue; } $property->setValue(null, $defaults[$name]); } } } private function restoreSuperGlobalArray(Snapshot $snapshot, string $superGlobalArray): void { $superGlobalVariables = $snapshot->superGlobalVariables(); if (isset($GLOBALS[$superGlobalArray], $superGlobalVariables[$superGlobalArray]) && is_array($GLOBALS[$superGlobalArray])) { $keys = array_keys( array_merge( $GLOBALS[$superGlobalArray], $superGlobalVariables[$superGlobalArray] ) ); foreach ($keys as $key) { if (isset($superGlobalVariables[$superGlobalArray][$key])) { $GLOBALS[$superGlobalArray][$key] = $superGlobalVariables[$superGlobalArray][$key]; } else { unset($GLOBALS[$superGlobalArray][$key]); } } } } } global-state/src/ExcludeList.php 0000644 00000005015 15111337760 0012654 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/global-state. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\GlobalState; use function in_array; use function strpos; use ReflectionClass; final class ExcludeList { private array $globalVariables = []; private array $classes = []; private array $classNamePrefixes = []; private array $parentClasses = []; private array $interfaces = []; private array $staticProperties = []; public function addGlobalVariable(string $variableName): void { $this->globalVariables[$variableName] = true; } public function addClass(string $className): void { $this->classes[] = $className; } public function addSubclassesOf(string $className): void { $this->parentClasses[] = $className; } public function addImplementorsOf(string $interfaceName): void { $this->interfaces[] = $interfaceName; } public function addClassNamePrefix(string $classNamePrefix): void { $this->classNamePrefixes[] = $classNamePrefix; } public function addStaticProperty(string $className, string $propertyName): void { if (!isset($this->staticProperties[$className])) { $this->staticProperties[$className] = []; } $this->staticProperties[$className][$propertyName] = true; } public function isGlobalVariableExcluded(string $variableName): bool { return isset($this->globalVariables[$variableName]); } /** * @psalm-param class-string $className */ public function isStaticPropertyExcluded(string $className, string $propertyName): bool { if (in_array($className, $this->classes, true)) { return true; } foreach ($this->classNamePrefixes as $prefix) { if (strpos($className, $prefix) === 0) { return true; } } $class = new ReflectionClass($className); foreach ($this->parentClasses as $type) { if ($class->isSubclassOf($type)) { return true; } } foreach ($this->interfaces as $type) { if ($class->implementsInterface($type)) { return true; } } return isset($this->staticProperties[$className][$propertyName]); } } global-state/src/CodeExporter.php 0000644 00000005073 15111337760 0013036 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/global-state. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\GlobalState; use const PHP_EOL; use function is_array; use function is_scalar; use function serialize; use function sprintf; use function var_export; final class CodeExporter { public function constants(Snapshot $snapshot): string { $result = ''; foreach ($snapshot->constants() as $name => $value) { $result .= sprintf( 'if (!defined(\'%s\')) define(\'%s\', %s);' . "\n", $name, $name, $this->exportVariable($value) ); } return $result; } public function globalVariables(Snapshot $snapshot): string { $result = <<<'EOT' call_user_func( function () { foreach (array_keys($GLOBALS) as $key) { unset($GLOBALS[$key]); } } ); EOT; foreach ($snapshot->globalVariables() as $name => $value) { $result .= sprintf( '$GLOBALS[%s] = %s;' . PHP_EOL, $this->exportVariable($name), $this->exportVariable($value) ); } return $result; } public function iniSettings(Snapshot $snapshot): string { $result = ''; foreach ($snapshot->iniSettings() as $key => $value) { $result .= sprintf( '@ini_set(%s, %s);' . "\n", $this->exportVariable($key), $this->exportVariable($value) ); } return $result; } private function exportVariable(mixed $variable): string { if (is_scalar($variable) || null === $variable || (is_array($variable) && $this->arrayOnlyContainsScalars($variable))) { return var_export($variable, true); } return 'unserialize(' . var_export(serialize($variable), true) . ')'; } private function arrayOnlyContainsScalars(array $array): bool { $result = true; foreach ($array as $element) { if (is_array($element)) { $result = $this->arrayOnlyContainsScalars($element); } elseif (!is_scalar($element) && null !== $element) { $result = false; } if ($result === false) { break; } } return $result; } } global-state/src/Snapshot.php 0000644 00000024146 15111337760 0012234 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/global-state. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\GlobalState; use function array_keys; use function array_merge; use function array_reverse; use function assert; use function func_get_args; use function get_declared_classes; use function get_declared_interfaces; use function get_declared_traits; use function get_defined_constants; use function get_defined_functions; use function get_included_files; use function in_array; use function ini_get_all; use function is_array; use function is_object; use function is_resource; use function is_scalar; use function serialize; use function unserialize; use ReflectionClass; use SebastianBergmann\ObjectReflector\ObjectReflector; use SebastianBergmann\RecursionContext\Context; use Throwable; /** * A snapshot of global state. */ class Snapshot { private ExcludeList $excludeList; private array $globalVariables = []; private array $superGlobalArrays = []; private array $superGlobalVariables = []; private array $staticProperties = []; private array $iniSettings = []; private array $includedFiles = []; private array $constants = []; private array $functions = []; private array $interfaces = []; 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) { $this->excludeList = $excludeList ?: new ExcludeList; if ($includeConstants) { $this->snapshotConstants(); } if ($includeFunctions) { $this->snapshotFunctions(); } if ($includeClasses || $includeStaticProperties) { $this->snapshotClasses(); } if ($includeInterfaces) { $this->snapshotInterfaces(); } if ($includeGlobalVariables) { $this->setupSuperGlobalArrays(); $this->snapshotGlobals(); } if ($includeStaticProperties) { $this->snapshotStaticProperties(); } if ($includeIniSettings) { $this->iniSettings = ini_get_all(null, false); } if ($includeIncludedFiles) { $this->includedFiles = get_included_files(); } if ($includeTraits) { $this->traits = get_declared_traits(); } } public function excludeList(): ExcludeList { return $this->excludeList; } public function globalVariables(): array { return $this->globalVariables; } public function superGlobalVariables(): array { return $this->superGlobalVariables; } public function superGlobalArrays(): array { return $this->superGlobalArrays; } public function staticProperties(): array { return $this->staticProperties; } public function iniSettings(): array { return $this->iniSettings; } public function includedFiles(): array { return $this->includedFiles; } public function constants(): array { return $this->constants; } public function functions(): array { return $this->functions; } public function interfaces(): array { return $this->interfaces; } public function classes(): array { return $this->classes; } public function traits(): array { return $this->traits; } private function snapshotConstants(): void { $constants = get_defined_constants(true); if (isset($constants['user'])) { $this->constants = $constants['user']; } } private function snapshotFunctions(): void { $functions = get_defined_functions(); $this->functions = $functions['user']; } private function snapshotClasses(): void { foreach (array_reverse(get_declared_classes()) as $className) { $class = new ReflectionClass($className); if (!$class->isUserDefined()) { break; } $this->classes[] = $className; } $this->classes = array_reverse($this->classes); } private function snapshotInterfaces(): void { foreach (array_reverse(get_declared_interfaces()) as $interfaceName) { $class = new ReflectionClass($interfaceName); if (!$class->isUserDefined()) { break; } $this->interfaces[] = $interfaceName; } $this->interfaces = array_reverse($this->interfaces); } private function snapshotGlobals(): void { $superGlobalArrays = $this->superGlobalArrays(); foreach ($superGlobalArrays as $superGlobalArray) { $this->snapshotSuperGlobalArray($superGlobalArray); } foreach (array_keys($GLOBALS) as $key) { if ($key !== 'GLOBALS' && !in_array($key, $superGlobalArrays, true) && $this->canBeSerialized($GLOBALS[$key]) && !$this->excludeList->isGlobalVariableExcluded($key)) { /* @noinspection UnserializeExploitsInspection */ $this->globalVariables[$key] = unserialize(serialize($GLOBALS[$key])); } } } private function snapshotSuperGlobalArray(string $superGlobalArray): void { $this->superGlobalVariables[$superGlobalArray] = []; if (isset($GLOBALS[$superGlobalArray]) && is_array($GLOBALS[$superGlobalArray])) { foreach ($GLOBALS[$superGlobalArray] as $key => $value) { /* @noinspection UnserializeExploitsInspection */ $this->superGlobalVariables[$superGlobalArray][$key] = unserialize(serialize($value)); } } } private function snapshotStaticProperties(): void { foreach ($this->classes as $className) { $class = new ReflectionClass($className); $snapshot = []; foreach ($class->getProperties() as $property) { if ($property->isStatic()) { $name = $property->getName(); if ($this->excludeList->isStaticPropertyExcluded($className, $name)) { continue; } if (!$property->isInitialized()) { continue; } $value = $property->getValue(); if ($this->canBeSerialized($value)) { /* @noinspection UnserializeExploitsInspection */ $snapshot[$name] = unserialize(serialize($value)); } } } if (!empty($snapshot)) { $this->staticProperties[$className] = $snapshot; } } } private function setupSuperGlobalArrays(): void { $this->superGlobalArrays = [ '_ENV', '_POST', '_GET', '_COOKIE', '_SERVER', '_FILES', '_REQUEST', ]; } private function canBeSerialized(mixed $variable): bool { if (is_scalar($variable) || $variable === null) { return true; } if (is_resource($variable)) { return false; } foreach ($this->enumerateObjectsAndResources($variable) as $value) { if (is_resource($value)) { return false; } if (is_object($value)) { $class = new ReflectionClass($value); if ($class->isAnonymous()) { return false; } try { @serialize($value); } catch (Throwable $t) { return false; } } } return true; } private function enumerateObjectsAndResources(mixed $variable): array { if (isset(func_get_args()[1])) { $processed = func_get_args()[1]; } else { $processed = new Context; } assert($processed instanceof Context); $result = []; if ($processed->contains($variable)) { return $result; } $array = $variable; /* @noinspection UnusedFunctionResultInspection */ $processed->add($variable); if (is_array($variable)) { foreach ($array as $element) { if (!is_array($element) && !is_object($element) && !is_resource($element)) { continue; } if (!is_resource($element)) { /** @noinspection SlowArrayOperationsInLoopInspection */ $result = array_merge( $result, $this->enumerateObjectsAndResources($element, $processed) ); } else { $result[] = $element; } } } else { $result[] = $variable; foreach ((new ObjectReflector)->getProperties($variable) as $value) { if (!is_array($value) && !is_object($value) && !is_resource($value)) { continue; } if (!is_resource($value)) { /** @noinspection SlowArrayOperationsInLoopInspection */ $result = array_merge( $result, $this->enumerateObjectsAndResources($value, $processed) ); } else { $result[] = $value; } } } return $result; } } global-state/README.md 0000644 00000002113 15111337760 0010402 0 ustar 00 [](https://packagist.org/packages/sebastian/global-state) [](https://github.com/sebastianbergmann/global-state/actions) [](https://shepherd.dev/github/sebastianbergmann/global-state) [](https://codecov.io/gh/sebastianbergmann/global-state) # sebastian/global-state Snapshotting of global state, factored out of PHPUnit into a stand-alone component. ## Installation You can add this library as a local, per-project dependency to your project using [Composer](https://getcomposer.org/): ``` composer require sebastian/global-state ``` If you only need this library during development, for instance to run your project's test suite, then you should add it as a development-time dependency: ``` composer require --dev sebastian/global-state ``` global-state/LICENSE 0000644 00000002773 15111337760 0010144 0 ustar 00 BSD 3-Clause License Copyright (c) 2001-2023, Sebastian Bergmann All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. global-state/ChangeLog.md 0000644 00000006651 15111337760 0011307 0 ustar 00 # Changes in sebastian/global-state All notable changes in `sebastian/global-state` are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles. ## [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 * Renamed `SebastianBergmann\GlobalState\ExcludeList::addStaticAttribute()` to `SebastianBergmann\GlobalState\ExcludeList::addStaticProperty()` * Renamed `SebastianBergmann\GlobalState\ExcludeList::isStaticAttributeExcluded()` to `SebastianBergmann\GlobalState\ExcludeList::isStaticPropertyExcluded()` * Renamed `SebastianBergmann\GlobalState\Restorer::restoreStaticAttributes()` to `SebastianBergmann\GlobalState\Restorer::restoreStaticProperties()` * Renamed `SebastianBergmann\GlobalState\Snapshot::staticAttributes()` to `SebastianBergmann\GlobalState\Snapshot::staticProperties()` ### Removed * Removed `SebastianBergmann\GlobalState\Restorer::restoreFunctions()` * This component is no longer supported on PHP 7.3, PHP 7.4 and PHP 8.0 ## [5.0.5] - 2022-02-14 ### Fixed * [#34](https://github.com/sebastianbergmann/global-state/pull/34): Uninitialised typed static properties are not handled correctly ## [5.0.4] - 2022-02-10 ### Fixed * The `$includeTraits` parameter of `SebastianBergmann\GlobalState\Snapshot::__construct()` is not respected ## [5.0.3] - 2021-06-11 ### Changed * `SebastianBergmann\GlobalState\CodeExporter::globalVariables()` now generates code that is compatible with PHP 8.1 ## [5.0.2] - 2020-10-26 ### Fixed * `SebastianBergmann\GlobalState\Exception` now correctly extends `\Throwable` ## [5.0.1] - 2020-09-28 ### Changed * Changed PHP version constraint in `composer.json` from `^7.3 || ^8.0` to `>=7.3` ## [5.0.0] - 2020-08-07 ### Changed * The `SebastianBergmann\GlobalState\Blacklist` class has been renamed to `SebastianBergmann\GlobalState\ExcludeList` ## [4.0.0] - 2020-02-07 ### Removed * This component is no longer supported on PHP 7.2 ## [3.0.2] - 2022-02-10 ### Fixed * The `$includeTraits` parameter of `SebastianBergmann\GlobalState\Snapshot::__construct()` is not respected ## [3.0.1] - 2020-11-30 ### Changed * Changed PHP version constraint in `composer.json` from `^7.2` to `>=7.2` ## [3.0.0] - 2019-02-01 ### Changed * `Snapshot::canBeSerialized()` now recursively checks arrays and object graphs for variables that cannot be serialized ### Removed * This component is no longer supported on PHP 7.0 and PHP 7.1 [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 [5.0.3]: https://github.com/sebastianbergmann/global-state/compare/5.0.2...5.0.3 [5.0.2]: https://github.com/sebastianbergmann/global-state/compare/5.0.1...5.0.2 [5.0.1]: https://github.com/sebastianbergmann/global-state/compare/5.0.0...5.0.1 [5.0.0]: https://github.com/sebastianbergmann/global-state/compare/4.0.0...5.0.0 [4.0.0]: https://github.com/sebastianbergmann/global-state/compare/3.0.2...4.0.0 [3.0.2]: https://github.com/sebastianbergmann/phpunit/compare/3.0.1...3.0.2 [3.0.1]: https://github.com/sebastianbergmann/phpunit/compare/3.0.0...3.0.1 [3.0.0]: https://github.com/sebastianbergmann/phpunit/compare/2.0.0...3.0.0 global-state/composer.json 0000644 00000002415 15111337760 0011652 0 ustar 00 { "name": "sebastian/global-state", "description": "Snapshotting of global state", "keywords": ["global state"], "homepage": "http://www.github.com/sebastianbergmann/global-state", "license": "BSD-3-Clause", "authors": [ { "name": "Sebastian Bergmann", "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": { "php": "8.1.0" }, "optimize-autoloader": true, "sort-packages": true }, "require": { "php": ">=8.1", "sebastian/object-reflector": "^3.0", "sebastian/recursion-context": "^5.0" }, "require-dev": { "ext-dom": "*", "phpunit/phpunit": "^10.0" }, "autoload": { "classmap": [ "src/" ] }, "autoload-dev": { "classmap": [ "tests/_fixture/" ], "files": [ "tests/_fixture/SnapshotFunctions.php" ] }, "extra": { "branch-alias": { "dev-main": "6.0-dev" } } } global-state/SECURITY.md 0000644 00000003565 15111337760 0010730 0 ustar 00 # Security Policy 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. **Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.** 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. exporter/src/Exporter.php 0000644 00000023176 15111337760 0011541 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/exporter. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Exporter; use function bin2hex; use function count; use function get_resource_type; use function gettype; use function implode; use function ini_get; use function ini_set; use function is_array; use function is_float; use function is_object; use function is_resource; use function is_string; use function mb_strlen; use function mb_substr; use function preg_match; use function spl_object_id; use function sprintf; use function str_repeat; use function str_replace; use function var_export; use BackedEnum; use SebastianBergmann\RecursionContext\Context; use SplObjectStorage; use UnitEnum; final class Exporter { /** * Exports a value as a string. * * The output of this method is similar to the output of print_r(), but * improved in various aspects: * * - NULL is rendered as "null" (instead of "") * - TRUE is rendered as "true" (instead of "1") * - FALSE is rendered as "false" (instead of "") * - Strings are always quoted with single quotes * - Carriage returns and newlines are normalized to \n * - Recursion and repeated rendering is treated properly */ public function export(mixed $value, int $indentation = 0): string { return $this->recursiveExport($value, $indentation); } public function shortenedRecursiveExport(array &$data, Context $context = null): string { $result = []; $exporter = new self; if (!$context) { $context = new Context; } $array = $data; /* @noinspection UnusedFunctionResultInspection */ $context->add($data); foreach ($array as $key => $value) { if (is_array($value)) { if ($context->contains($data[$key]) !== false) { $result[] = '*RECURSION*'; } else { $result[] = sprintf('[%s]', $this->shortenedRecursiveExport($data[$key], $context)); } } else { $result[] = $exporter->shortenedExport($value); } } return implode(', ', $result); } /** * Exports a value into a single-line string. * * The output of this method is similar to the output of * SebastianBergmann\Exporter\Exporter::export(). * * Newlines are replaced by the visible string '\n'. * Contents of arrays and objects (if any) are replaced by '...'. */ public function shortenedExport(mixed $value): string { if (is_string($value)) { $string = str_replace("\n", '', $this->export($value)); if (mb_strlen($string) > 40) { return mb_substr($string, 0, 30) . '...' . mb_substr($string, -7); } return $string; } if ($value instanceof BackedEnum) { return sprintf( '%s Enum (%s, %s)', $value::class, $value->name, $this->export($value->value), ); } if ($value instanceof UnitEnum) { return sprintf( '%s Enum (%s)', $value::class, $value->name, ); } if (is_object($value)) { return sprintf( '%s Object (%s)', $value::class, count($this->toArray($value)) > 0 ? '...' : '', ); } if (is_array($value)) { return sprintf( '[%s]', count($value) > 0 ? '...' : '', ); } return $this->export($value); } /** * Converts an object to an array containing all of its private, protected * and public properties. */ public function toArray(mixed $value): array { if (!is_object($value)) { return (array) $value; } $array = []; foreach ((array) $value as $key => $val) { // Exception traces commonly reference hundreds to thousands of // objects currently loaded in memory. Including them in the result // has a severe negative performance impact. if ("\0Error\0trace" === $key || "\0Exception\0trace" === $key) { continue; } // properties are transformed to keys in the following way: // private $propertyName => "\0ClassName\0propertyName" // protected $propertyName => "\0*\0propertyName" // public $propertyName => "propertyName" if (preg_match('/^\0.+\0(.+)$/', (string) $key, $matches)) { $key = $matches[1]; } // See https://github.com/php/php-src/commit/5721132 if ($key === "\0gcdata") { continue; } $array[$key] = $val; } // 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) { foreach ($value as $_value) { $array['Object #' . spl_object_id($_value)] = [ 'obj' => $_value, 'inf' => $value->getInfo(), ]; } $value->rewind(); } return $array; } 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_float($value)) { $precisionBackup = ini_get('precision'); ini_set('precision', '-1'); try { $valueStr = (string) $value; if ((string) (int) $value === $valueStr) { return $valueStr . '.0'; } return $valueStr; } finally { ini_set('precision', $precisionBackup); } } if (gettype($value) === 'resource (closed)') { return 'resource (closed)'; } if (is_resource($value)) { return sprintf( 'resource(%d) of type (%s)', $value, get_resource_type($value), ); } if ($value instanceof BackedEnum) { return sprintf( '%s Enum #%d (%s, %s)', $value::class, spl_object_id($value), $value->name, $this->export($value->value, $indentation), ); } if ($value instanceof UnitEnum) { return sprintf( '%s Enum #%d (%s)', $value::class, spl_object_id($value), $value->name, ); } if (is_string($value)) { // 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); } return "'" . str_replace( '<lf>', "\n", str_replace( ["\r\n", "\n\r", "\r", "\n"], ['\r\n<lf>', '\n\r<lf>', '\r<lf>', '\n<lf>'], $value, ), ) . "'"; } $whitespace = str_repeat(' ', 4 * $indentation); if (!$processed) { $processed = new Context; } if (is_array($value)) { if (($key = $processed->contains($value)) !== false) { return 'Array &' . $key; } $array = $value; $key = $processed->add($value); $values = ''; if (count($array) > 0) { foreach ($array as $k => $v) { $values .= $whitespace . ' ' . $this->recursiveExport($k, $indentation) . ' => ' . $this->recursiveExport($value[$k], $indentation + 1, $processed) . ",\n"; } $values = "\n" . $values . $whitespace; } return 'Array &' . (string) $key . ' [' . $values . ']'; } if (is_object($value)) { $class = $value::class; if ($processed->contains($value)) { return $class . ' Object #' . spl_object_id($value); } $processed->add($value); $values = ''; $array = $this->toArray($value); if (count($array) > 0) { foreach ($array as $k => $v) { $values .= $whitespace . ' ' . $this->recursiveExport($k, $indentation) . ' => ' . $this->recursiveExport($v, $indentation + 1, $processed) . ",\n"; } $values = "\n" . $values . $whitespace; } return $class . ' Object #' . spl_object_id($value) . ' (' . $values . ')'; } return var_export($value, true); } } exporter/README.md 0000644 00000006343 15111337760 0007705 0 ustar 00 [](https://packagist.org/packages/sebastian/exporter) [](https://github.com/sebastianbergmann/exporter/actions) [](https://shepherd.dev/github/sebastianbergmann/exporter) [](https://codecov.io/gh/sebastianbergmann/exporter) # sebastian/exporter This component provides the functionality to export PHP variables for visualization. ## Installation You can add this library as a local, per-project dependency to your project using [Composer](https://getcomposer.org/): ``` composer require sebastian/exporter ``` If you only need this library during development, for instance to run your project's test suite, then you should add it as a development-time dependency: ``` composer require --dev sebastian/exporter ``` ## Usage Exporting: ```php <?php use SebastianBergmann\Exporter\Exporter; $exporter = new Exporter; /* Exception Object &0000000078de0f0d000000002003a261 ( 'message' => '' 'string' => '' 'code' => 0 'file' => '/home/sebastianbergmann/test.php' 'line' => 34 'previous' => null ) */ print $exporter->export(new Exception); ``` ## Data Types Exporting simple types: ```php <?php use SebastianBergmann\Exporter\Exporter; $exporter = new Exporter; // 46 print $exporter->export(46); // 4.0 print $exporter->export(4.0); // 'hello, world!' print $exporter->export('hello, world!'); // false print $exporter->export(false); // NAN print $exporter->export(acos(8)); // -INF print $exporter->export(log(0)); // null print $exporter->export(null); // resource(13) of type (stream) print $exporter->export(fopen('php://stderr', 'w')); // Binary String: 0x000102030405 print $exporter->export(chr(0) . chr(1) . chr(2) . chr(3) . chr(4) . chr(5)); ``` Exporting complex types: ```php <?php use SebastianBergmann\Exporter\Exporter; $exporter = new Exporter; /* Array &0 ( 0 => Array &1 ( 0 => 1 1 => 2 2 => 3 ) 1 => Array &2 ( 0 => '' 1 => 0 2 => false ) ) */ print $exporter->export(array(array(1,2,3), array("",0,FALSE))); /* Array &0 ( 'self' => Array &1 ( 'self' => Array &1 ) ) */ $array = array(); $array['self'] = &$array; print $exporter->export($array); /* stdClass Object &0000000003a66dcc0000000025e723e2 ( 'self' => stdClass Object &0000000003a66dcc0000000025e723e2 ) */ $obj = new stdClass(); $obj->self = $obj; print $exporter->export($obj); ``` Compact exports: ```php <?php use SebastianBergmann\Exporter\Exporter; $exporter = new Exporter; // Array () print $exporter->shortenedExport(array()); // Array (...) print $exporter->shortenedExport(array(1,2,3,4,5)); // stdClass Object () print $exporter->shortenedExport(new stdClass); // Exception Object (...) print $exporter->shortenedExport(new Exception); // this\nis\na\nsuper\nlong\nstring\nt...\nspace print $exporter->shortenedExport( <<<LONG_STRING this is a super long string that wraps a lot and eats up a lot of space LONG_STRING ); ``` exporter/LICENSE 0000644 00000002773 15111337760 0007436 0 ustar 00 BSD 3-Clause License Copyright (c) 2002-2023, Sebastian Bergmann All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. exporter/ChangeLog.md 0000644 00000006126 15111337760 0010576 0 ustar 00 # ChangeLog All notable changes are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles. ## [5.1.1] - 2023-09-24 ### Changed * [#52](https://github.com/sebastianbergmann/exporter/pull/52): Optimize export of large arrays and object graphs ## [5.1.0] - 2023-09-18 ### Changed * [#51](https://github.com/sebastianbergmann/exporter/pull/51): Export arrays using short array syntax ## [5.0.1] - 2023-09-08 ### Fixed * [#49](https://github.com/sebastianbergmann/exporter/issues/49): `Exporter::toArray()` changes `SplObjectStorage` index ## [5.0.0] - 2023-02-03 ### Changed * [#42](https://github.com/sebastianbergmann/exporter/pull/42): Improve export of enumerations ### 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 ### Changed * [#37](https://github.com/sebastianbergmann/exporter/pull/37): Improve export of closed resources ## [4.0.3] - 2020-09-28 ### Changed * Changed PHP version constraint in `composer.json` from `^7.3 || ^8.0` to `>=7.3` ## [4.0.2] - 2020-06-26 ### Added * This component is now supported on PHP 8 ## [4.0.1] - 2020-06-15 ### Changed * Tests etc. are now ignored for archive exports ## [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 ### Changed * [#38](https://github.com/sebastianbergmann/exporter/pull/38): Improve export of closed resources ## [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.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 [5.0.1]: https://github.com/sebastianbergmann/exporter/compare/5.0.0...5.0.1 [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 exporter/composer.json 0000644 00000003101 15111337760 0011135 0 ustar 00 { "name": "sebastian/exporter", "description": "Provides the functionality to export PHP variables for visualization", "keywords": ["exporter","export"], "homepage": "https://www.github.com/sebastianbergmann/exporter", "license": "BSD-3-Clause", "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" }, { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" }, { "name": "Volker Dusch", "email": "github@wallbash.com" }, { "name": "Adam Harvey", "email": "aharvey@php.net" }, { "name": "Bernhard Schussek", "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" }, "optimize-autoloader": true, "sort-packages": true }, "prefer-stable": true, "require": { "php": ">=8.1", "ext-mbstring": "*", "sebastian/recursion-context": "^5.0" }, "require-dev": { "phpunit/phpunit": "^10.0" }, "autoload": { "classmap": [ "src/" ] }, "autoload-dev": { "classmap": [ "tests/_fixture" ] }, "extra": { "branch-alias": { "dev-main": "5.1-dev" } } } exporter/SECURITY.md 0000644 00000003565 15111337760 0010222 0 ustar 00 # Security Policy 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. **Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.** 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. cli-parser/src/exceptions/OptionDoesNotAllowArgumentException.php 0000644 00000001232 15111337760 0021415 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/cli-parser. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\CliParser; use function sprintf; use RuntimeException; final class OptionDoesNotAllowArgumentException extends RuntimeException implements Exception { public function __construct(string $option) { parent::__construct( sprintf( 'Option "%s" does not allow an argument', $option ) ); } } cli-parser/src/exceptions/UnknownOptionException.php 0000644 00000001172 15111337760 0017002 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/cli-parser. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\CliParser; use function sprintf; use RuntimeException; final class UnknownOptionException extends RuntimeException implements Exception { public function __construct(string $option) { parent::__construct( sprintf( 'Unknown option "%s"', $option ) ); } } cli-parser/src/exceptions/Exception.php 0000644 00000000554 15111337760 0014234 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/cli-parser. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\CliParser; use Throwable; interface Exception extends Throwable { } cli-parser/src/exceptions/AmbiguousOptionException.php 0000644 00000001201 15111337760 0017267 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/cli-parser. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\CliParser; use function sprintf; use RuntimeException; final class AmbiguousOptionException extends RuntimeException implements Exception { public function __construct(string $option) { parent::__construct( sprintf( 'Option "%s" is ambiguous', $option ) ); } } cli-parser/src/exceptions/error_log 0000644 00000003004 15111337760 0013473 0 ustar 00 [19-Nov-2025 13:26:22 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\CliParser\Exception" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/cli-parser/src/exceptions/AmbiguousOptionException.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/cli-parser/src/exceptions/AmbiguousOptionException.php on line 15 [19-Nov-2025 19:39:36 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\CliParser\Exception" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/cli-parser/src/exceptions/AmbiguousOptionException.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/cli-parser/src/exceptions/AmbiguousOptionException.php on line 15 [20-Nov-2025 01:37:41 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\CliParser\Exception" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/cli-parser/src/exceptions/UnknownOptionException.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/cli-parser/src/exceptions/UnknownOptionException.php on line 15 [20-Nov-2025 05:31:40 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\CliParser\Exception" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/cli-parser/src/exceptions/UnknownOptionException.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/cli-parser/src/exceptions/UnknownOptionException.php on line 15 cli-parser/src/exceptions/RequiredOptionArgumentMissingException.php 0000644 00000001243 15111337760 0022157 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/cli-parser. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\CliParser; use function sprintf; use RuntimeException; final class RequiredOptionArgumentMissingException extends RuntimeException implements Exception { public function __construct(string $option) { parent::__construct( sprintf( 'Required argument for option "%s" is missing', $option ) ); } } cli-parser/src/Parser.php 0000644 00000013250 15111337760 0011346 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/cli-parser. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\CliParser; use function array_map; use function array_merge; use function array_shift; use function array_slice; use function assert; use function count; use function current; use function explode; use function is_array; use function is_int; use function is_string; use function key; use function next; use function preg_replace; use function reset; use function sort; use function str_ends_with; use function str_starts_with; use function strlen; use function strstr; use function substr; final class Parser { /** * @psalm-param list<string> $argv * @psalm-param list<string> $longOptions * * @psalm-return array{0: array, 1: array} * * @throws AmbiguousOptionException * @throws OptionDoesNotAllowArgumentException * @throws RequiredOptionArgumentMissingException * @throws UnknownOptionException */ public function parse(array $argv, string $shortOptions, array $longOptions = null): array { if (empty($argv)) { return [[], []]; } $options = []; $nonOptions = []; if ($longOptions) { sort($longOptions); } if (isset($argv[0][0]) && $argv[0][0] !== '-') { array_shift($argv); } reset($argv); $argv = array_map('trim', $argv); while (false !== $arg = current($argv)) { $i = key($argv); assert(is_int($i)); next($argv); if ($arg === '') { continue; } if ($arg === '--') { $nonOptions = array_merge($nonOptions, array_slice($argv, $i + 1)); break; } if ($arg[0] !== '-' || (strlen($arg) > 1 && $arg[1] === '-' && !$longOptions)) { $nonOptions[] = $arg; continue; } if (strlen($arg) > 1 && $arg[1] === '-' && is_array($longOptions)) { $this->parseLongOption( substr($arg, 2), $longOptions, $options, $argv ); continue; } $this->parseShortOption( substr($arg, 1), $shortOptions, $options, $argv ); } return [$options, $nonOptions]; } /** * @throws RequiredOptionArgumentMissingException */ private function parseShortOption(string $argument, string $shortOptions, array &$options, array &$argv): void { $argumentLength = strlen($argument); for ($i = 0; $i < $argumentLength; $i++) { $option = $argument[$i]; $optionArgument = null; if ($argument[$i] === ':' || ($spec = strstr($shortOptions, $option)) === false) { throw new UnknownOptionException('-' . $option); } if (strlen($spec) > 1 && $spec[1] === ':') { if ($i + 1 < $argumentLength) { $options[] = [$option, substr($argument, $i + 1)]; break; } if (!(strlen($spec) > 2 && $spec[2] === ':')) { $optionArgument = current($argv); if (!$optionArgument) { throw new RequiredOptionArgumentMissingException('-' . $option); } assert(is_string($optionArgument)); next($argv); } } $options[] = [$option, $optionArgument]; } } /** * @psalm-param list<string> $longOptions * * @throws AmbiguousOptionException * @throws OptionDoesNotAllowArgumentException * @throws RequiredOptionArgumentMissingException * @throws UnknownOptionException */ private function parseLongOption(string $argument, array $longOptions, array &$options, array &$argv): void { $count = count($longOptions); $list = explode('=', $argument); $option = $list[0]; $optionArgument = null; if (count($list) > 1) { $optionArgument = $list[1]; } $optionLength = strlen($option); foreach ($longOptions as $i => $longOption) { $opt_start = substr($longOption, 0, $optionLength); if ($opt_start !== $option) { continue; } $opt_rest = substr($longOption, $optionLength); if ($opt_rest !== '' && $i + 1 < $count && $option[0] !== '=' && str_starts_with($longOptions[$i + 1], $option)) { throw new AmbiguousOptionException('--' . $option); } if (str_ends_with($longOption, '=')) { if (!str_ends_with($longOption, '==') && !strlen((string) $optionArgument)) { if (false === $optionArgument = current($argv)) { throw new RequiredOptionArgumentMissingException('--' . $option); } next($argv); } } elseif ($optionArgument) { throw new OptionDoesNotAllowArgumentException('--' . $option); } $fullOption = '--' . preg_replace('/={1,2}$/', '', $longOption); $options[] = [$fullOption, $optionArgument]; return; } throw new UnknownOptionException('--' . $option); } } cli-parser/README.md 0000644 00000002053 15111337760 0010070 0 ustar 00 [](https://packagist.org/packages/sebastian/cli-parser) [](https://github.com/sebastianbergmann/cli-parser/actions) [](https://shepherd.dev/github/sebastianbergmann/cli-parser) [](https://codecov.io/gh/sebastianbergmann/cli-parser) # sebastian/cli-parser Library for parsing `$_SERVER['argv']`, extracted from `phpunit/phpunit`. ## Installation You can add this library as a local, per-project dependency to your project using [Composer](https://getcomposer.org/): ``` composer require sebastian/cli-parser ``` If you only need this library during development, for instance to run your project's test suite, then you should add it as a development-time dependency: ``` composer require --dev sebastian/cli-parser ``` cli-parser/LICENSE 0000644 00000002773 15111337760 0007627 0 ustar 00 BSD 3-Clause License Copyright (c) 2020-2023, Sebastian Bergmann All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. cli-parser/ChangeLog.md 0000644 00000001252 15111337760 0010762 0 ustar 00 # ChangeLog All notable changes are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles. ## [2.0.0] - 2023-02-03 ### Removed * This component is no longer supported on PHP 7.3, PHP 7.4, and PHP 8.0 ## [1.0.1] - 2020-09-28 ### Changed * Changed PHP version constraint in `composer.json` from `^7.3 || ^8.0` to `>=7.3` ## [1.0.0] - 2020-08-12 * Initial release [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 cli-parser/composer.json 0000644 00000001636 15111337760 0011341 0 ustar 00 { "name": "sebastian/cli-parser", "description": "Library for parsing CLI options", "type": "library", "homepage": "https://github.com/sebastianbergmann/cli-parser", "license": "BSD-3-Clause", "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "lead" } ], "support": { "issues": "https://github.com/sebastianbergmann/cli-parser/issues" }, "prefer-stable": true, "require": { "php": ">=8.1" }, "require-dev": { "phpunit/phpunit": "^10.0" }, "config": { "platform": { "php": "8.1.0" }, "optimize-autoloader": true, "sort-packages": true }, "autoload": { "classmap": [ "src/" ] }, "extra": { "branch-alias": { "dev-main": "2.0-dev" } } } cli-parser/SECURITY.md 0000644 00000001120 15111337760 0010374 0 ustar 00 # 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 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.** ## Security Contact Information After the above, if you still would like to report a security vulnerability, please email `sebastian@phpunit.de`. environment/src/Console.php 0000644 00000011632 15111337760 0012021 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/environment. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Environment; use const DIRECTORY_SEPARATOR; use const STDIN; use const STDOUT; use function defined; use function fclose; use function fstat; use function function_exists; use function getenv; use function is_resource; use function is_string; use function posix_isatty; use function preg_match; use function proc_close; use function proc_open; use function sapi_windows_vt100_support; use function shell_exec; use function stream_get_contents; use function stream_isatty; use function trim; final class Console { /** * @var int */ public const STDIN = 0; /** * @var int */ public const STDOUT = 1; /** * @var int */ public const STDERR = 2; /** * Returns true if STDOUT supports colorization. * * This code has been copied and adapted from * Symfony\Component\Console\Output\StreamOutput. */ public function hasColorSupport(): bool { if ('Hyper' === getenv('TERM_PROGRAM')) { return true; } if ($this->isWindows()) { // @codeCoverageIgnoreStart return (defined('STDOUT') && function_exists('sapi_windows_vt100_support') && @sapi_windows_vt100_support(STDOUT)) || false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI') || 'xterm' === getenv('TERM'); // @codeCoverageIgnoreEnd } if (!defined('STDOUT')) { // @codeCoverageIgnoreStart return false; // @codeCoverageIgnoreEnd } return $this->isInteractive(STDOUT); } /** * Returns the number of columns of the terminal. * * @codeCoverageIgnore */ public function getNumberOfColumns(): int { if (!$this->isInteractive(defined('STDIN') ? STDIN : self::STDIN)) { return 80; } if ($this->isWindows()) { return $this->getNumberOfColumnsWindows(); } return $this->getNumberOfColumnsInteractive(); } /** * 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, * eg when running code in interactive console (`php -a`), STDIN/STDOUT/STDERR constants are not defined. * * @param int|resource $fileDescriptor */ public function isInteractive($fileDescriptor = self::STDOUT): bool { if (is_resource($fileDescriptor)) { if (function_exists('stream_isatty') && @stream_isatty($fileDescriptor)) { return true; } if (function_exists('fstat')) { $stat = @fstat(STDOUT); return $stat && 0020000 === ($stat['mode'] & 0170000); } return false; } return function_exists('posix_isatty') && @posix_isatty($fileDescriptor); } private function isWindows(): bool { return DIRECTORY_SEPARATOR === '\\'; } /** * @codeCoverageIgnore */ private function getNumberOfColumnsInteractive(): int { if (function_exists('shell_exec') && preg_match('#\d+ (\d+)#', shell_exec('stty size') ?: '', $match) === 1) { if ((int) $match[1] > 0) { return (int) $match[1]; } } if (function_exists('shell_exec') && preg_match('#columns = (\d+);#', shell_exec('stty') ?: '', $match) === 1) { if ((int) $match[1] > 0) { return (int) $match[1]; } } return 80; } /** * @codeCoverageIgnore */ private function getNumberOfColumnsWindows(): int { $ansicon = getenv('ANSICON'); $columns = 80; if (is_string($ansicon) && preg_match('/^(\d+)x\d+ \(\d+x(\d+)\)$/', trim($ansicon), $matches)) { $columns = (int) $matches[1]; } elseif (function_exists('proc_open')) { $process = proc_open( 'mode CON', [ 1 => ['pipe', 'w'], 2 => ['pipe', 'w'], ], $pipes, null, null, ['suppress_errors' => true] ); if (is_resource($process)) { $info = stream_get_contents($pipes[1]); fclose($pipes[1]); fclose($pipes[2]); proc_close($process); if (preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) { $columns = (int) $matches[2]; } } } return $columns - 1; } } environment/src/Runtime.php 0000644 00000016044 15111337760 0012044 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/environment. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Environment; use const PHP_BINARY; use const PHP_BINDIR; use const PHP_MAJOR_VERSION; use const PHP_SAPI; use const PHP_VERSION; use function array_map; use function array_merge; use function escapeshellarg; use function explode; use function extension_loaded; use function ini_get; use function is_readable; use function parse_ini_file; use function php_ini_loaded_file; use function php_ini_scanned_files; use function phpversion; use function sprintf; use function strrpos; final class Runtime { private static string $binary; private static bool $initialized = false; /** * Returns true when Xdebug or PCOV is available or * the runtime used is PHPDBG. */ public function canCollectCodeCoverage(): bool { return $this->hasXdebug() || $this->hasPCOV() || $this->hasPHPDBGCodeCoverage(); } /** * Returns true when Zend OPcache is loaded, enabled, * and is configured to discard comments. */ public function discardsComments(): bool { if (!$this->isOpcacheActive()) { return false; } if (ini_get('opcache.save_comments') !== '0') { return false; } return true; } /** * Returns true when Zend OPcache is loaded, enabled, * and is configured to perform just-in-time compilation. */ public function performsJustInTimeCompilation(): bool { if (PHP_MAJOR_VERSION < 8) { return false; } if (!$this->isOpcacheActive()) { return false; } 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; } return true; } /** * Returns the path to the binary of the current runtime. */ public function getBinary(): string { if (self::$initialized) { return self::$binary; } if (PHP_BINARY !== '') { self::$binary = escapeshellarg(PHP_BINARY); self::$initialized = true; return self::$binary; } // @codeCoverageIgnoreStart $possibleBinaryLocations = [ PHP_BINDIR . '/php', PHP_BINDIR . '/php-cli.exe', PHP_BINDIR . '/php.exe', ]; foreach ($possibleBinaryLocations as $binary) { if (is_readable($binary)) { self::$binary = escapeshellarg($binary); self::$initialized = true; return self::$binary; } } // @codeCoverageIgnoreStart self::$binary = 'php'; self::$initialized = true; // @codeCoverageIgnoreEnd return self::$binary; } public function getNameWithVersion(): string { return $this->getName() . ' ' . $this->getVersion(); } public function getNameWithVersionAndCodeCoverageDriver(): string { if ($this->hasPCOV()) { return sprintf( '%s with PCOV %s', $this->getNameWithVersion(), phpversion('pcov') ); } if ($this->hasXdebug()) { return sprintf( '%s with Xdebug %s', $this->getNameWithVersion(), phpversion('xdebug') ); } return $this->getNameWithVersion(); } public function getName(): string { if ($this->isPHPDBG()) { // @codeCoverageIgnoreStart return 'PHPDBG'; // @codeCoverageIgnoreEnd } return 'PHP'; } public function getVendorUrl(): string { return 'https://www.php.net/'; } public function getVersion(): string { return PHP_VERSION; } /** * Returns true when the runtime used is PHP and Xdebug is loaded. */ public function hasXdebug(): bool { return $this->isPHP() && extension_loaded('xdebug'); } /** * Returns true when the runtime used is PHP without the PHPDBG SAPI. */ public function isPHP(): bool { return !$this->isPHPDBG(); } /** * Returns true when the runtime used is PHP with the PHPDBG SAPI. */ public function isPHPDBG(): bool { return PHP_SAPI === 'phpdbg'; } /** * Returns true when the runtime used is PHP with the PHPDBG SAPI * and the phpdbg_*_oplog() functions are available (PHP >= 7.0). */ public function hasPHPDBGCodeCoverage(): bool { return $this->isPHPDBG(); } /** * Returns true when the runtime used is PHP with PCOV loaded and enabled. */ public function hasPCOV(): bool { return $this->isPHP() && extension_loaded('pcov') && ini_get('pcov.enabled'); } /** * Parses the loaded php.ini file (if any) as well as all * additional php.ini files from the additional ini dir for * a list of all configuration settings loaded from files * at startup. Then checks for each php.ini setting passed * via the `$values` parameter whether this setting has * been changed at runtime. Returns an array of strings * where each string has the format `key=value` denoting * the name of a changed php.ini setting with its new value. * * @return string[] */ public function getCurrentSettings(array $values): array { $diff = []; $files = []; if ($file = php_ini_loaded_file()) { $files[] = $file; } if ($scanned = php_ini_scanned_files()) { $files = array_merge( $files, array_map( 'trim', explode(",\n", $scanned) ) ); } foreach ($files as $ini) { $config = parse_ini_file($ini, true); foreach ($values as $value) { $set = ini_get($value); if (empty($set)) { continue; } if ((!isset($config[$value]) || ($set !== $config[$value]))) { $diff[$value] = sprintf('%s=%s', $value, $set); } } } return $diff; } private function isOpcacheActive(): bool { if (!extension_loaded('Zend OPcache')) { return false; } if ((PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') && ini_get('opcache.enable_cli') === '1') { return true; } if (PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg' && ini_get('opcache.enable') === '1') { return true; } return false; } } environment/README.md 0000644 00000002146 15111337760 0010376 0 ustar 00 [](https://packagist.org/packages/sebastian/environment) [](https://github.com/sebastianbergmann/environment/actions) [](https://shepherd.dev/github/sebastianbergmann/environment) [](https://codecov.io/gh/sebastianbergmann/environment) # sebastian/environment This component provides functionality that helps writing PHP code that has runtime-specific (PHP / HHVM) execution paths. ## Installation You can add this library as a local, per-project dependency to your project using [Composer](https://getcomposer.org/): ``` composer require sebastian/environment ``` If you only need this library during development, for instance to run your project's test suite, then you should add it as a development-time dependency: ``` composer require --dev sebastian/environment ``` environment/LICENSE 0000644 00000002773 15111337760 0010132 0 ustar 00 BSD 3-Clause License Copyright (c) 2014-2023, Sebastian Bergmann All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. environment/ChangeLog.md 0000644 00000015070 15111337760 0011270 0 ustar 00 # Changes in sebastianbergmann/environment All notable changes in `sebastianbergmann/environment` are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles. ## [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 * Removed `SebastianBergmann\Environment\OperatingSystem::getFamily()` because this component is no longer supported on PHP versions that do not have `PHP_OS_FAMILY` * Removed `SebastianBergmann\Environment\Runtime::isHHVM()` * This component is no longer supported on PHP 7.3, PHP 7.4, and PHP 8.0 ## [5.1.5] - 2022-MM-DD ### Fixed * [#59](https://github.com/sebastianbergmann/environment/issues/59): Wrong usage of `stream_isatty()`, `fstat()` used without checking whether the function is available ## [5.1.4] - 2022-04-03 ### Fixed * [#63](https://github.com/sebastianbergmann/environment/pull/63): `Runtime::getCurrentSettings()` does not correctly process INI settings ## [5.1.3] - 2020-09-28 ### Changed * Changed PHP version constraint in `composer.json` from `^7.3 || ^8.0` to `>=7.3` ## [5.1.2] - 2020-06-26 ### Added * This component is now supported on PHP 8 ## [5.1.1] - 2020-06-15 ### Changed * Tests etc. are now ignored for archive exports ## [5.1.0] - 2020-04-14 ### Added * `Runtime::performsJustInTimeCompilation()` returns `true` if PHP 8's JIT is active, `false` otherwise ## [5.0.2] - 2020-03-31 ### Fixed * [#55](https://github.com/sebastianbergmann/environment/issues/55): `stty` command is executed even if no tty is available ## [5.0.1] - 2020-02-19 ### Changed * `Runtime::getNameWithVersionAndCodeCoverageDriver()` now prioritizes PCOV over Xdebug when both extensions are loaded (just like php-code-coverage does) ## [5.0.0] - 2020-02-07 ### Removed * This component is no longer supported on PHP 7.1 and PHP 7.2 ## [4.2.3] - 2019-11-20 ### Changed * [#50](https://github.com/sebastianbergmann/environment/pull/50): Windows improvements to console capabilities ### Fixed * [#49](https://github.com/sebastianbergmann/environment/issues/49): Detection how OpCache handles docblocks does not work correctly when PHPDBG is used ## [4.2.2] - 2019-05-05 ### Fixed * [#44](https://github.com/sebastianbergmann/environment/pull/44): `TypeError` in `Console::getNumberOfColumnsInteractive()` ## [4.2.1] - 2019-04-25 ### Fixed * Fixed an issue in `Runtime::getCurrentSettings()` ## [4.2.0] - 2019-04-25 ### Added * [#36](https://github.com/sebastianbergmann/environment/pull/36): `Runtime::getCurrentSettings()` ## [4.1.0] - 2019-02-01 ### Added * Implemented `Runtime::getNameWithVersionAndCodeCoverageDriver()` method * [#34](https://github.com/sebastianbergmann/environment/pull/34): Support for PCOV extension ## [4.0.2] - 2019-01-28 ### Fixed * [#33](https://github.com/sebastianbergmann/environment/issues/33): `Runtime::discardsComments()` returns true too eagerly ### Removed * Removed support for Zend Optimizer+ in `Runtime::discardsComments()` ## [4.0.1] - 2018-11-25 ### Fixed * [#31](https://github.com/sebastianbergmann/environment/issues/31): Regressions in `Console` class ## [4.0.0] - 2018-10-23 [YANKED] ### Fixed * [#25](https://github.com/sebastianbergmann/environment/pull/25): `Console::hasColorSupport()` does not work on Windows ### Removed * This component is no longer supported on PHP 7.0 ## [3.1.0] - 2017-07-01 ### Added * [#21](https://github.com/sebastianbergmann/environment/issues/21): Equivalent of `PHP_OS_FAMILY` (for PHP < 7.2) ## [3.0.4] - 2017-06-20 ### Fixed * [#20](https://github.com/sebastianbergmann/environment/pull/20): PHP 7 mode of HHVM not forced ## [3.0.3] - 2017-05-18 ### Fixed * [#18](https://github.com/sebastianbergmann/environment/issues/18): `Uncaught TypeError: preg_match() expects parameter 2 to be string, null given` ## [3.0.2] - 2017-04-21 ### Fixed * [#17](https://github.com/sebastianbergmann/environment/issues/17): `Uncaught TypeError: trim() expects parameter 1 to be string, boolean given` ## [3.0.1] - 2017-04-21 ### Fixed * Fixed inverted logic in `Runtime::discardsComments()` ## [3.0.0] - 2017-04-21 ### Added * Implemented `Runtime::discardsComments()` for querying whether the PHP runtime discards annotations ### Removed * This component is no longer supported on PHP 5.6 [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 [5.1.3]: https://github.com/sebastianbergmann/environment/compare/5.1.2...5.1.3 [5.1.2]: https://github.com/sebastianbergmann/environment/compare/5.1.1...5.1.2 [5.1.1]: https://github.com/sebastianbergmann/environment/compare/5.1.0...5.1.1 [5.1.0]: https://github.com/sebastianbergmann/environment/compare/5.0.2...5.1.0 [5.0.2]: https://github.com/sebastianbergmann/environment/compare/5.0.1...5.0.2 [5.0.1]: https://github.com/sebastianbergmann/environment/compare/5.0.0...5.0.1 [5.0.0]: https://github.com/sebastianbergmann/environment/compare/4.2.3...5.0.0 [4.2.3]: https://github.com/sebastianbergmann/environment/compare/4.2.2...4.2.3 [4.2.2]: https://github.com/sebastianbergmann/environment/compare/4.2.1...4.2.2 [4.2.1]: https://github.com/sebastianbergmann/environment/compare/4.2.0...4.2.1 [4.2.0]: https://github.com/sebastianbergmann/environment/compare/4.1.0...4.2.0 [4.1.0]: https://github.com/sebastianbergmann/environment/compare/4.0.2...4.1.0 [4.0.2]: https://github.com/sebastianbergmann/environment/compare/4.0.1...4.0.2 [4.0.1]: https://github.com/sebastianbergmann/environment/compare/66691f8e2dc4641909166b275a9a4f45c0e89092...4.0.1 [4.0.0]: https://github.com/sebastianbergmann/environment/compare/3.1.0...66691f8e2dc4641909166b275a9a4f45c0e89092 [3.1.0]: https://github.com/sebastianbergmann/environment/compare/3.0...3.1.0 [3.0.4]: https://github.com/sebastianbergmann/environment/compare/3.0.3...3.0.4 [3.0.3]: https://github.com/sebastianbergmann/environment/compare/3.0.2...3.0.3 [3.0.2]: https://github.com/sebastianbergmann/environment/compare/3.0.1...3.0.2 [3.0.1]: https://github.com/sebastianbergmann/environment/compare/3.0.0...3.0.1 [3.0.0]: https://github.com/sebastianbergmann/environment/compare/2.0...3.0.0 environment/composer.json 0000644 00000002077 15111337760 0011644 0 ustar 00 { "name": "sebastian/environment", "description": "Provides functionality to handle HHVM/PHP environments", "keywords": ["environment","hhvm","xdebug"], "homepage": "https://github.com/sebastianbergmann/environment", "license": "BSD-3-Clause", "authors": [ { "name": "Sebastian Bergmann", "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" }, "optimize-autoloader": true, "sort-packages": true }, "prefer-stable": true, "require": { "php": ">=8.1" }, "require-dev": { "phpunit/phpunit": "^10.0" }, "suggest": { "ext-posix": "*" }, "autoload": { "classmap": [ "src/" ] }, "extra": { "branch-alias": { "dev-main": "6.0-dev" } } } environment/SECURITY.md 0000644 00000003565 15111337760 0010716 0 ustar 00 # Security Policy 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. **Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.** 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. version/src/Version.php 0000644 00000003776 15111337760 0011177 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/version. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann; use function end; use function explode; use function fclose; use function is_dir; use function is_resource; use function proc_close; use function proc_open; use function stream_get_contents; use function substr_count; use function trim; final class Version { private readonly string $version; public function __construct(string $release, string $path) { $this->version = $this->generate($release, $path); } public function asString(): string { return $this->version; } private function generate(string $release, string $path): string { if (substr_count($release, '.') + 1 === 3) { $version = $release; } else { $version = $release . '-dev'; } $git = $this->getGitInformation($path); if (!$git) { return $version; } if (substr_count($release, '.') + 1 === 3) { return $git; } $git = explode('-', $git); return $release . '-' . end($git); } private function getGitInformation(string $path): bool|string { if (!is_dir($path . DIRECTORY_SEPARATOR . '.git')) { return false; } $process = proc_open( 'git describe --tags', [ 1 => ['pipe', 'w'], 2 => ['pipe', 'w'], ], $pipes, $path ); if (!is_resource($process)) { return false; } $result = trim(stream_get_contents($pipes[1])); fclose($pipes[1]); fclose($pipes[2]); $returnCode = proc_close($process); if ($returnCode !== 0) { return false; } return $result; } } version/README.md 0000644 00000004234 15111337760 0007517 0 ustar 00 [](https://packagist.org/packages/sebastian/version) # sebastian/version **sebastian/version** is a library that helps with managing the version number of Git-hosted PHP projects. ## Installation You can add this library as a local, per-project dependency to your project using [Composer](https://getcomposer.org/): ``` composer require sebastian/version ``` If you only need this library during development, for instance to run your project's test suite, then you should add it as a development-time dependency: ``` composer require --dev sebastian/version ``` ## Usage The constructor of the `SebastianBergmann\Version` class expects two parameters: * `$release` is the version number of the latest release (`X.Y.Z`, for instance) or the name of the release series (`X.Y`) when no release has been made from that branch / for that release series yet. * `$path` is the path to the directory (or a subdirectory thereof) where the sourcecode of the project can be found. Simply passing `__DIR__` here usually suffices. Apart from the constructor, the `SebastianBergmann\Version` class has a single public method: `asString()`. Here is a contrived example that shows the basic usage: ```php <?php declare(strict_types=1); use SebastianBergmann\Version; $version = new Version('1.0.0', __DIR__); var_dump($version->asString()); ``` ``` string(18) "1.0.0-17-g00f3408" ``` When a new release is prepared, the string that is passed to the constructor as the first argument needs to be updated. ### How SebastianBergmann\Version::asString() works * If `$path` is not (part of) a Git repository and `$release` is in `X.Y.Z` format then `$release` is returned as-is. * If `$path` is not (part of) a Git repository and `$release` is in `X.Y` format then `$release` is returned suffixed with `-dev`. * If `$path` is (part of) a Git repository and `$release` is in `X.Y.Z` format then the output of `git describe --tags` is returned as-is. * If `$path` is (part of) a Git repository and `$release` is in `X.Y` format then a string is returned that begins with `X.Y` and ends with information from `git describe --tags`. version/LICENSE 0000644 00000002773 15111337760 0007253 0 ustar 00 BSD 3-Clause License Copyright (c) 2013-2023, Sebastian Bergmann All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. version/ChangeLog.md 0000644 00000002202 15111337760 0010402 0 ustar 00 # ChangeLog All notable changes are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles. ## [4.0.1] - 2023-02-07 ### Fixed * [#17](https://github.com/sebastianbergmann/version/pull/17): Release archive contains unnecessary assets ## [4.0.0] - 2023-02-03 ### Changed * `Version::getVersion()` has been renamed to `Version::asString()` ### Removed * This component is no longer supported on PHP 7.3, PHP 7.4, and PHP 8.0 ## [3.0.2] - 2020-09-28 ### Changed * Changed PHP version constraint in `composer.json` from `^7.3 || ^8.0` to `>=7.3` ## [3.0.1] - 2020-06-26 ### Added * This component is now supported on PHP 8 ## [3.0.0] - 2020-01-21 ### Removed * This component is no longer supported on PHP 7.1 and PHP 7.2 [4.0.1]: https://github.com/sebastianbergmann/version/compare/4.0.0...4.0.1 [4.0.0]: https://github.com/sebastianbergmann/version/compare/3.0.2...4.0.0 [3.0.2]: https://github.com/sebastianbergmann/version/compare/3.0.1...3.0.2 [3.0.1]: https://github.com/sebastianbergmann/version/compare/3.0.0...3.0.1 [3.0.0]: https://github.com/sebastianbergmann/version/compare/2.0.1...3.0.0 version/composer.json 0000644 00000001556 15111337760 0010766 0 ustar 00 { "name": "sebastian/version", "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", "license": "BSD-3-Clause", "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "lead" } ], "support": { "issues": "https://github.com/sebastianbergmann/version/issues" }, "config": { "platform": { "php": "8.1.0" }, "optimize-autoloader": true, "sort-packages": true }, "prefer-stable": true, "require": { "php": ">=8.1" }, "autoload": { "classmap": [ "src/" ] }, "extra": { "branch-alias": { "dev-main": "4.0-dev" } } } version/SECURITY.md 0000644 00000001120 15111337760 0010020 0 ustar 00 # 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 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.** ## Security Contact Information After the above, if you still would like to report a security vulnerability, please email `sebastian@phpunit.de`. code-unit-reverse-lookup/src/Wizard.php 0000644 00000006253 15111337760 0014165 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/code-unit-reverse-lookup. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\CodeUnitReverseLookup; use function array_merge; use function assert; use function get_declared_classes; use function get_declared_traits; use function get_defined_functions; use function is_array; use function range; use ReflectionClass; use ReflectionFunction; use ReflectionFunctionAbstract; use ReflectionMethod; class Wizard { /** * @psalm-var array<string,array<int,string>> */ private array $lookupTable = []; /** * @psalm-var array<class-string,true> */ private array $processedClasses = []; /** * @psalm-var array<string,true> */ private array $processedFunctions = []; public function lookup(string $filename, int $lineNumber): string { if (!isset($this->lookupTable[$filename][$lineNumber])) { $this->updateLookupTable(); } if (isset($this->lookupTable[$filename][$lineNumber])) { return $this->lookupTable[$filename][$lineNumber]; } return $filename . ':' . $lineNumber; } private function updateLookupTable(): void { $this->processClassesAndTraits(); $this->processFunctions(); } private function processClassesAndTraits(): void { $classes = get_declared_classes(); $traits = get_declared_traits(); /* @noinspection PhpConditionAlreadyCheckedInspection */ assert(is_array($traits)); foreach (array_merge($classes, $traits) as $classOrTrait) { if (isset($this->processedClasses[$classOrTrait])) { continue; } foreach ((new ReflectionClass($classOrTrait))->getMethods() as $method) { $this->processFunctionOrMethod($method); } $this->processedClasses[$classOrTrait] = true; } } private function processFunctions(): void { foreach (get_defined_functions()['user'] as $function) { if (isset($this->processedFunctions[$function])) { continue; } $this->processFunctionOrMethod(new ReflectionFunction($function)); $this->processedFunctions[$function] = true; } } private function processFunctionOrMethod(ReflectionFunctionAbstract $functionOrMethod): void { if ($functionOrMethod->isInternal()) { return; } $name = $functionOrMethod->getName(); if ($functionOrMethod instanceof ReflectionMethod) { $name = $functionOrMethod->getDeclaringClass()->getName() . '::' . $name; } if (!isset($this->lookupTable[$functionOrMethod->getFileName()])) { $this->lookupTable[$functionOrMethod->getFileName()] = []; } foreach (range($functionOrMethod->getStartLine(), $functionOrMethod->getEndLine()) as $line) { $this->lookupTable[$functionOrMethod->getFileName()][$line] = $name; } } } code-unit-reverse-lookup/README.md 0000644 00000002270 15111337760 0012677 0 ustar 00 [](https://packagist.org/packages/sebastian/code-unit-reverse-lookup) [](https://github.com/sebastianbergmann/code-unit-reverse-lookup/actions) [](https://shepherd.dev/github/sebastianbergmann/code-unit-reverse-lookup) [](https://codecov.io/gh/sebastianbergmann/code-unit-reverse-lookup) # sebastian/code-unit-reverse-lookup Looks up which function or method a line of code belongs to. ## Installation You can add this library as a local, per-project dependency to your project using [Composer](https://getcomposer.org/): ``` composer require sebastian/code-unit-reverse-lookup ``` If you only need this library during development, for instance to run your project's test suite, then you should add it as a development-time dependency: ``` composer require --dev sebastian/code-unit-reverse-lookup ``` code-unit-reverse-lookup/LICENSE 0000644 00000002773 15111337760 0012435 0 ustar 00 BSD 3-Clause License Copyright (c) 2016-2023, Sebastian Bergmann All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. code-unit-reverse-lookup/ChangeLog.md 0000644 00000002303 15111337760 0013566 0 ustar 00 # Change Log All notable changes to `sebastianbergmann/code-unit-reverse-lookup` are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles. ## [3.0.0] - 2023-02-03 ### Removed * This component is no longer supported on PHP 7.3, PHP 7.4, and PHP 8.0 ## [2.0.3] - 2020-09-28 ### Changed * Changed PHP version constraint in `composer.json` from `^7.3 || ^8.0` to `>=7.3` ## [2.0.2] - 2020-06-26 ### Added * This component is now supported on PHP 8 ## [2.0.1] - 2020-06-15 ### Changed * Tests etc. are now ignored for archive exports ## 2.0.0 - 2020-02-07 ### Removed * This component is no longer supported on PHP 5.6, PHP 7.0, PHP 7.1, and PHP 7.2 ## 1.0.0 - 2016-02-13 ### Added * Initial release [3.0.0]: https://github.com/sebastianbergmann/code-unit-reverse-lookup/compare/2.0.3...3.0.0 [2.0.3]: https://github.com/sebastianbergmann/code-unit-reverse-lookup/compare/2.0.2...2.0.3 [2.0.2]: https://github.com/sebastianbergmann/code-unit-reverse-lookup/compare/2.0.1...2.0.2 [2.0.1]: https://github.com/sebastianbergmann/code-unit-reverse-lookup/compare/2.0.0...2.0.1 [2.0.0]: https://github.com/sebastianbergmann/code-unit-reverse-lookup/compare/1.0.0...2.0.0 code-unit-reverse-lookup/composer.json 0000644 00000001501 15111337760 0014136 0 ustar 00 { "name": "sebastian/code-unit-reverse-lookup", "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", "license": "BSD-3-Clause", "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], "config": { "platform": { "php": "8.1.0" }, "optimize-autoloader": true, "sort-packages": true }, "prefer-stable": true, "require": { "php": ">=8.1" }, "require-dev": { "phpunit/phpunit": "^10.0" }, "autoload": { "classmap": [ "src/" ] }, "extra": { "branch-alias": { "dev-main": "3.0-dev" } } } code-unit-reverse-lookup/SECURITY.md 0000644 00000001120 15111337760 0013202 0 ustar 00 # 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 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.** ## Security Contact Information After the above, if you still would like to report a security vulnerability, please email `sebastian@phpunit.de`. code-unit-reverse-lookup/.psalm/config.xml 0000644 00000000722 15111337760 0014601 0 ustar 00 <?xml version="1.0"?> <psalm xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://getpsalm.org/schema/config" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" resolveFromConfigFile="false" errorBaseline=".psalm/baseline.xml" > <projectFiles> <directory name="src" /> <ignoreFiles> <directory name="vendor" /> </ignoreFiles> </projectFiles> </psalm> code-unit-reverse-lookup/.psalm/baseline.xml 0000644 00000000444 15111337760 0015117 0 ustar 00 <?xml version="1.0" encoding="UTF-8"?> <files psalm-version="5.5.0@b63061a27f2683ec0f3509012bb22daab3b65b61"> <file src="src/Wizard.php"> <RedundantCondition> <code>assert(is_array($traits))</code> <code>is_array($traits)</code> </RedundantCondition> </file> </files> recursion-context/src/Context.php 0000644 00000007021 15111337760 0013167 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/recursion-context. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\RecursionContext; use const PHP_INT_MAX; use const PHP_INT_MIN; use function array_key_exists; use function array_pop; use function array_slice; use function count; use function is_array; use function random_int; use function spl_object_hash; use SplObjectStorage; final class Context { private array $arrays = []; private SplObjectStorage $objects; public function __construct() { $this->objects = new SplObjectStorage; } /** * @codeCoverageIgnore */ public function __destruct() { foreach ($this->arrays as &$array) { if (is_array($array)) { array_pop($array); array_pop($array); } } } /** * @psalm-template T * * @psalm-param T $value * * @param-out T $value */ public function add(object|array &$value): int|string|false { if (is_array($value)) { return $this->addArray($value); } return $this->addObject($value); } /** * @psalm-template T * * @psalm-param T $value * * @param-out T $value */ public function contains(object|array &$value): int|string|false { if (is_array($value)) { return $this->containsArray($value); } return $this->containsObject($value); } private function addArray(array &$array): int { $key = $this->containsArray($array); if ($key !== false) { return $key; } $key = count($this->arrays); $this->arrays[] = &$array; if (!array_key_exists(PHP_INT_MAX, $array) && !array_key_exists(PHP_INT_MAX - 1, $array)) { $array[] = $key; $array[] = $this->objects; } else { /* Cover the improbable case, too. * * Note that array_slice() (used in containsArray()) will return the * last two values added, *not necessarily* the highest integer keys * in the array. Therefore, the order of these writes to $array is * important, but the actual keys used is not. */ do { /** @noinspection PhpUnhandledExceptionInspection */ $key = random_int(PHP_INT_MIN, PHP_INT_MAX); } while (array_key_exists($key, $array)); $array[$key] = $key; do { /** @noinspection PhpUnhandledExceptionInspection */ $key = random_int(PHP_INT_MIN, PHP_INT_MAX); } while (array_key_exists($key, $array)); $array[$key] = $this->objects; } return $key; } private function addObject(object $object): string { if (!$this->objects->contains($object)) { $this->objects->attach($object); } return spl_object_hash($object); } private function containsArray(array $array): int|false { $end = array_slice($array, -2); return isset($end[1]) && $end[1] === $this->objects ? $end[0] : false; } private function containsObject(object $value): string|false { if ($this->objects->contains($value)) { return spl_object_hash($value); } return false; } } recursion-context/README.md 0000644 00000002055 15111337760 0011524 0 ustar 00 [](https://packagist.org/packages/sebastian/recursion-context) [](https://github.com/sebastianbergmann/recursion-context/actions) [](https://shepherd.dev/github/sebastianbergmann/recursion-context) [](https://codecov.io/gh/sebastianbergmann/recursion-context) # sebastian/recursion-context ## Installation You can add this library as a local, per-project dependency to your project using [Composer](https://getcomposer.org/): ``` composer require sebastian/recursion-context ``` If you only need this library during development, for instance to run your project's test suite, then you should add it as a development-time dependency: ``` composer require --dev sebastian/recursion-context ``` recursion-context/LICENSE 0000644 00000002773 15111337760 0011261 0 ustar 00 BSD 3-Clause License Copyright (c) 2002-2023, Sebastian Bergmann All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. recursion-context/ChangeLog.md 0000644 00000002673 15111337760 0012424 0 ustar 00 # ChangeLog All notable changes are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles. ## [5.0.0] - 2023-02-03 ### Removed * This component is no longer supported on PHP 7.3, PHP 7.4 and PHP 8.0 ## [4.0.5] - 2023-02-03 ### Fixed * [#26](https://github.com/sebastianbergmann/recursion-context/pull/26): Don't clobber `null` values if `array_key_exists(PHP_INT_MAX, $array)` ## [4.0.4] - 2020-10-26 ### Fixed * `SebastianBergmann\RecursionContext\Exception` now correctly extends `\Throwable` ## [4.0.3] - 2020-09-28 ### Changed * [#21](https://github.com/sebastianbergmann/recursion-context/pull/21): Add type annotations for in/out parameters * Changed PHP version constraint in `composer.json` from `^7.3 || ^8.0` to `>=7.3` ## [4.0.2] - 2020-06-26 ### Added * This component is now supported on PHP 8 ## [4.0.1] - 2020-06-15 ### Changed * Tests etc. are now ignored for archive exports [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 [4.0.3]: https://github.com/sebastianbergmann/recursion-context/compare/4.0.2...4.0.3 [4.0.2]: https://github.com/sebastianbergmann/recursion-context/compare/4.0.1...4.0.2 [4.0.1]: https://github.com/sebastianbergmann/recursion-context/compare/4.0.0...4.0.1 recursion-context/composer.json 0000644 00000001765 15111337760 0012776 0 ustar 00 { "name": "sebastian/recursion-context", "description": "Provides functionality to recursively process PHP variables", "homepage": "https://github.com/sebastianbergmann/recursion-context", "license": "BSD-3-Clause", "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" }, { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" }, { "name": "Adam Harvey", "email": "aharvey@php.net" } ], "prefer-stable": true, "config": { "platform": { "php": "8.1.0" }, "optimize-autoloader": true, "sort-packages": true }, "require": { "php": ">=8.1" }, "require-dev": { "phpunit/phpunit": "^10.0" }, "autoload": { "classmap": [ "src/" ] }, "extra": { "branch-alias": { "dev-main": "5.0-dev" } } } recursion-context/SECURITY.md 0000644 00000001120 15111337760 0012026 0 ustar 00 # 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 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.** ## Security Contact Information After the above, if you still would like to report a security vulnerability, please email `sebastian@phpunit.de`. object-reflector/src/ObjectReflector.php 0000644 00000001766 15111337760 0014367 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/object-reflector. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\ObjectReflector; use function count; use function explode; final class ObjectReflector { /** * @psalm-return array<string,mixed> */ public function getProperties(object $object): array { $properties = []; $className = $object::class; foreach ((array) $object as $name => $value) { $name = explode("\0", (string) $name); if (count($name) === 1) { $name = $name[0]; } elseif ($name[1] !== $className) { $name = $name[1] . '::' . $name[2]; } else { $name = $name[2]; } $properties[$name] = $value; } return $properties; } } object-reflector/README.md 0000644 00000002206 15111337760 0011260 0 ustar 00 [](https://packagist.org/packages/sebastian/object-reflector) [](https://github.com/sebastianbergmann/object-reflector/actions) [](https://shepherd.dev/github/sebastianbergmann/object-reflector) [](https://codecov.io/gh/sebastianbergmann/object-reflector) # sebastian/object-reflector Allows reflection of object properties, including inherited and private as well as protected ones. ## Installation You can add this library as a local, per-project dependency to your project using [Composer](https://getcomposer.org/): ``` composer require sebastian/object-reflector ``` If you only need this library during development, for instance to run your project's test suite, then you should add it as a development-time dependency: ``` composer require --dev sebastian/object-reflector ``` object-reflector/LICENSE 0000644 00000002773 15111337760 0011017 0 ustar 00 BSD 3-Clause License Copyright (c) 2017-2023, Sebastian Bergmann All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. object-reflector/ChangeLog.md 0000644 00000003636 15111337760 0012162 0 ustar 00 # Change Log All notable changes to `sebastianbergmann/object-reflector` are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles. ## [3.0.0] - 2023-02-03 ### Changed * `ObjectReflector::getAttributes()` has been renamed to `ObjectReflector::getProperties()` ### Removed * This component is no longer supported on PHP 7.3, PHP 7.4 and PHP 8.0 ## [2.0.4] - 2020-10-26 ### Fixed * `SebastianBergmann\ObjectReflector\Exception` now correctly extends `\Throwable` ## [2.0.3] - 2020-09-28 ### Changed * Changed PHP version constraint in `composer.json` from `^7.3 || ^8.0` to `>=7.3` ## [2.0.2] - 2020-06-26 ### Added * This component is now supported on PHP 8 ## [2.0.1] - 2020-06-15 ### Changed * Tests etc. are now ignored for archive exports ## [2.0.0] - 2020-02-07 ### Removed * This component is no longer supported on PHP 7.0, PHP 7.1, and PHP 7.2 ## [1.1.1] - 2017-03-29 * Fixed [#1](https://github.com/sebastianbergmann/object-reflector/issues/1): Attributes with non-string names are not handled correctly ## [1.1.0] - 2017-03-16 ### Changed * Changed implementation of `ObjectReflector::getattributes()` to use `(array)` cast instead of `ReflectionObject` ## 1.0.0 - 2017-03-12 * Initial release [3.0.0]: https://github.com/sebastianbergmann/object-reflector/compare/2.0.4...3.0.0 [2.0.4]: https://github.com/sebastianbergmann/object-reflector/compare/2.0.3...2.0.4 [2.0.3]: https://github.com/sebastianbergmann/object-reflector/compare/2.0.2...2.0.3 [2.0.2]: https://github.com/sebastianbergmann/object-reflector/compare/2.0.1...2.0.2 [2.0.1]: https://github.com/sebastianbergmann/object-reflector/compare/2.0.0...2.0.1 [2.0.0]: https://github.com/sebastianbergmann/object-reflector/compare/1.1.1...2.0.0 [1.1.1]: https://github.com/sebastianbergmann/object-reflector/compare/1.1.0...1.1.1 [1.1.0]: https://github.com/sebastianbergmann/object-reflector/compare/1.0.0...1.1.0 object-reflector/composer.json 0000644 00000001640 15111337760 0012524 0 ustar 00 { "name": "sebastian/object-reflector", "description": "Allows reflection of object attributes, including inherited and non-public ones", "homepage": "https://github.com/sebastianbergmann/object-reflector/", "license": "BSD-3-Clause", "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], "prefer-stable": true, "config": { "platform": { "php": "8.1.0" }, "optimize-autoloader": true, "sort-packages": true }, "require": { "php": ">=8.1" }, "require-dev": { "phpunit/phpunit": "^10.0" }, "autoload": { "classmap": [ "src/" ] }, "autoload-dev": { "classmap": [ "tests/_fixture/" ] }, "extra": { "branch-alias": { "dev-main": "3.0-dev" } } } object-reflector/SECURITY.md 0000644 00000001120 15111337760 0011564 0 ustar 00 # 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 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.** ## Security Contact Information After the above, if you still would like to report a security vulnerability, please email `sebastian@phpunit.de`. diff/src/LongestCommonSubsequenceCalculator.php 0000644 00000000746 15111337760 0015770 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/diff. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Diff; interface LongestCommonSubsequenceCalculator { /** * Calculates the longest common subsequence of two arrays. */ public function calculate(array $from, array $to): array; } diff/src/Differ.php 0000644 00000015113 15111337760 0010160 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/diff. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Diff; use const PHP_INT_SIZE; use const PREG_SPLIT_DELIM_CAPTURE; use const PREG_SPLIT_NO_EMPTY; use function array_shift; use function array_unshift; use function array_values; use function count; use function current; use function end; use function is_string; use function key; use function min; use function preg_split; use function prev; use function reset; use function str_ends_with; use function substr; 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 NO_LINE_END_EOF_WARNING = 4; private DiffOutputBuilderInterface $outputBuilder; public function __construct(DiffOutputBuilderInterface $outputBuilder) { $this->outputBuilder = $outputBuilder; } 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 { if (is_string($from)) { $from = $this->splitStringByLines($from); } if (is_string($to)) { $to = $this->splitStringByLines($to); } [$from, $to, $start, $end] = self::getArrayDiffParted($from, $to); if ($lcs === null) { $lcs = $this->selectLcsImplementation($from, $to); } $common = $lcs->calculate(array_values($from), array_values($to)); $diff = []; foreach ($start as $token) { $diff[] = [$token, self::OLD]; } reset($from); reset($to); foreach ($common as $token) { while (($fromToken = reset($from)) !== $token) { $diff[] = [array_shift($from), self::REMOVED]; } while (($toToken = reset($to)) !== $token) { $diff[] = [array_shift($to), self::ADDED]; } $diff[] = [$token, self::OLD]; array_shift($from); array_shift($to); } while (($token = array_shift($from)) !== null) { $diff[] = [$token, self::REMOVED]; } while (($token = array_shift($to)) !== null) { $diff[] = [$token, self::ADDED]; } foreach ($end as $token) { $diff[] = [$token, self::OLD]; } if ($this->detectUnmatchedLineEndings($diff)) { array_unshift($diff, ["#Warning: Strings contain different line endings!\n", self::DIFF_LINE_END_WARNING]); } return $diff; } private function splitStringByLines(string $input): array { return preg_split('/(.*\R)/', $input, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); } private function selectLcsImplementation(array $from, array $to): LongestCommonSubsequenceCalculator { // We do not want to use the time-efficient implementation if its memory // footprint will probably exceed this value. Note that the footprint // calculation is only an estimation for the matrix and the LCS method // will typically allocate a bit more memory than this. $memoryLimit = 100 * 1024 * 1024; if ($this->calculateEstimatedFootprint($from, $to) > $memoryLimit) { return new MemoryEfficientLongestCommonSubsequenceCalculator; } return new TimeEfficientLongestCommonSubsequenceCalculator; } private function calculateEstimatedFootprint(array $from, array $to): float|int { $itemSize = PHP_INT_SIZE === 4 ? 76 : 144; return $itemSize * min(count($from), count($to)) ** 2; } private function detectUnmatchedLineEndings(array $diff): bool { $newLineBreaks = ['' => true]; $oldLineBreaks = ['' => true]; foreach ($diff as $entry) { if (self::OLD === $entry[1]) { $ln = $this->getLinebreak($entry[0]); $oldLineBreaks[$ln] = true; $newLineBreaks[$ln] = true; } elseif (self::ADDED === $entry[1]) { $newLineBreaks[$this->getLinebreak($entry[0])] = true; } elseif (self::REMOVED === $entry[1]) { $oldLineBreaks[$this->getLinebreak($entry[0])] = true; } } // if either input or output is a single line without breaks than no warning should be raised if (['' => true] === $newLineBreaks || ['' => true] === $oldLineBreaks) { return false; } // two-way compare foreach ($newLineBreaks as $break => $set) { if (!isset($oldLineBreaks[$break])) { return true; } } foreach ($oldLineBreaks as $break => $set) { if (!isset($newLineBreaks[$break])) { return true; } } return false; } private function getLinebreak($line): string { if (!is_string($line)) { return ''; } $lc = substr($line, -1); if ("\r" === $lc) { return "\r"; } if ("\n" !== $lc) { return ''; } if (str_ends_with($line, "\r\n")) { return "\r\n"; } return "\n"; } private static function getArrayDiffParted(array &$from, array &$to): array { $start = []; $end = []; reset($to); foreach ($from as $k => $v) { $toK = key($to); if ($toK === $k && $v === $to[$k]) { $start[$k] = $v; unset($from[$k], $to[$k]); } else { break; } } end($from); end($to); do { $fromK = key($from); $toK = key($to); if (null === $fromK || null === $toK || current($from) !== current($to)) { break; } prev($from); prev($to); $end = [$fromK => $from[$fromK]] + $end; unset($from[$fromK], $to[$toK]); } while (true); return [$from, $to, $start, $end]; } } diff/src/Diff.php 0000644 00000002136 15111337760 0007632 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/diff. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Diff; final class Diff { private string $from; private string $to; /** * @psalm-var list<Chunk> */ private array $chunks; /** * @psalm-param list<Chunk> $chunks */ public function __construct(string $from, string $to, array $chunks = []) { $this->from = $from; $this->to = $to; $this->chunks = $chunks; } public function getFrom(): string { return $this->from; } public function getTo(): string { return $this->to; } /** * @psalm-return list<Chunk> */ public function getChunks(): array { return $this->chunks; } /** * @psalm-param list<Chunk> $chunks */ public function setChunks(array $chunks): void { $this->chunks = $chunks; } } diff/src/Output/DiffOnlyOutputBuilder.php 0000644 00000004061 15111337760 0014523 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/diff. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Diff\Output; use function fclose; use function fopen; use function fwrite; use function str_ends_with; use function stream_get_contents; use function substr; use SebastianBergmann\Diff\Differ; /** * Builds a diff string representation in a loose unified diff format * listing only changes lines. Does not include line numbers. */ final class DiffOnlyOutputBuilder implements DiffOutputBuilderInterface { private string $header; public function __construct(string $header = "--- Original\n+++ New\n") { $this->header = $header; } public function getDiff(array $diff): string { $buffer = fopen('php://memory', 'r+b'); if ('' !== $this->header) { fwrite($buffer, $this->header); if (!str_ends_with($this->header, "\n")) { fwrite($buffer, "\n"); } } foreach ($diff as $diffEntry) { if ($diffEntry[1] === Differ::ADDED) { fwrite($buffer, '+' . $diffEntry[0]); } elseif ($diffEntry[1] === Differ::REMOVED) { fwrite($buffer, '-' . $diffEntry[0]); } elseif ($diffEntry[1] === Differ::DIFF_LINE_END_WARNING) { fwrite($buffer, ' ' . $diffEntry[0]); continue; // Warnings should not be tested for line break, it will always be there } else { /* Not changed (old) 0 */ continue; // we didn't write the not-changed line, so do not add a line break either } $lc = substr($diffEntry[0], -1); if ($lc !== "\n" && $lc !== "\r") { fwrite($buffer, "\n"); // \No newline at end of file } } $diff = stream_get_contents($buffer, -1, 0); fclose($buffer); return $diff; } } diff/src/Output/StrictUnifiedDiffOutputBuilder.php 0000644 00000025242 15111337760 0016362 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/diff. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Diff\Output; use function array_merge; use function array_splice; use function count; use function fclose; use function fopen; use function fwrite; use function is_bool; use function is_int; use function is_string; use function max; use function min; use function sprintf; use function stream_get_contents; use function substr; use SebastianBergmann\Diff\ConfigurationException; use SebastianBergmann\Diff\Differ; /** * Strict Unified diff output builder. * * Generates (strict) Unified diff's (unidiffs) with hunks. */ final class StrictUnifiedDiffOutputBuilder implements DiffOutputBuilderInterface { private static array $default = [ 'collapseRanges' => true, // ranges of length one are rendered with the trailing `,1` 'commonLineThreshold' => 6, // number of same lines before ending a new hunk and creating a new one (if needed) 'contextLines' => 3, // like `diff: -u, -U NUM, --unified[=NUM]`, for patch/git apply compatibility best to keep at least @ 3 'fromFile' => null, 'fromFileDate' => null, 'toFile' => null, 'toFileDate' => null, ]; private bool $changed; private bool $collapseRanges; /** * @psalm-var positive-int */ private int $commonLineThreshold; private string $header; /** * @psalm-var positive-int */ private int $contextLines; public function __construct(array $options = []) { $options = array_merge(self::$default, $options); if (!is_bool($options['collapseRanges'])) { throw new ConfigurationException('collapseRanges', 'a bool', $options['collapseRanges']); } if (!is_int($options['contextLines']) || $options['contextLines'] < 0) { throw new ConfigurationException('contextLines', 'an int >= 0', $options['contextLines']); } if (!is_int($options['commonLineThreshold']) || $options['commonLineThreshold'] <= 0) { throw new ConfigurationException('commonLineThreshold', 'an int > 0', $options['commonLineThreshold']); } $this->assertString($options, 'fromFile'); $this->assertString($options, 'toFile'); $this->assertStringOrNull($options, 'fromFileDate'); $this->assertStringOrNull($options, 'toFileDate'); $this->header = sprintf( "--- %s%s\n+++ %s%s\n", $options['fromFile'], null === $options['fromFileDate'] ? '' : "\t" . $options['fromFileDate'], $options['toFile'], null === $options['toFileDate'] ? '' : "\t" . $options['toFileDate'] ); $this->collapseRanges = $options['collapseRanges']; $this->commonLineThreshold = $options['commonLineThreshold']; $this->contextLines = $options['contextLines']; } public function getDiff(array $diff): string { if (0 === count($diff)) { return ''; } $this->changed = false; $buffer = fopen('php://memory', 'r+b'); fwrite($buffer, $this->header); $this->writeDiffHunks($buffer, $diff); if (!$this->changed) { fclose($buffer); return ''; } $diff = stream_get_contents($buffer, -1, 0); fclose($buffer); // If the last char is not a linebreak: add it. // This might happen when both the `from` and `to` do not have a trailing linebreak $last = substr($diff, -1); return "\n" !== $last && "\r" !== $last ? $diff . "\n" : $diff; } private function writeDiffHunks($output, array $diff): void { // detect "No newline at end of file" and insert into `$diff` if needed $upperLimit = count($diff); if (0 === $diff[$upperLimit - 1][1]) { $lc = substr($diff[$upperLimit - 1][0], -1); if ("\n" !== $lc) { array_splice($diff, $upperLimit, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]); } } else { // search back for the last `+` and `-` line, // check if it has a trailing linebreak, else add a warning under it $toFind = [1 => true, 2 => true]; for ($i = $upperLimit - 1; $i >= 0; $i--) { if (isset($toFind[$diff[$i][1]])) { unset($toFind[$diff[$i][1]]); $lc = substr($diff[$i][0], -1); if ("\n" !== $lc) { array_splice($diff, $i + 1, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]); } if (!count($toFind)) { break; } } } } // write hunks to output buffer $cutOff = max($this->commonLineThreshold, $this->contextLines); $hunkCapture = false; $sameCount = $toRange = $fromRange = 0; $toStart = $fromStart = 1; $i = 0; /** @var int $i */ foreach ($diff as $i => $entry) { if (0 === $entry[1]) { // same if (false === $hunkCapture) { $fromStart++; $toStart++; continue; } $sameCount++; $toRange++; $fromRange++; if ($sameCount === $cutOff) { $contextStartOffset = ($hunkCapture - $this->contextLines) < 0 ? $hunkCapture : $this->contextLines; // note: $contextEndOffset = $this->contextLines; // // because we never go beyond the end of the diff. // with the cutoff/contextlines here the follow is never true; // // if ($i - $cutOff + $this->contextLines + 1 > \count($diff)) { // $contextEndOffset = count($diff) - 1; // } // // ; that would be true for a trailing incomplete hunk case which is dealt with after this loop $this->writeHunk( $diff, $hunkCapture - $contextStartOffset, $i - $cutOff + $this->contextLines + 1, $fromStart - $contextStartOffset, $fromRange - $cutOff + $contextStartOffset + $this->contextLines, $toStart - $contextStartOffset, $toRange - $cutOff + $contextStartOffset + $this->contextLines, $output ); $fromStart += $fromRange; $toStart += $toRange; $hunkCapture = false; $sameCount = $toRange = $fromRange = 0; } continue; } $sameCount = 0; if ($entry[1] === Differ::NO_LINE_END_EOF_WARNING) { continue; } $this->changed = true; if (false === $hunkCapture) { $hunkCapture = $i; } if (Differ::ADDED === $entry[1]) { // added $toRange++; } if (Differ::REMOVED === $entry[1]) { // removed $fromRange++; } } if (false === $hunkCapture) { return; } // we end here when cutoff (commonLineThreshold) was not reached, but we were capturing a hunk, // do not render hunk till end automatically because the number of context lines might be less than the commonLineThreshold $contextStartOffset = $hunkCapture - $this->contextLines < 0 ? $hunkCapture : $this->contextLines; // prevent trying to write out more common lines than there are in the diff _and_ // do not write more than configured through the context lines $contextEndOffset = min($sameCount, $this->contextLines); $fromRange -= $sameCount; $toRange -= $sameCount; $this->writeHunk( $diff, $hunkCapture - $contextStartOffset, $i - $sameCount + $contextEndOffset + 1, $fromStart - $contextStartOffset, $fromRange + $contextStartOffset + $contextEndOffset, $toStart - $contextStartOffset, $toRange + $contextStartOffset + $contextEndOffset, $output ); } private function writeHunk( array $diff, int $diffStartIndex, int $diffEndIndex, int $fromStart, int $fromRange, int $toStart, int $toRange, $output ): void { fwrite($output, '@@ -' . $fromStart); if (!$this->collapseRanges || 1 !== $fromRange) { fwrite($output, ',' . $fromRange); } fwrite($output, ' +' . $toStart); if (!$this->collapseRanges || 1 !== $toRange) { fwrite($output, ',' . $toRange); } fwrite($output, " @@\n"); for ($i = $diffStartIndex; $i < $diffEndIndex; $i++) { if ($diff[$i][1] === Differ::ADDED) { $this->changed = true; fwrite($output, '+' . $diff[$i][0]); } elseif ($diff[$i][1] === Differ::REMOVED) { $this->changed = true; fwrite($output, '-' . $diff[$i][0]); } elseif ($diff[$i][1] === Differ::OLD) { fwrite($output, ' ' . $diff[$i][0]); } elseif ($diff[$i][1] === Differ::NO_LINE_END_EOF_WARNING) { $this->changed = true; fwrite($output, $diff[$i][0]); } //} elseif ($diff[$i][1] === Differ::DIFF_LINE_END_WARNING) { // custom comment inserted by PHPUnit/diff package // skip //} else { // unknown/invalid //} } } private function assertString(array $options, string $option): void { if (!is_string($options[$option])) { throw new ConfigurationException($option, 'a string', $options[$option]); } } private function assertStringOrNull(array $options, string $option): void { if (null !== $options[$option] && !is_string($options[$option])) { throw new ConfigurationException($option, 'a string or <null>', $options[$option]); } } } diff/src/Output/DiffOutputBuilderInterface.php 0000644 00000001011 15111337760 0015472 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/diff. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Diff\Output; /** * Defines how an output builder should take a generated * diff array and return a string representation of that diff. */ interface DiffOutputBuilderInterface { public function getDiff(array $diff): string; } diff/src/Output/UnifiedDiffOutputBuilder.php 0000644 00000020323 15111337760 0015164 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/diff. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Diff\Output; use function array_splice; use function count; use function fclose; use function fopen; use function fwrite; 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; /** * Builds a diff string representation in unified diff format in chunks. */ final class UnifiedDiffOutputBuilder extends AbstractChunkOutputBuilder { private bool $collapseRanges = true; private int $commonLineThreshold = 6; /** * @psalm-var positive-int */ private int $contextLines = 3; private string $header; private bool $addLineNumbers; public function __construct(string $header = "--- Original\n+++ New\n", bool $addLineNumbers = false) { $this->header = $header; $this->addLineNumbers = $addLineNumbers; } public function getDiff(array $diff): string { $buffer = fopen('php://memory', 'r+b'); if ('' !== $this->header) { fwrite($buffer, $this->header); if (!str_ends_with($this->header, "\n")) { fwrite($buffer, "\n"); } } if (0 !== count($diff)) { $this->writeDiffHunks($buffer, $diff); } $diff = stream_get_contents($buffer, -1, 0); fclose($buffer); // If the diff is non-empty and last char is not a linebreak: add it. // 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 ? $diff . "\n" : $diff; } private function writeDiffHunks($output, array $diff): void { // detect "No newline at end of file" and insert into `$diff` if needed $upperLimit = count($diff); if (0 === $diff[$upperLimit - 1][1]) { $lc = substr($diff[$upperLimit - 1][0], -1); if ("\n" !== $lc) { array_splice($diff, $upperLimit, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]); } } else { // search back for the last `+` and `-` line, // check if it has trailing linebreak, else add a warning under it $toFind = [1 => true, 2 => true]; for ($i = $upperLimit - 1; $i >= 0; $i--) { if (isset($toFind[$diff[$i][1]])) { unset($toFind[$diff[$i][1]]); $lc = substr($diff[$i][0], -1); if ("\n" !== $lc) { array_splice($diff, $i + 1, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]); } if (!count($toFind)) { break; } } } } // write hunks to output buffer $cutOff = max($this->commonLineThreshold, $this->contextLines); $hunkCapture = false; $sameCount = $toRange = $fromRange = 0; $toStart = $fromStart = 1; $i = 0; /** @var int $i */ foreach ($diff as $i => $entry) { if (0 === $entry[1]) { // same if (false === $hunkCapture) { $fromStart++; $toStart++; continue; } $sameCount++; $toRange++; $fromRange++; if ($sameCount === $cutOff) { $contextStartOffset = ($hunkCapture - $this->contextLines) < 0 ? $hunkCapture : $this->contextLines; // note: $contextEndOffset = $this->contextLines; // // because we never go beyond the end of the diff. // with the cutoff/contextlines here the follow is never true; // // if ($i - $cutOff + $this->contextLines + 1 > \count($diff)) { // $contextEndOffset = count($diff) - 1; // } // // ; that would be true for a trailing incomplete hunk case which is dealt with after this loop $this->writeHunk( $diff, $hunkCapture - $contextStartOffset, $i - $cutOff + $this->contextLines + 1, $fromStart - $contextStartOffset, $fromRange - $cutOff + $contextStartOffset + $this->contextLines, $toStart - $contextStartOffset, $toRange - $cutOff + $contextStartOffset + $this->contextLines, $output ); $fromStart += $fromRange; $toStart += $toRange; $hunkCapture = false; $sameCount = $toRange = $fromRange = 0; } continue; } $sameCount = 0; if ($entry[1] === Differ::NO_LINE_END_EOF_WARNING) { continue; } if (false === $hunkCapture) { $hunkCapture = $i; } if (Differ::ADDED === $entry[1]) { $toRange++; } if (Differ::REMOVED === $entry[1]) { $fromRange++; } } if (false === $hunkCapture) { return; } // we end here when cutoff (commonLineThreshold) was not reached, but we were capturing a hunk, // do not render hunk till end automatically because the number of context lines might be less than the commonLineThreshold $contextStartOffset = $hunkCapture - $this->contextLines < 0 ? $hunkCapture : $this->contextLines; // prevent trying to write out more common lines than there are in the diff _and_ // do not write more than configured through the context lines $contextEndOffset = min($sameCount, $this->contextLines); $fromRange -= $sameCount; $toRange -= $sameCount; $this->writeHunk( $diff, $hunkCapture - $contextStartOffset, $i - $sameCount + $contextEndOffset + 1, $fromStart - $contextStartOffset, $fromRange + $contextStartOffset + $contextEndOffset, $toStart - $contextStartOffset, $toRange + $contextStartOffset + $contextEndOffset, $output ); } private function writeHunk( array $diff, int $diffStartIndex, int $diffEndIndex, int $fromStart, int $fromRange, int $toStart, int $toRange, $output ): void { if ($this->addLineNumbers) { fwrite($output, '@@ -' . $fromStart); if (!$this->collapseRanges || 1 !== $fromRange) { fwrite($output, ',' . $fromRange); } fwrite($output, ' +' . $toStart); if (!$this->collapseRanges || 1 !== $toRange) { fwrite($output, ',' . $toRange); } fwrite($output, " @@\n"); } else { fwrite($output, "@@ @@\n"); } for ($i = $diffStartIndex; $i < $diffEndIndex; $i++) { if ($diff[$i][1] === Differ::ADDED) { fwrite($output, '+' . $diff[$i][0]); } elseif ($diff[$i][1] === Differ::REMOVED) { fwrite($output, '-' . $diff[$i][0]); } elseif ($diff[$i][1] === Differ::OLD) { fwrite($output, ' ' . $diff[$i][0]); } elseif ($diff[$i][1] === Differ::NO_LINE_END_EOF_WARNING) { fwrite($output, "\n"); // $diff[$i][0] } else { /* Not changed (old) Differ::OLD or Warning Differ::DIFF_LINE_END_WARNING */ fwrite($output, ' ' . $diff[$i][0]); } } } } diff/src/Output/AbstractChunkOutputBuilder.php 0000644 00000003002 15111337760 0015537 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/diff. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Diff\Output; use function count; abstract class AbstractChunkOutputBuilder implements DiffOutputBuilderInterface { /** * Takes input of the diff array and returns the common parts. * Iterates through diff line by line. */ protected function getCommonChunks(array $diff, int $lineThreshold = 5): array { $diffSize = count($diff); $capturing = false; $chunkStart = 0; $chunkSize = 0; $commonChunks = []; for ($i = 0; $i < $diffSize; $i++) { if ($diff[$i][1] === 0 /* OLD */) { if ($capturing === false) { $capturing = true; $chunkStart = $i; $chunkSize = 0; } else { $chunkSize++; } } elseif ($capturing !== false) { if ($chunkSize >= $lineThreshold) { $commonChunks[$chunkStart] = $chunkStart + $chunkSize; } $capturing = false; } } if ($capturing !== false && $chunkSize >= $lineThreshold) { $commonChunks[$chunkStart] = $chunkStart + $chunkSize; } return $commonChunks; } } diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php 0000644 00000004500 15111337760 0020414 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/diff. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Diff; use function array_reverse; use function count; use function max; use SplFixedArray; final class TimeEfficientLongestCommonSubsequenceCalculator implements LongestCommonSubsequenceCalculator { /** * @inheritDoc */ public function calculate(array $from, array $to): array { $common = []; $fromLength = count($from); $toLength = count($to); $width = $fromLength + 1; $matrix = new SplFixedArray($width * ($toLength + 1)); for ($i = 0; $i <= $fromLength; $i++) { $matrix[$i] = 0; } for ($j = 0; $j <= $toLength; $j++) { $matrix[$j * $width] = 0; } for ($i = 1; $i <= $fromLength; $i++) { for ($j = 1; $j <= $toLength; $j++) { $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]; } } } } $i = $fromLength; $j = $toLength; while ($i > 0 && $j > 0) { if ($from[$i - 1] === $to[$j - 1]) { $common[] = $from[$i - 1]; $i--; $j--; } else { $o = ($j * $width) + $i; if ($matrix[$o - $width] > $matrix[$o - 1]) { $j--; } else { $i--; } } } return array_reverse($common); } } diff/src/Chunk.php 0000644 00000002757 15111337760 0010043 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/diff. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Diff; final class Chunk { private int $start; private int $startRange; private int $end; private int $endRange; private array $lines; public function __construct(int $start = 0, int $startRange = 1, int $end = 0, int $endRange = 1, array $lines = []) { $this->start = $start; $this->startRange = $startRange; $this->end = $end; $this->endRange = $endRange; $this->lines = $lines; } public function getStart(): int { return $this->start; } public function getStartRange(): int { return $this->startRange; } public function getEnd(): int { return $this->end; } public function getEndRange(): int { return $this->endRange; } /** * @psalm-return list<Line> */ public function getLines(): array { return $this->lines; } /** * @psalm-param list<Line> $lines */ public function setLines(array $lines): void { foreach ($lines as $line) { if (!$line instanceof Line) { throw new InvalidArgumentException; } } $this->lines = $lines; } } diff/src/Exception/Exception.php 0000644 00000000541 15111337760 0012654 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/diff. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Diff; use Throwable; interface Exception extends Throwable { } diff/src/Exception/ConfigurationException.php 0000644 00000001676 15111337760 0015416 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/diff. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Diff; use function gettype; use function is_object; use function sprintf; use Exception; final class ConfigurationException extends InvalidArgumentException { public function __construct( string $option, string $expected, $value, int $code = 0, 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) ), $code, $previous ); } } diff/src/Exception/InvalidArgumentException.php 0000644 00000000601 15111337760 0015663 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/diff. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Diff; class InvalidArgumentException extends \InvalidArgumentException implements Exception { } diff/src/Parser.php 0000644 00000005761 15111337760 0010225 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/diff. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Diff; use function array_pop; use function count; use function max; use function preg_match; use function preg_split; /** * Unified diff parser. */ final class Parser { /** * @return Diff[] */ public function parse(string $string): array { $lines = preg_split('(\r\n|\r|\n)', $string); if (!empty($lines) && $lines[count($lines) - 1] === '') { array_pop($lines); } $lineCount = count($lines); $diffs = []; $diff = null; $collected = []; for ($i = 0; $i < $lineCount; $i++) { if (preg_match('#^---\h+"?(?P<file>[^\\v\\t"]+)#', $lines[$i], $fromMatch) && preg_match('#^\\+\\+\\+\\h+"?(?P<file>[^\\v\\t"]+)#', $lines[$i + 1], $toMatch)) { if ($diff !== null) { $this->parseFileDiff($diff, $collected); $diffs[] = $diff; $collected = []; } $diff = new Diff($fromMatch['file'], $toMatch['file']); $i++; } else { if (preg_match('/^(?:diff --git |index [\da-f.]+|[+-]{3} [ab])/', $lines[$i])) { continue; } $collected[] = $lines[$i]; } } if ($diff !== null && count($collected)) { $this->parseFileDiff($diff, $collected); $diffs[] = $diff; } return $diffs; } private function parseFileDiff(Diff $diff, array $lines): void { $chunks = []; $chunk = null; $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, PREG_UNMATCHED_AS_NULL)) { $chunk = new Chunk( (int) $match['start'], isset($match['startrange']) ? max(0, (int) $match['startrange']) : 1, (int) $match['end'], isset($match['endrange']) ? max(0, (int) $match['endrange']) : 1 ); $chunks[] = $chunk; $diffLines = []; continue; } if (preg_match('/^(?P<type>[+ -])?(?P<line>.*)/', $line, $match)) { $type = Line::UNCHANGED; if ($match['type'] === '+') { $type = Line::ADDED; } elseif ($match['type'] === '-') { $type = Line::REMOVED; } $diffLines[] = new Line($type, $match['line']); $chunk?->setLines($diffLines); } } $diff->setChunks($chunks); } } diff/src/error_log 0000644 00000017471 15111337760 0010176 0 ustar 00 [18-Nov-2025 17:52:40 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\Diff\LongestCommonSubsequenceCalculator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php on line 17 [18-Nov-2025 18:37:29 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\Diff\LongestCommonSubsequenceCalculator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php on line 20 [19-Nov-2025 01:57:24 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\Diff\LongestCommonSubsequenceCalculator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php on line 17 [19-Nov-2025 02:34:41 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\Diff\LongestCommonSubsequenceCalculator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php on line 20 [20-Nov-2025 07:27:37 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\Diff\LongestCommonSubsequenceCalculator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php on line 17 [20-Nov-2025 07:37:58 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\Diff\LongestCommonSubsequenceCalculator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php on line 20 [20-Nov-2025 08:24:00 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\Diff\LongestCommonSubsequenceCalculator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php on line 20 [20-Nov-2025 08:27:08 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\Diff\LongestCommonSubsequenceCalculator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php on line 17 [20-Nov-2025 09:00:55 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\Diff\LongestCommonSubsequenceCalculator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php on line 17 [20-Nov-2025 10:09:23 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\Diff\LongestCommonSubsequenceCalculator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php on line 17 [20-Nov-2025 10:29:52 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\Diff\LongestCommonSubsequenceCalculator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php on line 17 [20-Nov-2025 12:22:47 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\Diff\LongestCommonSubsequenceCalculator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php on line 20 [20-Nov-2025 12:23:48 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\Diff\LongestCommonSubsequenceCalculator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php on line 17 [20-Nov-2025 13:39:34 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\Diff\LongestCommonSubsequenceCalculator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php on line 17 [20-Nov-2025 13:47:53 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\Diff\LongestCommonSubsequenceCalculator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php on line 20 [20-Nov-2025 14:19:58 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\Diff\LongestCommonSubsequenceCalculator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php on line 17 [20-Nov-2025 14:23:09 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\Diff\LongestCommonSubsequenceCalculator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php on line 20 [25-Nov-2025 02:56:39 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\Diff\LongestCommonSubsequenceCalculator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php on line 20 [25-Nov-2025 03:32:23 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\Diff\LongestCommonSubsequenceCalculator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php on line 17 diff/src/Line.php 0000644 00000001424 15111337760 0007650 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/diff. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Diff; final class Line { public const ADDED = 1; public const REMOVED = 2; public const UNCHANGED = 3; private int $type; private string $content; public function __construct(int $type = self::UNCHANGED, string $content = '') { $this->type = $type; $this->content = $content; } public function getContent(): string { return $this->content; } public function getType(): int { return $this->type; } } diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php 0000644 00000004707 15111337760 0020777 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/diff. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Diff; use function array_fill; use function array_merge; use function array_reverse; use function array_slice; use function count; use function in_array; use function max; final class MemoryEfficientLongestCommonSubsequenceCalculator implements LongestCommonSubsequenceCalculator { /** * @inheritDoc */ public function calculate(array $from, array $to): array { $cFrom = count($from); $cTo = count($to); if ($cFrom === 0) { return []; } if ($cFrom === 1) { if (in_array($from[0], $to, true)) { return [$from[0]]; } return []; } $i = (int) ($cFrom / 2); $fromStart = array_slice($from, 0, $i); $fromEnd = array_slice($from, $i); $llB = $this->length($fromStart, $to); $llE = $this->length(array_reverse($fromEnd), array_reverse($to)); $jMax = 0; $max = 0; for ($j = 0; $j <= $cTo; $j++) { $m = $llB[$j] + $llE[$cTo - $j]; if ($m >= $max) { $max = $m; $jMax = $j; } } $toStart = array_slice($to, 0, $jMax); $toEnd = array_slice($to, $jMax); return array_merge( $this->calculate($fromStart, $toStart), $this->calculate($fromEnd, $toEnd) ); } private function length(array $from, array $to): array { $current = array_fill(0, count($to) + 1, 0); $cFrom = count($from); $cTo = count($to); for ($i = 0; $i < $cFrom; $i++) { $prev = $current; for ($j = 0; $j < $cTo; $j++) { if ($from[$i] === $to[$j]) { $current[$j + 1] = $prev[$j] + 1; } else { // don't use max() to avoid function call overhead if ($current[$j] > $prev[$j + 1]) { $current[$j + 1] = $current[$j]; } else { $current[$j + 1] = $prev[$j + 1]; } } } } return $current; } } diff/README.md 0000644 00000020170 15111337760 0006737 0 ustar 00 [](https://packagist.org/packages/sebastian/diff) [](https://github.com/sebastianbergmann/diff/actions) [](https://shepherd.dev/github/sebastianbergmann/diff) [](https://codecov.io/gh/sebastianbergmann/diff) # sebastian/diff Diff implementation for PHP, factored out of PHPUnit into a stand-alone component. ## Installation You can add this library as a local, per-project dependency to your project using [Composer](https://getcomposer.org/): ``` composer require sebastian/diff ``` If you only need this library during development, for instance to run your project's test suite, then you should add it as a development-time dependency: ``` composer require --dev sebastian/diff ``` ### Usage #### Generating diff The `Differ` class can be used to generate a textual representation of the difference between two strings: ```php <?php use SebastianBergmann\Diff\Differ; $differ = new Differ; print $differ->diff('foo', 'bar'); ``` The code above yields the output below: ```diff --- Original +++ New @@ @@ -foo +bar ``` There are three output builders available in this package: #### UnifiedDiffOutputBuilder This is default builder, which generates the output close to udiff and is used by PHPUnit. ```php <?php use SebastianBergmann\Diff\Differ; use SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder; $builder = new UnifiedDiffOutputBuilder( "--- Original\n+++ New\n", // custom header false // do not add line numbers to the diff ); $differ = new Differ($builder); print $differ->diff('foo', 'bar'); ``` #### StrictUnifiedDiffOutputBuilder Generates (strict) Unified diff's (unidiffs) with hunks, similar to `diff -u` and compatible with `patch` and `git apply`. ```php <?php use SebastianBergmann\Diff\Differ; use SebastianBergmann\Diff\Output\StrictUnifiedDiffOutputBuilder; $builder = new StrictUnifiedDiffOutputBuilder([ 'collapseRanges' => true, // ranges of length one are rendered with the trailing `,1` 'commonLineThreshold' => 6, // number of same lines before ending a new hunk and creating a new one (if needed) 'contextLines' => 3, // like `diff: -u, -U NUM, --unified[=NUM]`, for patch/git apply compatibility best to keep at least @ 3 'fromFile' => '', 'fromFileDate' => null, 'toFile' => '', 'toFileDate' => null, ]); $differ = new Differ($builder); print $differ->diff('foo', 'bar'); ``` #### DiffOnlyOutputBuilder Output only the lines that differ. ```php <?php use SebastianBergmann\Diff\Differ; use SebastianBergmann\Diff\Output\DiffOnlyOutputBuilder; $builder = new DiffOnlyOutputBuilder( "--- Original\n+++ New\n" ); $differ = new Differ($builder); print $differ->diff('foo', 'bar'); ``` #### DiffOutputBuilderInterface You can pass any output builder to the `Differ` class as longs as it implements the `DiffOutputBuilderInterface`. #### Parsing diff The `Parser` class can be used to parse a unified diff into an object graph: ```php use SebastianBergmann\Diff\Parser; use SebastianBergmann\Git; $git = new Git('/usr/local/src/money'); $diff = $git->getDiff( '948a1a07768d8edd10dcefa8315c1cbeffb31833', 'c07a373d2399f3e686234c4f7f088d635eb9641b' ); $parser = new Parser; print_r($parser->parse($diff)); ``` The code above yields the output below: Array ( [0] => SebastianBergmann\Diff\Diff Object ( [from:SebastianBergmann\Diff\Diff:private] => a/tests/MoneyTest.php [to:SebastianBergmann\Diff\Diff:private] => b/tests/MoneyTest.php [chunks:SebastianBergmann\Diff\Diff:private] => Array ( [0] => SebastianBergmann\Diff\Chunk Object ( [start:SebastianBergmann\Diff\Chunk:private] => 87 [startRange:SebastianBergmann\Diff\Chunk:private] => 7 [end:SebastianBergmann\Diff\Chunk:private] => 87 [endRange:SebastianBergmann\Diff\Chunk:private] => 7 [lines:SebastianBergmann\Diff\Chunk:private] => Array ( [0] => SebastianBergmann\Diff\Line Object ( [type:SebastianBergmann\Diff\Line:private] => 3 [content:SebastianBergmann\Diff\Line:private] => * @covers SebastianBergmann\Money\Money::add ) [1] => SebastianBergmann\Diff\Line Object ( [type:SebastianBergmann\Diff\Line:private] => 3 [content:SebastianBergmann\Diff\Line:private] => * @covers SebastianBergmann\Money\Money::newMoney ) [2] => SebastianBergmann\Diff\Line Object ( [type:SebastianBergmann\Diff\Line:private] => 3 [content:SebastianBergmann\Diff\Line:private] => */ ) [3] => SebastianBergmann\Diff\Line Object ( [type:SebastianBergmann\Diff\Line:private] => 2 [content:SebastianBergmann\Diff\Line:private] => public function testAnotherMoneyWithSameCurrencyObjectCanBeAdded() ) [4] => SebastianBergmann\Diff\Line Object ( [type:SebastianBergmann\Diff\Line:private] => 1 [content:SebastianBergmann\Diff\Line:private] => public function testAnotherMoneyObjectWithSameCurrencyCanBeAdded() ) [5] => SebastianBergmann\Diff\Line Object ( [type:SebastianBergmann\Diff\Line:private] => 3 [content:SebastianBergmann\Diff\Line:private] => { ) [6] => SebastianBergmann\Diff\Line Object ( [type:SebastianBergmann\Diff\Line:private] => 3 [content:SebastianBergmann\Diff\Line:private] => $a = new Money(1, new Currency('EUR')); ) [7] => SebastianBergmann\Diff\Line Object ( [type:SebastianBergmann\Diff\Line:private] => 3 [content:SebastianBergmann\Diff\Line:private] => $b = new Money(2, new Currency('EUR')); ) ) ) ) ) ) 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. diff/LICENSE 0000644 00000002773 15111337760 0006476 0 ustar 00 BSD 3-Clause License Copyright (c) 2002-2023, Sebastian Bergmann All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff/ChangeLog.md 0000644 00000006705 15111337760 0007641 0 ustar 00 # ChangeLog All notable changes are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles. ## [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 * Passing a `DiffOutputBuilderInterface` instance to `Differ::__construct()` is no longer optional ### Removed * Removed support for PHP 7.3, PHP 7.4, and PHP 8.0 ## [4.0.4] - 2020-10-26 ### Fixed * `SebastianBergmann\Diff\Exception` now correctly extends `\Throwable` ## [4.0.3] - 2020-09-28 ### Changed * Changed PHP version constraint in `composer.json` from `^7.3 || ^8.0` to `>=7.3` ## [4.0.2] - 2020-06-30 ### Added * This component is now supported on PHP 8 ## [4.0.1] - 2020-05-08 ### Fixed * [#99](https://github.com/sebastianbergmann/diff/pull/99): Regression in unified diff output of identical strings ## [4.0.0] - 2020-02-07 ### Removed * Removed support for PHP 7.1 and PHP 7.2 ## [3.0.2] - 2019-02-04 ### Changed * `Chunk::setLines()` now ensures that the `$lines` array only contains `Line` objects ## [3.0.1] - 2018-06-10 ### Fixed * Removed `"minimum-stability": "dev",` from `composer.json` ## [3.0.0] - 2018-02-01 * The `StrictUnifiedDiffOutputBuilder` implementation of the `DiffOutputBuilderInterface` was added ### Changed * The default `DiffOutputBuilderInterface` implementation now generates context lines (unchanged lines) ### Removed * Removed support for PHP 7.0 ### Fixed * [#70](https://github.com/sebastianbergmann/diff/issues/70): Diffing of arrays no longer works ## [2.0.1] - 2017-08-03 ### Fixed * [#66](https://github.com/sebastianbergmann/diff/pull/66): Restored backwards compatibility for PHPUnit 6.1.4, 6.2.0, 6.2.1, 6.2.2, and 6.2.3 ## [2.0.0] - 2017-07-11 [YANKED] ### Added * [#64](https://github.com/sebastianbergmann/diff/pull/64): Show line numbers for chunks of a diff ### Removed * This component is no longer supported on PHP 5.6 [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 [4.0.2]: https://github.com/sebastianbergmann/diff/compare/4.0.1...4.0.2 [4.0.1]: https://github.com/sebastianbergmann/diff/compare/4.0.0...4.0.1 [4.0.0]: https://github.com/sebastianbergmann/diff/compare/3.0.2...4.0.0 [3.0.2]: https://github.com/sebastianbergmann/diff/compare/3.0.1...3.0.2 [3.0.1]: https://github.com/sebastianbergmann/diff/compare/3.0.0...3.0.1 [3.0.0]: https://github.com/sebastianbergmann/diff/compare/2.0...3.0.0 [2.0.1]: https://github.com/sebastianbergmann/diff/compare/c341c98ce083db77f896a0aa64f5ee7652915970...2.0.1 [2.0.0]: https://github.com/sebastianbergmann/diff/compare/1.4...c341c98ce083db77f896a0aa64f5ee7652915970 diff/composer.json 0000644 00000002276 15111337760 0010211 0 ustar 00 { "name": "sebastian/diff", "description": "Diff implementation", "keywords": ["diff", "udiff", "unidiff", "unified diff"], "homepage": "https://github.com/sebastianbergmann/diff", "license": "BSD-3-Clause", "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" }, { "name": "Kore Nordmann", "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": { "php": "8.1.0" }, "optimize-autoloader": true, "sort-packages": true }, "require": { "php": ">=8.1" }, "require-dev": { "phpunit/phpunit": "^10.0", "symfony/process": "^4.2 || ^5" }, "autoload": { "classmap": [ "src/" ] }, "autoload-dev": { "classmap": [ "tests/" ] }, "extra": { "branch-alias": { "dev-main": "5.0-dev" } } } diff/SECURITY.md 0000644 00000003565 15111337760 0007262 0 ustar 00 # Security Policy 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. **Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.** 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. comparator/src/exceptions/Exception.php 0000644 00000000555 15111337760 0014343 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/comparator. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Comparator; use Throwable; interface Exception extends Throwable { } comparator/src/exceptions/RuntimeException.php 0000644 00000000603 15111337760 0015701 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/comparator. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Comparator; final class RuntimeException extends \RuntimeException implements Exception { } comparator/src/exceptions/error_log 0000644 00000001350 15111337760 0013603 0 ustar 00 [20-Nov-2025 01:24:01 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\Comparator\Exception" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/exceptions/RuntimeException.php:12 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/exceptions/RuntimeException.php on line 12 [20-Nov-2025 05:27:55 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\Comparator\Exception" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/exceptions/RuntimeException.php:12 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/exceptions/RuntimeException.php on line 12 comparator/src/ScalarComparator.php 0000644 00000005411 15111337760 0013455 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/comparator. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Comparator; use function is_bool; use function is_object; use function is_scalar; use function is_string; use function mb_strtolower; use function method_exists; use function sprintf; use SebastianBergmann\Exporter\Exporter; /** * Compares scalar or NULL values for equality. */ class ScalarComparator extends Comparator { public function accepts(mixed $expected, mixed $actual): bool { return ((is_scalar($expected) xor null === $expected) && (is_scalar($actual) xor null === $actual)) || // allow comparison between strings and objects featuring __toString() (is_string($expected) && is_object($actual) && method_exists($actual, '__toString')) || (is_object($expected) && method_exists($expected, '__toString') && is_string($actual)); } /** * @throws ComparisonFailure */ public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = false, bool $ignoreCase = false): void { $expectedToCompare = $expected; $actualToCompare = $actual; $exporter = new Exporter; // 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; if ($ignoreCase) { $expectedToCompare = mb_strtolower($expectedToCompare, 'UTF-8'); $actualToCompare = mb_strtolower($actualToCompare, 'UTF-8'); } } if ($expectedToCompare !== $actualToCompare && is_string($expected) && is_string($actual)) { throw new ComparisonFailure( $expected, $actual, $exporter->export($expected), $exporter->export($actual), 'Failed asserting that two strings are equal.' ); } if ($expectedToCompare != $actualToCompare) { throw new ComparisonFailure( $expected, $actual, // no diff is required '', '', sprintf( 'Failed asserting that %s matches expected %s.', $exporter->export($actual), $exporter->export($expected) ) ); } } } comparator/src/NumericComparator.php 0000644 00000003675 15111337760 0013664 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/comparator. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Comparator; use function abs; use function is_float; use function is_infinite; use function is_nan; use function is_numeric; use function is_string; use function sprintf; use SebastianBergmann\Exporter\Exporter; final class NumericComparator extends ScalarComparator { public function accepts(mixed $expected, mixed $actual): bool { // all numerical values, but not if both of them are strings return is_numeric($expected) && is_numeric($actual) && !(is_string($expected) && is_string($actual)); } /** * @throws ComparisonFailure */ public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = false, bool $ignoreCase = false): void { if ($this->isInfinite($actual) && $this->isInfinite($expected)) { return; } if (($this->isInfinite($actual) xor $this->isInfinite($expected)) || ($this->isNan($actual) || $this->isNan($expected)) || abs($actual - $expected) > $delta) { $exporter = new Exporter; throw new ComparisonFailure( $expected, $actual, '', '', sprintf( 'Failed asserting that %s matches expected %s.', $exporter->export($actual), $exporter->export($expected) ) ); } } private function isInfinite(mixed $value): bool { return is_float($value) && is_infinite($value); } private function isNan(mixed $value): bool { return is_float($value) && is_nan($value); } } comparator/src/ComparisonFailure.php 0000644 00000003402 15111337760 0013640 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/comparator. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Comparator; use RuntimeException; use SebastianBergmann\Diff\Differ; use SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder; final class ComparisonFailure extends RuntimeException { private mixed $expected; private mixed $actual; private string $expectedAsString; private string $actualAsString; public function __construct(mixed $expected, mixed $actual, string $expectedAsString, string $actualAsString, string $message = '') { parent::__construct($message); $this->expected = $expected; $this->actual = $actual; $this->expectedAsString = $expectedAsString; $this->actualAsString = $actualAsString; } public function getActual(): mixed { return $this->actual; } public function getExpected(): mixed { return $this->expected; } public function getActualAsString(): string { return $this->actualAsString; } public function getExpectedAsString(): string { return $this->expectedAsString; } public function getDiff(): string { if (!$this->actualAsString && !$this->expectedAsString) { return ''; } $differ = new Differ(new UnifiedDiffOutputBuilder("\n--- Expected\n+++ Actual\n")); return $differ->diff($this->expectedAsString, $this->actualAsString); } public function toString(): string { return $this->getMessage() . $this->getDiff(); } } comparator/src/Comparator.php 0000644 00000001506 15111337760 0012330 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/comparator. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Comparator; abstract class Comparator { private Factory $factory; public function setFactory(Factory $factory): void { $this->factory = $factory; } abstract public function accepts(mixed $expected, mixed $actual): bool; /** * @throws ComparisonFailure */ abstract public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = false, bool $ignoreCase = false): void; protected function factory(): Factory { return $this->factory; } } comparator/src/MockObjectComparator.php 0000644 00000002070 15111337760 0014266 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/comparator. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Comparator; use function array_keys; use function assert; use function str_starts_with; use PHPUnit\Framework\MockObject\Stub; /** * Compares PHPUnit\Framework\MockObject\MockObject instances for equality. */ final class MockObjectComparator extends ObjectComparator { public function accepts(mixed $expected, mixed $actual): bool { return $expected instanceof Stub && $actual instanceof Stub; } protected function toArray(object $object): array { assert($object instanceof Stub); $array = parent::toArray($object); foreach (array_keys($array) as $key) { if (!str_starts_with($key, '__phpunit_')) { continue; } unset($array[$key]); } return $array; } } comparator/src/DateTimeComparator.php 0000644 00000004407 15111337760 0013750 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/comparator. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Comparator; use function abs; use function assert; use function floor; use function sprintf; use DateInterval; use DateTimeInterface; use DateTimeZone; final class DateTimeComparator extends ObjectComparator { public function accepts(mixed $expected, mixed $actual): bool { return ($expected instanceof DateTimeInterface) && ($actual instanceof DateTimeInterface); } /** * @throws ComparisonFailure */ public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = false, bool $ignoreCase = false, array &$processed = []): void { assert($expected instanceof DateTimeInterface); assert($actual instanceof DateTimeInterface); $absDelta = abs($delta); $delta = new DateInterval(sprintf('PT%dS', $absDelta)); $delta->f = $absDelta - floor($absDelta); $actualClone = (clone $actual) ->setTimezone(new DateTimeZone('UTC')); $expectedLower = (clone $expected) ->setTimezone(new DateTimeZone('UTC')) ->sub($delta); $expectedUpper = (clone $expected) ->setTimezone(new DateTimeZone('UTC')) ->add($delta); if ($actualClone < $expectedLower || $actualClone > $expectedUpper) { throw new ComparisonFailure( $expected, $actual, $this->dateTimeToString($expected), $this->dateTimeToString($actual), 'Failed asserting that two DateTime objects are equal.' ); } } /** * Returns an ISO 8601 formatted string representation of a datetime or * 'Invalid DateTimeInterface object' if the provided DateTimeInterface was not properly * initialized. */ private function dateTimeToString(DateTimeInterface $datetime): string { $string = $datetime->format('Y-m-d\TH:i:s.uO'); return $string ?: 'Invalid DateTimeInterface object'; } } comparator/src/ObjectComparator.php 0000644 00000005501 15111337760 0013456 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/comparator. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Comparator; use function assert; use function in_array; use function is_object; use function sprintf; use function substr_replace; use SebastianBergmann\Exporter\Exporter; class ObjectComparator extends ArrayComparator { public function accepts(mixed $expected, mixed $actual): bool { return is_object($expected) && is_object($actual); } /** * @throws ComparisonFailure */ public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = false, bool $ignoreCase = false, array &$processed = []): void { assert(is_object($expected)); assert(is_object($actual)); if ($actual::class !== $expected::class) { $exporter = new Exporter; throw new ComparisonFailure( $expected, $actual, $exporter->export($expected), $exporter->export($actual), sprintf( '%s is not instance of expected class "%s".', $exporter->export($actual), $expected::class ) ); } // don't compare twice to allow for cyclic dependencies if (in_array([$actual, $expected], $processed, true) || in_array([$expected, $actual], $processed, true)) { return; } $processed[] = [$actual, $expected]; // don't compare objects if they are identical // this helps to avoid the error "maximum function nesting level reached" // CAUTION: this conditional clause is not tested if ($actual !== $expected) { try { parent::assertEquals( $this->toArray($expected), $this->toArray($actual), $delta, $canonicalize, $ignoreCase, $processed ); } catch (ComparisonFailure $e) { throw new ComparisonFailure( $expected, $actual, // 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.' ); } } } protected function toArray(object $object): array { return (new Exporter)->toArray($object); } } comparator/src/ArrayComparator.php 0000644 00000007463 15111337760 0013337 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/comparator. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Comparator; use function array_key_exists; use function assert; use function is_array; use function sort; use function sprintf; use function str_replace; use function trim; use SebastianBergmann\Exporter\Exporter; /** * Arrays are equal if they contain the same key-value pairs. * The order of the keys does not matter. * The types of key-value pairs do not matter. */ class ArrayComparator extends Comparator { public function accepts(mixed $expected, mixed $actual): bool { return is_array($expected) && is_array($actual); } /** * @throws ComparisonFailure */ public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = false, bool $ignoreCase = false, array &$processed = []): void { assert(is_array($expected)); assert(is_array($actual)); if ($canonicalize) { sort($expected); sort($actual); } $remaining = $actual; $actualAsString = "Array (\n"; $expectedAsString = "Array (\n"; $equal = true; $exporter = new Exporter; foreach ($expected as $key => $value) { unset($remaining[$key]); if (!array_key_exists($key, $actual)) { $expectedAsString .= sprintf( " %s => %s\n", $exporter->export($key), $exporter->shortenedExport($value) ); $equal = false; continue; } try { $comparator = $this->factory()->getComparatorFor($value, $actual[$key]); $comparator->assertEquals($value, $actual[$key], $delta, $canonicalize, $ignoreCase, $processed); $expectedAsString .= sprintf( " %s => %s\n", $exporter->export($key), $exporter->shortenedExport($value) ); $actualAsString .= sprintf( " %s => %s\n", $exporter->export($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()) ); $actualAsString .= sprintf( " %s => %s\n", $exporter->export($key), $e->getActualAsString() ? $this->indent($e->getActualAsString()) : $exporter->shortenedExport($e->getActual()) ); $equal = false; } } foreach ($remaining as $key => $value) { $actualAsString .= sprintf( " %s => %s\n", $exporter->export($key), $exporter->shortenedExport($value) ); $equal = false; } $expectedAsString .= ')'; $actualAsString .= ')'; if (!$equal) { throw new ComparisonFailure( $expected, $actual, $expectedAsString, $actualAsString, 'Failed asserting that two arrays are equal.' ); } } private function indent(string $lines): string { return trim(str_replace("\n", "\n ", $lines)); } } comparator/src/Factory.php 0000644 00000006530 15111337760 0011632 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/comparator. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Comparator; use function array_unshift; final class Factory { private static ?Factory $instance = null; /** * @psalm-var list<Comparator> */ private array $customComparators = []; /** * @psalm-var list<Comparator> */ private array $defaultComparators = []; public static function getInstance(): self { if (self::$instance === null) { self::$instance = new self; // @codeCoverageIgnore } return self::$instance; } public function __construct() { $this->registerDefaultComparators(); } public function getComparatorFor(mixed $expected, mixed $actual): Comparator { foreach ($this->customComparators as $comparator) { if ($comparator->accepts($expected, $actual)) { return $comparator; } } foreach ($this->defaultComparators as $comparator) { if ($comparator->accepts($expected, $actual)) { return $comparator; } } throw new RuntimeException('No suitable Comparator implementation found'); } /** * Registers a new comparator. * * This comparator will be returned by getComparatorFor() if its accept() method * returns TRUE for the compared values. It has higher priority than the * existing comparators, meaning that its accept() method will be invoked * before those of the other comparators. */ public function register(Comparator $comparator): void { array_unshift($this->customComparators, $comparator); $comparator->setFactory($this); } /** * Unregisters a comparator. * * This comparator will no longer be considered by getComparatorFor(). */ public function unregister(Comparator $comparator): void { foreach ($this->customComparators as $key => $_comparator) { if ($comparator === $_comparator) { unset($this->customComparators[$key]); } } } public function reset(): void { $this->customComparators = []; } private function registerDefaultComparators(): void { $this->registerDefaultComparator(new MockObjectComparator); $this->registerDefaultComparator(new DateTimeComparator); $this->registerDefaultComparator(new DOMNodeComparator); $this->registerDefaultComparator(new SplObjectStorageComparator); $this->registerDefaultComparator(new ExceptionComparator); $this->registerDefaultComparator(new ObjectComparator); $this->registerDefaultComparator(new ResourceComparator); $this->registerDefaultComparator(new ArrayComparator); $this->registerDefaultComparator(new NumericComparator); $this->registerDefaultComparator(new ScalarComparator); $this->registerDefaultComparator(new TypeComparator); } private function registerDefaultComparator(Comparator $comparator): void { $this->defaultComparators[] = $comparator; $comparator->setFactory($this); } } comparator/src/error_log 0000644 00000026105 15111337760 0011427 0 ustar 00 [18-Nov-2025 12:42:36 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\ScalarComparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/NumericComparator.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/NumericComparator.php on line 21 [18-Nov-2025 12:43:06 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\ArrayComparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ObjectComparator.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ObjectComparator.php on line 19 [18-Nov-2025 12:44:12 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\Comparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ResourceComparator.php:16 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ResourceComparator.php on line 16 [18-Nov-2025 12:46:15 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\ObjectComparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ExceptionComparator.php:18 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ExceptionComparator.php on line 18 [18-Nov-2025 12:48:17 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\Comparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ArrayComparator.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ArrayComparator.php on line 26 [18-Nov-2025 12:53:32 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\ObjectComparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/DateTimeComparator.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/DateTimeComparator.php on line 20 [18-Nov-2025 12:56:09 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\ObjectComparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/MockObjectComparator.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/MockObjectComparator.php on line 20 [18-Nov-2025 12:56:58 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\ObjectComparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/DOMNodeComparator.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/DOMNodeComparator.php on line 19 [18-Nov-2025 12:59:02 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\Comparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ScalarComparator.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ScalarComparator.php on line 24 [18-Nov-2025 13:36:02 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\Comparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/SplObjectStorageComparator.php:16 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/SplObjectStorageComparator.php on line 16 [18-Nov-2025 22:00:51 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\ObjectComparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ExceptionComparator.php:18 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ExceptionComparator.php on line 18 [18-Nov-2025 22:01:00 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\Comparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ResourceComparator.php:16 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ResourceComparator.php on line 16 [18-Nov-2025 22:01:25 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\Comparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ArrayComparator.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ArrayComparator.php on line 26 [18-Nov-2025 22:03:36 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\ArrayComparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ObjectComparator.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ObjectComparator.php on line 19 [18-Nov-2025 22:04:32 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\ScalarComparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/NumericComparator.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/NumericComparator.php on line 21 [18-Nov-2025 22:07:36 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\ObjectComparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/DateTimeComparator.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/DateTimeComparator.php on line 20 [18-Nov-2025 22:09:34 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\Comparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ScalarComparator.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ScalarComparator.php on line 24 [18-Nov-2025 22:10:33 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\ObjectComparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/DOMNodeComparator.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/DOMNodeComparator.php on line 19 [18-Nov-2025 22:13:45 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\ObjectComparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/MockObjectComparator.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/MockObjectComparator.php on line 20 [18-Nov-2025 22:39:36 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\Comparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/TypeComparator.php:16 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/TypeComparator.php on line 16 [18-Nov-2025 22:51:09 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\Comparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/SplObjectStorageComparator.php:16 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/SplObjectStorageComparator.php on line 16 [25-Nov-2025 02:30:08 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\ScalarComparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/NumericComparator.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/NumericComparator.php on line 21 [25-Nov-2025 02:31:23 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\Comparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/TypeComparator.php:16 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/TypeComparator.php on line 16 [25-Nov-2025 02:59:24 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\Comparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ScalarComparator.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ScalarComparator.php on line 24 [25-Nov-2025 03:00:12 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\Comparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/SplObjectStorageComparator.php:16 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/SplObjectStorageComparator.php on line 16 [25-Nov-2025 03:00:25 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\ObjectComparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/DOMNodeComparator.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/DOMNodeComparator.php on line 19 [25-Nov-2025 03:02:23 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\ObjectComparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ExceptionComparator.php:18 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ExceptionComparator.php on line 18 [25-Nov-2025 03:03:16 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\ArrayComparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ObjectComparator.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ObjectComparator.php on line 19 [25-Nov-2025 03:04:47 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\ObjectComparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/MockObjectComparator.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/MockObjectComparator.php on line 20 [25-Nov-2025 03:31:20 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\Comparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ArrayComparator.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ArrayComparator.php on line 26 [25-Nov-2025 05:25:14 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\ObjectComparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/DateTimeComparator.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/DateTimeComparator.php on line 20 [25-Nov-2025 05:26:02 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\Comparator\Comparator" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ResourceComparator.php:16 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/comparator/src/ResourceComparator.php on line 16 comparator/src/TypeComparator.php 0000644 00000002266 15111337760 0013176 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/comparator. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Comparator; use function gettype; use function sprintf; use SebastianBergmann\Exporter\Exporter; final class TypeComparator extends Comparator { public function accepts(mixed $expected, mixed $actual): bool { return true; } /** * @throws ComparisonFailure */ public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = false, bool $ignoreCase = false): void { if (gettype($expected) != gettype($actual)) { throw new ComparisonFailure( $expected, $actual, // we don't need a diff '', '', sprintf( '%s does not match expected type "%s".', (new Exporter)->shortenedExport($actual), gettype($expected) ) ); } } } comparator/src/SplObjectStorageComparator.php 0000644 00000003363 15111337760 0015466 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/comparator. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Comparator; use function assert; use SebastianBergmann\Exporter\Exporter; use SplObjectStorage; final class SplObjectStorageComparator extends Comparator { public function accepts(mixed $expected, mixed $actual): bool { return $expected instanceof SplObjectStorage && $actual instanceof SplObjectStorage; } /** * @throws ComparisonFailure */ public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = false, bool $ignoreCase = false): void { assert($expected instanceof SplObjectStorage); assert($actual instanceof SplObjectStorage); $exporter = new Exporter; foreach ($actual as $object) { if (!$expected->contains($object)) { throw new ComparisonFailure( $expected, $actual, $exporter->export($expected), $exporter->export($actual), 'Failed asserting that two objects are equal.' ); } } foreach ($expected as $object) { if (!$actual->contains($object)) { throw new ComparisonFailure( $expected, $actual, $exporter->export($expected), $exporter->export($actual), 'Failed asserting that two objects are equal.' ); } } } } comparator/src/ExceptionComparator.php 0000644 00000001720 15111337760 0014205 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/comparator. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Comparator; use function assert; use Exception; /** * Compares Exception instances for equality. */ final class ExceptionComparator extends ObjectComparator { public function accepts(mixed $expected, mixed $actual): bool { return $expected instanceof Exception && $actual instanceof Exception; } protected function toArray(object $object): array { assert($object instanceof Exception); $array = parent::toArray($object); unset( $array['file'], $array['line'], $array['trace'], $array['string'], $array['xdebug_message'] ); return $array; } } comparator/src/ResourceComparator.php 0000644 00000002203 15111337760 0014033 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/comparator. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Comparator; use function assert; use function is_resource; use SebastianBergmann\Exporter\Exporter; final class ResourceComparator extends Comparator { public function accepts(mixed $expected, mixed $actual): bool { return is_resource($expected) && is_resource($actual); } /** * @throws ComparisonFailure */ public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = false, bool $ignoreCase = false): void { assert(is_resource($expected)); assert(is_resource($actual)); $exporter = new Exporter; if ($actual != $expected) { throw new ComparisonFailure( $expected, $actual, $exporter->export($expected), $exporter->export($actual) ); } } } comparator/src/DOMNodeComparator.php 0000644 00000004502 15111337760 0013475 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/comparator. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Comparator; use function assert; use function mb_strtolower; use function sprintf; use DOMDocument; use DOMNode; use ValueError; final class DOMNodeComparator extends ObjectComparator { public function accepts(mixed $expected, mixed $actual): bool { return $expected instanceof DOMNode && $actual instanceof DOMNode; } /** * @throws ComparisonFailure */ public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = false, bool $ignoreCase = false, array &$processed = []): void { assert($expected instanceof DOMNode); assert($actual instanceof DOMNode); $expectedAsString = $this->nodeToText($expected, true, $ignoreCase); $actualAsString = $this->nodeToText($actual, true, $ignoreCase); if ($expectedAsString !== $actualAsString) { $type = $expected instanceof DOMDocument ? 'documents' : 'nodes'; throw new ComparisonFailure( $expected, $actual, $expectedAsString, $actualAsString, sprintf("Failed asserting that two DOM %s are equal.\n", $type) ); } } /** * Returns the normalized, whitespace-cleaned, and indented textual * representation of a DOMNode. */ private function nodeToText(DOMNode $node, bool $canonicalize, bool $ignoreCase): string { if ($canonicalize) { $document = new DOMDocument; try { $c14n = $node->C14N(); assert(!empty($c14n)); @$document->loadXML($c14n); } catch (ValueError) { } $node = $document; } $document = $node instanceof DOMDocument ? $node : $node->ownerDocument; $document->formatOutput = true; $document->normalizeDocument(); $text = $node instanceof DOMDocument ? $node->saveXML() : $document->saveXML($node); return $ignoreCase ? mb_strtolower($text, 'UTF-8') : $text; } } comparator/README.md 0000644 00000003073 15111337760 0010201 0 ustar 00 [](https://packagist.org/packages/sebastian/comparator) [](https://github.com/sebastianbergmann/comparator/actions) [](https://shepherd.dev/github/sebastianbergmann/comparator) [](https://codecov.io/gh/sebastianbergmann/comparator) # sebastian/comparator This component provides the functionality to compare PHP values for equality. ## Installation You can add this library as a local, per-project dependency to your project using [Composer](https://getcomposer.org/): ``` composer require sebastian/comparator ``` If you only need this library during development, for instance to run your project's test suite, then you should add it as a development-time dependency: ``` composer require --dev sebastian/comparator ``` ## Usage ```php <?php use SebastianBergmann\Comparator\Factory; use SebastianBergmann\Comparator\ComparisonFailure; $date1 = new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/New_York')); $date2 = new DateTime('2013-03-29 03:13:35', new DateTimeZone('America/Chicago')); $factory = new Factory; $comparator = $factory->getComparatorFor($date1, $date2); try { $comparator->assertEquals($date1, $date2); print "Dates match"; } catch (ComparisonFailure $failure) { print "Dates don't match"; } ``` comparator/LICENSE 0000644 00000002773 15111337760 0007735 0 ustar 00 BSD 3-Clause License Copyright (c) 2002-2023, Sebastian Bergmann All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. comparator/ChangeLog.md 0000644 00000012512 15111337760 0011071 0 ustar 00 # ChangeLog All notable changes are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles. ## [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 * Methods now have parameter and return type declarations * `Comparator::$factory` is now private, use `Comparator::factory()` instead * `ComparisonFailure`, `DOMNodeComparator`, `DateTimeComparator`, `ExceptionComparator`, `MockObjectComparator`, `NumericComparator`, `ResourceComparator`, `SplObjectStorageComparator`, and `TypeComparator` are now `final` * `ScalarComparator` and `DOMNodeComparator` now use `mb_strtolower($string, 'UTF-8')` instead of `strtolower($string)` ### Removed * Removed `$identical` parameter from `ComparisonFailure::__construct()` * Removed `Comparator::$exporter` * Removed support for PHP 7.3, PHP 7.4, and PHP 8.0 ## [4.0.8] - 2022-09-14 ### Fixed * [#102](https://github.com/sebastianbergmann/comparator/pull/102): Fix `float` comparison precision ## [4.0.7] - 2022-09-14 ### Fixed * [#99](https://github.com/sebastianbergmann/comparator/pull/99): Fix weak comparison between `'0'` and `false` ## [4.0.6] - 2020-10-26 ### Fixed * `SebastianBergmann\Comparator\Exception` now correctly extends `\Throwable` ## [4.0.5] - 2020-09-30 ### Fixed * [#89](https://github.com/sebastianbergmann/comparator/pull/89): Handle PHP 8 `ValueError` ## [4.0.4] - 2020-09-28 ### Changed * Changed PHP version constraint in `composer.json` from `^7.3 || ^8.0` to `>=7.3` ## [4.0.3] - 2020-06-26 ### Added * This component is now supported on PHP 8 ## [4.0.2] - 2020-06-15 ### Fixed * [#85](https://github.com/sebastianbergmann/comparator/issues/85): Version 4.0.1 breaks backward compatibility ## [4.0.1] - 2020-06-15 ### Changed * Tests etc. are now ignored for archive exports ## [4.0.0] - 2020-02-07 ### Removed * Removed support for PHP 7.1 and PHP 7.2 ## [3.0.5] - 2022-09-14 ### Fixed * [#102](https://github.com/sebastianbergmann/comparator/pull/102): Fix `float` comparison precision ## [3.0.4] - 2022-09-14 ### Fixed * [#99](https://github.com/sebastianbergmann/comparator/pull/99): Fix weak comparison between `'0'` and `false` ## [3.0.3] - 2020-11-30 ### Changed * Changed PHP version constraint in `composer.json` from `^7.1` to `>=7.1` ## [3.0.2] - 2018-07-12 ### Changed * By default, `MockObjectComparator` is now tried before all other (default) comparators ## [3.0.1] - 2018-06-14 ### Fixed * [#53](https://github.com/sebastianbergmann/comparator/pull/53): `DOMNodeComparator` ignores `$ignoreCase` parameter * [#58](https://github.com/sebastianbergmann/comparator/pull/58): `ScalarComparator` does not handle extremely ugly string comparison edge cases ## [3.0.0] - 2018-04-18 ### Fixed * [#48](https://github.com/sebastianbergmann/comparator/issues/48): `DateTimeComparator` does not support fractional second deltas ### Removed * Removed support for PHP 7.0 ## [2.1.3] - 2018-02-01 ### Changed * This component is now compatible with version 3 of `sebastian/diff` ## [2.1.2] - 2018-01-12 ### Fixed * Fix comparison of `DateTimeImmutable` objects ## [2.1.1] - 2017-12-22 ### Fixed * [phpunit/#2923](https://github.com/sebastianbergmann/phpunit/issues/2923): Unexpected failed date matching ## [2.1.0] - 2017-11-03 ### Added * Added `SebastianBergmann\Comparator\Factory::reset()` to unregister all non-default comparators * Added support for `phpunit/phpunit-mock-objects` version `^5.0` [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.8...5.0.0 [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 [4.0.5]: https://github.com/sebastianbergmann/comparator/compare/4.0.4...4.0.5 [4.0.4]: https://github.com/sebastianbergmann/comparator/compare/4.0.3...4.0.4 [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 [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 [3.0.2]: https://github.com/sebastianbergmann/comparator/compare/3.0.1...3.0.2 [3.0.1]: https://github.com/sebastianbergmann/comparator/compare/3.0.0...3.0.1 [3.0.0]: https://github.com/sebastianbergmann/comparator/compare/2.1.3...3.0.0 [2.1.3]: https://github.com/sebastianbergmann/comparator/compare/2.1.2...2.1.3 [2.1.2]: https://github.com/sebastianbergmann/comparator/compare/2.1.1...2.1.2 [2.1.1]: https://github.com/sebastianbergmann/comparator/compare/2.1.0...2.1.1 [2.1.0]: https://github.com/sebastianbergmann/comparator/compare/2.0.2...2.1.0 comparator/composer.json 0000644 00000003044 15111337760 0011442 0 ustar 00 { "name": "sebastian/comparator", "description": "Provides the functionality to compare PHP values for equality", "keywords": ["comparator","compare","equality"], "homepage": "https://github.com/sebastianbergmann/comparator", "license": "BSD-3-Clause", "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" }, { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" }, { "name": "Volker Dusch", "email": "github@wallbash.com" }, { "name": "Bernhard Schussek", "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", "sebastian/diff": "^5.0", "sebastian/exporter": "^5.0", "ext-dom": "*", "ext-mbstring": "*" }, "require-dev": { "phpunit/phpunit": "^10.3" }, "config": { "platform": { "php": "8.1.0" }, "optimize-autoloader": true, "sort-packages": true }, "autoload": { "classmap": [ "src/" ] }, "autoload-dev": { "classmap": [ "tests/_fixture" ] }, "extra": { "branch-alias": { "dev-main": "5.0-dev" } } } comparator/SECURITY.md 0000644 00000003565 15111337760 0010521 0 ustar 00 # Security Policy 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. **Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.** 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. object-enumerator/src/Enumerator.php 0000644 00000003451 15111337760 0013621 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/object-enumerator. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\ObjectEnumerator; use function array_merge; use function is_array; use function is_object; use SebastianBergmann\ObjectReflector\ObjectReflector; use SebastianBergmann\RecursionContext\Context; final class Enumerator { /** * @psalm-return list<object> */ public function enumerate(array|object $variable, Context $processed = new Context): array { $objects = []; if ($processed->contains($variable)) { return $objects; } $array = $variable; /* @noinspection UnusedFunctionResultInspection */ $processed->add($variable); if (is_array($variable)) { foreach ($array as $element) { if (!is_array($element) && !is_object($element)) { continue; } /** @noinspection SlowArrayOperationsInLoopInspection */ $objects = array_merge( $objects, $this->enumerate($element, $processed) ); } return $objects; } $objects[] = $variable; foreach ((new ObjectReflector)->getProperties($variable) as $value) { if (!is_array($value) && !is_object($value)) { continue; } /** @noinspection SlowArrayOperationsInLoopInspection */ $objects = array_merge( $objects, $this->enumerate($value, $processed) ); } return $objects; } } object-enumerator/README.md 0000644 00000002200 15111337760 0011446 0 ustar 00 [](https://packagist.org/packages/sebastian/object-enumerator) [](https://github.com/sebastianbergmann/object-enumerator/actions) [](https://shepherd.dev/github/sebastianbergmann/object-enumerator) [](https://codecov.io/gh/sebastianbergmann/object-enumerator) # sebastian/object-enumerator Traverses array structures and object graphs to enumerate all referenced objects. ## Installation You can add this library as a local, per-project dependency to your project using [Composer](https://getcomposer.org/): ``` composer require sebastian/object-enumerator ``` If you only need this library during development, for instance to run your project's test suite, then you should add it as a development-time dependency: ``` composer require --dev sebastian/object-enumerator ``` object-enumerator/LICENSE 0000644 00000002773 15111337760 0011213 0 ustar 00 BSD 3-Clause License Copyright (c) 2016-2023, Sebastian Bergmann All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. object-enumerator/ChangeLog.md 0000644 00000004767 15111337760 0012364 0 ustar 00 # Change Log All notable changes to `sebastianbergmann/object-enumerator` are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles. ## [5.0.0] - 2023-02-03 ### Removed * This component is no longer supported on PHP 7.3, PHP 7.4 and PHP 8.0 ## [4.0.4] - 2020-10-26 ### Fixed * `SebastianBergmann\ObjectEnumerator\Exception` now correctly extends `\Throwable` ## [4.0.3] - 2020-09-28 ### Changed * Changed PHP version constraint in `composer.json` from `^7.3 || ^8.0` to `>=7.3` ## [4.0.2] - 2020-06-26 ### Added * This component is now supported on PHP 8 ## [4.0.1] - 2020-06-15 ### Changed * Tests etc. are now ignored for archive exports ## [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.0.3] - 2017-08-03 ### Changed * Bumped required version of `sebastian/object-reflector` ## [3.0.2] - 2017-03-12 ### Changed * `sebastian/object-reflector` is now a dependency ## [3.0.1] - 2017-03-12 ### Fixed * Objects aggregated in inherited attributes are not enumerated ## [3.0.0] - 2017-03-03 ### Removed * This component is no longer supported on PHP 5.6 ## [2.0.1] - 2017-02-18 ### Fixed * Fixed [#2](https://github.com/sebastianbergmann/phpunit/pull/2): Exceptions in `ReflectionProperty::getValue()` are not handled ## [2.0.0] - 2016-11-19 ### Changed * This component is now compatible with `sebastian/recursion-context: ~1.0.4` ## 1.0.0 - 2016-02-04 ### Added * Initial release [5.0.0]: https://github.com/sebastianbergmann/object-enumerator/compare/4.0.4...5.0.0 [4.0.4]: https://github.com/sebastianbergmann/object-enumerator/compare/4.0.3...4.0.4 [4.0.3]: https://github.com/sebastianbergmann/object-enumerator/compare/4.0.2...4.0.3 [4.0.2]: https://github.com/sebastianbergmann/object-enumerator/compare/4.0.1...4.0.2 [4.0.1]: https://github.com/sebastianbergmann/object-enumerator/compare/4.0.0...4.0.1 [4.0.0]: https://github.com/sebastianbergmann/object-enumerator/compare/3.0.3...4.0.0 [3.0.3]: https://github.com/sebastianbergmann/object-enumerator/compare/3.0.2...3.0.3 [3.0.2]: https://github.com/sebastianbergmann/object-enumerator/compare/3.0.1...3.0.2 [3.0.1]: https://github.com/sebastianbergmann/object-enumerator/compare/3.0.0...3.0.1 [3.0.0]: https://github.com/sebastianbergmann/object-enumerator/compare/2.0...3.0.0 [2.0.1]: https://github.com/sebastianbergmann/object-enumerator/compare/2.0.0...2.0.1 [2.0.0]: https://github.com/sebastianbergmann/object-enumerator/compare/1.0...2.0.0 object-enumerator/composer.json 0000644 00000002000 15111337760 0012707 0 ustar 00 { "name": "sebastian/object-enumerator", "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", "license": "BSD-3-Clause", "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], "prefer-stable": true, "config": { "platform": { "php": "8.1.0" }, "optimize-autoloader": true, "sort-packages": true }, "require": { "php": ">=8.1", "sebastian/object-reflector": "^3.0", "sebastian/recursion-context": "^5.0" }, "require-dev": { "phpunit/phpunit": "^10.0" }, "autoload": { "classmap": [ "src/" ] }, "autoload-dev": { "classmap": [ "tests/_fixture/" ] }, "extra": { "branch-alias": { "dev-main": "5.0-dev" } } } object-enumerator/SECURITY.md 0000644 00000001120 15111337760 0011760 0 ustar 00 # 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 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.** ## Security Contact Information After the above, if you still would like to report a security vulnerability, please email `sebastian@phpunit.de`. object-enumerator/phpunit.xml 0000644 00000001426 15111337760 0012411 0 ustar 00 <?xml version="1.0" encoding="UTF-8"?> <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.0/phpunit.xsd" bootstrap="vendor/autoload.php" cacheDirectory=".phpunit.cache" executionOrder="depends,defects" requireCoverageMetadata="true" beStrictAboutCoverageMetadata="true" beStrictAboutOutputDuringTests="true" failOnRisky="true" failOnWarning="true" colors="true"> <testsuites> <testsuite name="default"> <directory>tests</directory> </testsuite> </testsuites> <coverage> <include> <directory suffix=".php">src</directory> </include> </coverage> </phpunit> code-unit/src/FunctionUnit.php 0000644 00000001002 15111337760 0012355 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/code-unit. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\CodeUnit; /** * @psalm-immutable */ final class FunctionUnit extends CodeUnit { /** * @psalm-assert-if-true FunctionUnit $this */ public function isFunction(): bool { return true; } } code-unit/src/ClassMethodUnit.php 0000644 00000001013 15111337760 0013000 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/code-unit. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\CodeUnit; /** * @psalm-immutable */ final class ClassMethodUnit extends CodeUnit { /** * @psalm-assert-if-true ClassMethodUnit $this */ public function isClassMethod(): bool { return true; } } code-unit/src/CodeUnitCollection.php 0000644 00000003035 15111337760 0013466 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/code-unit. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\CodeUnit; use function array_merge; use function count; use Countable; use IteratorAggregate; /** * @template-implements IteratorAggregate<int, CodeUnit> * * @psalm-immutable */ final class CodeUnitCollection implements Countable, IteratorAggregate { /** * @psalm-var list<CodeUnit> */ private readonly array $codeUnits; public static function fromList(CodeUnit ...$codeUnits): self { return new self($codeUnits); } /** * @psalm-param list<CodeUnit> $codeUnits */ private function __construct(array $codeUnits) { $this->codeUnits = $codeUnits; } /** * @psalm-return list<CodeUnit> */ public function asArray(): array { return $this->codeUnits; } public function getIterator(): CodeUnitCollectionIterator { return new CodeUnitCollectionIterator($this); } public function count(): int { return count($this->codeUnits); } public function isEmpty(): bool { return empty($this->codeUnits); } public function mergeWith(self $other): self { return new self( array_merge( $this->asArray(), $other->asArray() ) ); } } code-unit/src/FileUnit.php 0000644 00000000766 15111337760 0011467 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/code-unit. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\CodeUnit; /** * @psalm-immutable */ final class FileUnit extends CodeUnit { /** * @psalm-assert-if-true FileUnit $this */ public function isFile(): bool { return true; } } code-unit/src/CodeUnit.php 0000644 00000030063 15111337760 0011453 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/code-unit. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\CodeUnit; use function count; use function file; use function file_exists; use function is_readable; use function range; use function sprintf; use ReflectionClass; use ReflectionFunction; use ReflectionMethod; /** * @psalm-immutable */ abstract class CodeUnit { private readonly string $name; private readonly string $sourceFileName; /** * @psalm-var list<int> */ private readonly array $sourceLines; /** * @psalm-param class-string $className * * @throws InvalidCodeUnitException * @throws ReflectionException */ public static function forClass(string $className): ClassUnit { self::ensureUserDefinedClass($className); $reflector = self::reflectorForClass($className); return new ClassUnit( $className, $reflector->getFileName(), range( $reflector->getStartLine(), $reflector->getEndLine() ) ); } /** * @psalm-param class-string $className * * @throws InvalidCodeUnitException * @throws ReflectionException */ public static function forClassMethod(string $className, string $methodName): ClassMethodUnit { self::ensureUserDefinedClass($className); $reflector = self::reflectorForClassMethod($className, $methodName); return new ClassMethodUnit( $className . '::' . $methodName, $reflector->getFileName(), range( $reflector->getStartLine(), $reflector->getEndLine() ) ); } /** * @throws InvalidCodeUnitException */ public static function forFileWithAbsolutePath(string $path): FileUnit { self::ensureFileExistsAndIsReadable($path); return new FileUnit( $path, $path, range( 1, count(file($path)) ) ); } /** * @psalm-param class-string $interfaceName * * @throws InvalidCodeUnitException * @throws ReflectionException */ public static function forInterface(string $interfaceName): InterfaceUnit { self::ensureUserDefinedInterface($interfaceName); $reflector = self::reflectorForClass($interfaceName); return new InterfaceUnit( $interfaceName, $reflector->getFileName(), range( $reflector->getStartLine(), $reflector->getEndLine() ) ); } /** * @psalm-param class-string $interfaceName * * @throws InvalidCodeUnitException * @throws ReflectionException */ public static function forInterfaceMethod(string $interfaceName, string $methodName): InterfaceMethodUnit { self::ensureUserDefinedInterface($interfaceName); $reflector = self::reflectorForClassMethod($interfaceName, $methodName); return new InterfaceMethodUnit( $interfaceName . '::' . $methodName, $reflector->getFileName(), range( $reflector->getStartLine(), $reflector->getEndLine() ) ); } /** * @psalm-param class-string $traitName * * @throws InvalidCodeUnitException * @throws ReflectionException */ public static function forTrait(string $traitName): TraitUnit { self::ensureUserDefinedTrait($traitName); $reflector = self::reflectorForClass($traitName); return new TraitUnit( $traitName, $reflector->getFileName(), range( $reflector->getStartLine(), $reflector->getEndLine() ) ); } /** * @psalm-param class-string $traitName * * @throws InvalidCodeUnitException * @throws ReflectionException */ public static function forTraitMethod(string $traitName, string $methodName): TraitMethodUnit { self::ensureUserDefinedTrait($traitName); $reflector = self::reflectorForClassMethod($traitName, $methodName); return new TraitMethodUnit( $traitName . '::' . $methodName, $reflector->getFileName(), range( $reflector->getStartLine(), $reflector->getEndLine() ) ); } /** * @psalm-param callable-string $functionName * * @throws InvalidCodeUnitException * @throws ReflectionException */ public static function forFunction(string $functionName): FunctionUnit { $reflector = self::reflectorForFunction($functionName); if (!$reflector->isUserDefined()) { throw new InvalidCodeUnitException( sprintf( '"%s" is not a user-defined function', $functionName ) ); } return new FunctionUnit( $functionName, $reflector->getFileName(), range( $reflector->getStartLine(), $reflector->getEndLine() ) ); } /** * @psalm-param list<int> $sourceLines */ private function __construct(string $name, string $sourceFileName, array $sourceLines) { $this->name = $name; $this->sourceFileName = $sourceFileName; $this->sourceLines = $sourceLines; } public function name(): string { return $this->name; } public function sourceFileName(): string { return $this->sourceFileName; } /** * @psalm-return list<int> */ public function sourceLines(): array { return $this->sourceLines; } public function isClass(): bool { return false; } public function isClassMethod(): bool { return false; } public function isInterface(): bool { return false; } public function isInterfaceMethod(): bool { return false; } public function isTrait(): bool { return false; } public function isTraitMethod(): bool { return false; } public function isFunction(): bool { return false; } public function isFile(): bool { return false; } /** * @throws InvalidCodeUnitException */ private static function ensureFileExistsAndIsReadable(string $path): void { if (!(file_exists($path) && is_readable($path))) { throw new InvalidCodeUnitException( sprintf( 'File "%s" does not exist or is not readable', $path ) ); } } /** * @psalm-param class-string $className * * @throws InvalidCodeUnitException */ private static function ensureUserDefinedClass(string $className): void { try { $reflector = new ReflectionClass($className); if ($reflector->isInterface()) { throw new InvalidCodeUnitException( sprintf( '"%s" is an interface and not a class', $className ) ); } if ($reflector->isTrait()) { throw new InvalidCodeUnitException( sprintf( '"%s" is a trait and not a class', $className ) ); } if (!$reflector->isUserDefined()) { throw new InvalidCodeUnitException( sprintf( '"%s" is not a user-defined class', $className ) ); } // @codeCoverageIgnoreStart } catch (\ReflectionException $e) { throw new ReflectionException( $e->getMessage(), $e->getCode(), $e ); } // @codeCoverageIgnoreEnd } /** * @psalm-param class-string $interfaceName * * @throws InvalidCodeUnitException */ private static function ensureUserDefinedInterface(string $interfaceName): void { try { $reflector = new ReflectionClass($interfaceName); if (!$reflector->isInterface()) { throw new InvalidCodeUnitException( sprintf( '"%s" is not an interface', $interfaceName ) ); } if (!$reflector->isUserDefined()) { throw new InvalidCodeUnitException( sprintf( '"%s" is not a user-defined interface', $interfaceName ) ); } // @codeCoverageIgnoreStart } catch (\ReflectionException $e) { throw new ReflectionException( $e->getMessage(), $e->getCode(), $e ); } // @codeCoverageIgnoreEnd } /** * @psalm-param class-string $traitName * * @throws InvalidCodeUnitException */ private static function ensureUserDefinedTrait(string $traitName): void { try { $reflector = new ReflectionClass($traitName); if (!$reflector->isTrait()) { throw new InvalidCodeUnitException( sprintf( '"%s" is not a trait', $traitName ) ); } // @codeCoverageIgnoreStart if (!$reflector->isUserDefined()) { throw new InvalidCodeUnitException( sprintf( '"%s" is not a user-defined trait', $traitName ) ); } } catch (\ReflectionException $e) { throw new ReflectionException( $e->getMessage(), $e->getCode(), $e ); } // @codeCoverageIgnoreEnd } /** * @psalm-param class-string $className * * @throws ReflectionException */ private static function reflectorForClass(string $className): ReflectionClass { try { return new ReflectionClass($className); // @codeCoverageIgnoreStart } catch (\ReflectionException $e) { throw new ReflectionException( $e->getMessage(), $e->getCode(), $e ); } // @codeCoverageIgnoreEnd } /** * @psalm-param class-string $className * * @throws ReflectionException */ private static function reflectorForClassMethod(string $className, string $methodName): ReflectionMethod { try { return new ReflectionMethod($className, $methodName); // @codeCoverageIgnoreStart } catch (\ReflectionException $e) { throw new ReflectionException( $e->getMessage(), $e->getCode(), $e ); } // @codeCoverageIgnoreEnd } /** * @psalm-param callable-string $functionName * * @throws ReflectionException */ private static function reflectorForFunction(string $functionName): ReflectionFunction { try { return new ReflectionFunction($functionName); // @codeCoverageIgnoreStart } catch (\ReflectionException $e) { throw new ReflectionException( $e->getMessage(), $e->getCode(), $e ); } // @codeCoverageIgnoreEnd } } code-unit/src/TraitUnit.php 0000644 00000000771 15111337760 0011667 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/code-unit. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\CodeUnit; /** * @psalm-immutable */ final class TraitUnit extends CodeUnit { /** * @psalm-assert-if-true TraitUnit $this */ public function isTrait(): bool { return true; } } code-unit/src/InterfaceMethodUnit.php 0000644 00000001023 15111337760 0013634 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/code-unit. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\CodeUnit; /** * @psalm-immutable */ final class InterfaceMethodUnit extends CodeUnit { /** * @psalm-assert-if-true InterfaceMethod $this */ public function isInterfaceMethod(): bool { return true; } } code-unit/src/exceptions/Exception.php 0000644 00000000552 15111337760 0014060 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/code-unit. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\CodeUnit; use Throwable; interface Exception extends Throwable { } code-unit/src/exceptions/NoTraitException.php 0000644 00000000626 15111337760 0015363 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/code-unit. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\CodeUnit; use RuntimeException; final class NoTraitException extends RuntimeException implements Exception { } code-unit/src/exceptions/InvalidCodeUnitException.php 0000644 00000000636 15111337760 0017025 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/code-unit. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\CodeUnit; use RuntimeException; final class InvalidCodeUnitException extends RuntimeException implements Exception { } code-unit/src/exceptions/error_log 0000644 00000001400 15111337760 0013317 0 ustar 00 [19-Nov-2025 19:02:38 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\CodeUnit\Exception" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/exceptions/InvalidCodeUnitException.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/exceptions/InvalidCodeUnitException.php on line 14 [20-Nov-2025 01:17:02 UTC] PHP Fatal error: Uncaught Error: Interface "SebastianBergmann\CodeUnit\Exception" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/exceptions/InvalidCodeUnitException.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/exceptions/InvalidCodeUnitException.php on line 14 code-unit/src/exceptions/ReflectionException.php 0000644 00000000631 15111337760 0016071 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/code-unit. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\CodeUnit; use RuntimeException; final class ReflectionException extends RuntimeException implements Exception { } code-unit/src/InterfaceUnit.php 0000644 00000001005 15111337760 0012473 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/code-unit. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\CodeUnit; /** * @psalm-immutable */ final class InterfaceUnit extends CodeUnit { /** * @psalm-assert-if-true InterfaceUnit $this */ public function isInterface(): bool { return true; } } code-unit/src/ClassUnit.php 0000644 00000000771 15111337760 0011651 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/code-unit. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\CodeUnit; /** * @psalm-immutable */ final class ClassUnit extends CodeUnit { /** * @psalm-assert-if-true ClassUnit $this */ public function isClass(): bool { return true; } } code-unit/src/Mapper.php 0000644 00000016327 15111337760 0011174 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/code-unit. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\CodeUnit; use function array_keys; use function array_merge; use function array_unique; use function array_values; use function class_exists; use function explode; use function function_exists; use function interface_exists; use function ksort; use function method_exists; use function sort; use function sprintf; use function str_contains; use function trait_exists; use ReflectionClass; use ReflectionFunction; use ReflectionMethod; final class Mapper { /** * @psalm-return array<string,list<int>> */ public function codeUnitsToSourceLines(CodeUnitCollection $codeUnits): array { $result = []; foreach ($codeUnits as $codeUnit) { $sourceFileName = $codeUnit->sourceFileName(); if (!isset($result[$sourceFileName])) { $result[$sourceFileName] = []; } $result[$sourceFileName] = array_merge($result[$sourceFileName], $codeUnit->sourceLines()); } foreach (array_keys($result) as $sourceFileName) { $result[$sourceFileName] = array_values(array_unique($result[$sourceFileName])); sort($result[$sourceFileName]); } ksort($result); return $result; } /** * @throws InvalidCodeUnitException * @throws ReflectionException */ public function stringToCodeUnits(string $unit): CodeUnitCollection { if (str_contains($unit, '::')) { [$firstPart, $secondPart] = explode('::', $unit); if ($this->isUserDefinedFunction($secondPart)) { return CodeUnitCollection::fromList(CodeUnit::forFunction($secondPart)); } if ($this->isUserDefinedMethod($firstPart, $secondPart)) { return CodeUnitCollection::fromList(CodeUnit::forClassMethod($firstPart, $secondPart)); } if ($this->isUserDefinedInterface($firstPart)) { return CodeUnitCollection::fromList(CodeUnit::forInterfaceMethod($firstPart, $secondPart)); } if ($this->isUserDefinedTrait($firstPart)) { return CodeUnitCollection::fromList(CodeUnit::forTraitMethod($firstPart, $secondPart)); } } else { if ($this->isUserDefinedClass($unit)) { $units = [CodeUnit::forClass($unit)]; foreach ($this->reflectorForClass($unit)->getTraits() as $trait) { if (!$trait->isUserDefined()) { // @codeCoverageIgnoreStart continue; // @codeCoverageIgnoreEnd } $units[] = CodeUnit::forTrait($trait->getName()); } return CodeUnitCollection::fromList(...$units); } if ($this->isUserDefinedInterface($unit)) { return CodeUnitCollection::fromList(CodeUnit::forInterface($unit)); } if ($this->isUserDefinedTrait($unit)) { return CodeUnitCollection::fromList(CodeUnit::forTrait($unit)); } if ($this->isUserDefinedFunction($unit)) { return CodeUnitCollection::fromList(CodeUnit::forFunction($unit)); } } throw new InvalidCodeUnitException( sprintf( '"%s" is not a valid code unit', $unit ) ); } /** * @psalm-param class-string $className * * @throws ReflectionException */ private function reflectorForClass(string $className): ReflectionClass { try { return new ReflectionClass($className); // @codeCoverageIgnoreStart } catch (\ReflectionException $e) { throw new ReflectionException( $e->getMessage(), $e->getCode(), $e ); } // @codeCoverageIgnoreEnd } /** * @throws ReflectionException */ private function isUserDefinedFunction(string $functionName): bool { if (!function_exists($functionName)) { return false; } try { return (new ReflectionFunction($functionName))->isUserDefined(); // @codeCoverageIgnoreStart } catch (\ReflectionException $e) { throw new ReflectionException( $e->getMessage(), $e->getCode(), $e ); } // @codeCoverageIgnoreEnd } /** * @throws ReflectionException */ private function isUserDefinedClass(string $className): bool { if (!class_exists($className)) { return false; } try { return (new ReflectionClass($className))->isUserDefined(); // @codeCoverageIgnoreStart } catch (\ReflectionException $e) { throw new ReflectionException( $e->getMessage(), $e->getCode(), $e ); } // @codeCoverageIgnoreEnd } /** * @throws ReflectionException */ private function isUserDefinedInterface(string $interfaceName): bool { if (!interface_exists($interfaceName)) { return false; } try { return (new ReflectionClass($interfaceName))->isUserDefined(); // @codeCoverageIgnoreStart } catch (\ReflectionException $e) { throw new ReflectionException( $e->getMessage(), $e->getCode(), $e ); } // @codeCoverageIgnoreEnd } /** * @throws ReflectionException */ private function isUserDefinedTrait(string $traitName): bool { if (!trait_exists($traitName)) { return false; } try { return (new ReflectionClass($traitName))->isUserDefined(); // @codeCoverageIgnoreStart } catch (\ReflectionException $e) { throw new ReflectionException( $e->getMessage(), $e->getCode(), $e ); } // @codeCoverageIgnoreEnd } /** * @throws ReflectionException */ private function isUserDefinedMethod(string $className, string $methodName): bool { if (!class_exists($className)) { // @codeCoverageIgnoreStart return false; // @codeCoverageIgnoreEnd } if (!method_exists($className, $methodName)) { // @codeCoverageIgnoreStart return false; // @codeCoverageIgnoreEnd } try { return (new ReflectionMethod($className, $methodName))->isUserDefined(); // @codeCoverageIgnoreStart } catch (\ReflectionException $e) { throw new ReflectionException( $e->getMessage(), $e->getCode(), $e ); } // @codeCoverageIgnoreEnd } } code-unit/src/TraitMethodUnit.php 0000644 00000001013 15111337760 0013016 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/code-unit. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\CodeUnit; /** * @psalm-immutable */ final class TraitMethodUnit extends CodeUnit { /** * @psalm-assert-if-true TraitMethodUnit $this */ public function isTraitMethod(): bool { return true; } } code-unit/src/error_log 0000644 00000072257 15111337760 0011160 0 ustar 00 [18-Nov-2025 21:29:50 UTC] PHP Fatal error: Could not check compatibility between SebastianBergmann\CodeUnit\CodeUnitCollection::getIterator(): SebastianBergmann\CodeUnit\CodeUnitCollectionIterator and IteratorAggregate::getIterator(): Traversable, because class SebastianBergmann\CodeUnit\CodeUnitCollectionIterator is not available in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/CodeUnitCollection.php on line 50 [18-Nov-2025 21:34:42 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceMethodUnit.php on line 15 [19-Nov-2025 02:38:17 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitMethodUnit.php on line 15 [19-Nov-2025 03:41:56 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassMethodUnit.php on line 15 [19-Nov-2025 04:56:35 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceMethodUnit.php on line 15 [19-Nov-2025 04:56:35 UTC] PHP Fatal error: Could not check compatibility between SebastianBergmann\CodeUnit\CodeUnitCollection::getIterator(): SebastianBergmann\CodeUnit\CodeUnitCollectionIterator and IteratorAggregate::getIterator(): Traversable, because class SebastianBergmann\CodeUnit\CodeUnitCollectionIterator is not available in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/CodeUnitCollection.php on line 50 [19-Nov-2025 05:31:39 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitUnit.php on line 15 [19-Nov-2025 05:33:33 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassUnit.php on line 15 [19-Nov-2025 05:36:50 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FileUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FileUnit.php on line 15 [19-Nov-2025 06:03:45 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceUnit.php on line 15 [19-Nov-2025 07:18:21 UTC] PHP Fatal error: Could not check compatibility between SebastianBergmann\CodeUnit\CodeUnitCollection::getIterator(): SebastianBergmann\CodeUnit\CodeUnitCollectionIterator and IteratorAggregate::getIterator(): Traversable, because class SebastianBergmann\CodeUnit\CodeUnitCollectionIterator is not available in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/CodeUnitCollection.php on line 50 [19-Nov-2025 07:18:21 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceMethodUnit.php on line 15 [19-Nov-2025 07:18:23 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitMethodUnit.php on line 15 [19-Nov-2025 07:18:28 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassMethodUnit.php on line 15 [19-Nov-2025 07:18:42 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FileUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FileUnit.php on line 15 [19-Nov-2025 07:19:23 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassUnit.php on line 15 [19-Nov-2025 07:20:29 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitUnit.php on line 15 [19-Nov-2025 07:21:31 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceUnit.php on line 15 [19-Nov-2025 07:43:13 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitUnit.php on line 15 [19-Nov-2025 07:43:28 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FileUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FileUnit.php on line 15 [19-Nov-2025 07:44:10 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassMethodUnit.php on line 15 [19-Nov-2025 07:46:18 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceUnit.php on line 15 [19-Nov-2025 07:47:22 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassUnit.php on line 15 [19-Nov-2025 07:48:25 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceMethodUnit.php on line 15 [19-Nov-2025 07:49:31 UTC] PHP Fatal error: Could not check compatibility between SebastianBergmann\CodeUnit\CodeUnitCollection::getIterator(): SebastianBergmann\CodeUnit\CodeUnitCollectionIterator and IteratorAggregate::getIterator(): Traversable, because class SebastianBergmann\CodeUnit\CodeUnitCollectionIterator is not available in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/CodeUnitCollection.php on line 50 [19-Nov-2025 07:50:35 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitMethodUnit.php on line 15 [19-Nov-2025 07:58:28 UTC] PHP Fatal error: Could not check compatibility between SebastianBergmann\CodeUnit\CodeUnitCollection::getIterator(): SebastianBergmann\CodeUnit\CodeUnitCollectionIterator and IteratorAggregate::getIterator(): Traversable, because class SebastianBergmann\CodeUnit\CodeUnitCollectionIterator is not available in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/CodeUnitCollection.php on line 50 [19-Nov-2025 07:59:53 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitUnit.php on line 15 [19-Nov-2025 08:00:48 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FileUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FileUnit.php on line 15 [19-Nov-2025 08:01:50 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassMethodUnit.php on line 15 [19-Nov-2025 08:02:51 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitMethodUnit.php on line 15 [19-Nov-2025 08:03:52 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassUnit.php on line 15 [19-Nov-2025 08:05:59 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceUnit.php on line 15 [19-Nov-2025 08:06:54 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceMethodUnit.php on line 15 [19-Nov-2025 08:17:45 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitMethodUnit.php on line 15 [19-Nov-2025 08:19:01 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassMethodUnit.php on line 15 [19-Nov-2025 08:19:54 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FileUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FileUnit.php on line 15 [19-Nov-2025 08:22:02 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceMethodUnit.php on line 15 [19-Nov-2025 08:22:59 UTC] PHP Fatal error: Could not check compatibility between SebastianBergmann\CodeUnit\CodeUnitCollection::getIterator(): SebastianBergmann\CodeUnit\CodeUnitCollectionIterator and IteratorAggregate::getIterator(): Traversable, because class SebastianBergmann\CodeUnit\CodeUnitCollectionIterator is not available in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/CodeUnitCollection.php on line 50 [19-Nov-2025 08:25:06 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassUnit.php on line 15 [19-Nov-2025 08:27:01 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceUnit.php on line 15 [19-Nov-2025 08:28:00 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitUnit.php on line 15 [19-Nov-2025 08:30:06 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FileUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FileUnit.php on line 15 [19-Nov-2025 09:39:28 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FunctionUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FunctionUnit.php on line 15 [19-Nov-2025 09:45:23 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitMethodUnit.php on line 15 [19-Nov-2025 10:23:52 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassMethodUnit.php on line 15 [19-Nov-2025 12:27:06 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassUnit.php on line 15 [19-Nov-2025 12:28:21 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FileUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FileUnit.php on line 15 [19-Nov-2025 12:31:40 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitUnit.php on line 15 [19-Nov-2025 13:03:59 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceUnit.php on line 15 [19-Nov-2025 14:18:45 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceMethodUnit.php on line 15 [19-Nov-2025 14:18:45 UTC] PHP Fatal error: Could not check compatibility between SebastianBergmann\CodeUnit\CodeUnitCollection::getIterator(): SebastianBergmann\CodeUnit\CodeUnitCollectionIterator and IteratorAggregate::getIterator(): Traversable, because class SebastianBergmann\CodeUnit\CodeUnitCollectionIterator is not available in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/CodeUnitCollection.php on line 50 [19-Nov-2025 14:18:47 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitMethodUnit.php on line 15 [19-Nov-2025 14:18:52 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassMethodUnit.php on line 15 [19-Nov-2025 14:19:06 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FileUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FileUnit.php on line 15 [19-Nov-2025 14:19:50 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassUnit.php on line 15 [19-Nov-2025 14:20:50 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitUnit.php on line 15 [19-Nov-2025 14:21:54 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceUnit.php on line 15 [19-Nov-2025 14:34:21 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitMethodUnit.php on line 15 [19-Nov-2025 14:34:39 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassUnit.php on line 15 [19-Nov-2025 14:35:35 UTC] PHP Fatal error: Could not check compatibility between SebastianBergmann\CodeUnit\CodeUnitCollection::getIterator(): SebastianBergmann\CodeUnit\CodeUnitCollectionIterator and IteratorAggregate::getIterator(): Traversable, because class SebastianBergmann\CodeUnit\CodeUnitCollectionIterator is not available in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/CodeUnitCollection.php on line 50 [19-Nov-2025 14:37:58 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceMethodUnit.php on line 15 [19-Nov-2025 14:38:51 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitUnit.php on line 15 [19-Nov-2025 14:40:02 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FileUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FileUnit.php on line 15 [19-Nov-2025 14:40:54 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassMethodUnit.php on line 15 [19-Nov-2025 14:43:56 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceUnit.php on line 15 [19-Nov-2025 14:55:37 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitMethodUnit.php on line 15 [19-Nov-2025 14:58:47 UTC] PHP Fatal error: Could not check compatibility between SebastianBergmann\CodeUnit\CodeUnitCollection::getIterator(): SebastianBergmann\CodeUnit\CodeUnitCollectionIterator and IteratorAggregate::getIterator(): Traversable, because class SebastianBergmann\CodeUnit\CodeUnitCollectionIterator is not available in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/CodeUnitCollection.php on line 50 [19-Nov-2025 15:00:36 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceMethodUnit.php on line 15 [19-Nov-2025 15:03:32 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassMethodUnit.php on line 15 [19-Nov-2025 15:05:23 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FileUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FileUnit.php on line 15 [19-Nov-2025 15:07:21 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassUnit.php on line 15 [19-Nov-2025 15:11:12 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitUnit.php on line 15 [19-Nov-2025 15:13:03 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceUnit.php on line 15 [19-Nov-2025 15:13:59 UTC] PHP Fatal error: Could not check compatibility between SebastianBergmann\CodeUnit\CodeUnitCollection::getIterator(): SebastianBergmann\CodeUnit\CodeUnitCollectionIterator and IteratorAggregate::getIterator(): Traversable, because class SebastianBergmann\CodeUnit\CodeUnitCollectionIterator is not available in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/CodeUnitCollection.php on line 50 [19-Nov-2025 15:14:59 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitMethodUnit.php on line 15 [19-Nov-2025 16:15:23 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FunctionUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FunctionUnit.php on line 15 [25-Nov-2025 02:35:24 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitUnit.php on line 15 [25-Nov-2025 02:59:55 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceUnit.php on line 15 [25-Nov-2025 03:00:20 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassMethodUnit.php on line 15 [25-Nov-2025 03:03:07 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/InterfaceMethodUnit.php on line 15 [25-Nov-2025 03:23:21 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/ClassUnit.php on line 15 [25-Nov-2025 03:27:28 UTC] PHP Fatal error: Could not check compatibility between SebastianBergmann\CodeUnit\CodeUnitCollection::getIterator(): SebastianBergmann\CodeUnit\CodeUnitCollectionIterator and IteratorAggregate::getIterator(): Traversable, because class SebastianBergmann\CodeUnit\CodeUnitCollectionIterator is not available in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/CodeUnitCollection.php on line 50 [25-Nov-2025 04:30:47 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FunctionUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FunctionUnit.php on line 15 [25-Nov-2025 05:27:25 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitMethodUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/TraitMethodUnit.php on line 15 [25-Nov-2025 05:30:03 UTC] PHP Fatal error: Uncaught Error: Class "SebastianBergmann\CodeUnit\CodeUnit" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FileUnit.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/code-unit/src/FileUnit.php on line 15 code-unit/src/CodeUnitCollectionIterator.php 0000644 00000002125 15111337760 0015177 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/code-unit. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\CodeUnit; use Iterator; /** * @template-implements Iterator<int, CodeUnit> */ final class CodeUnitCollectionIterator implements Iterator { /** * @psalm-var list<CodeUnit> */ private array $codeUnits; private int $position = 0; public function __construct(CodeUnitCollection $collection) { $this->codeUnits = $collection->asArray(); } public function rewind(): void { $this->position = 0; } public function valid(): bool { return isset($this->codeUnits[$this->position]); } public function key(): int { return $this->position; } public function current(): CodeUnit { return $this->codeUnits[$this->position]; } public function next(): void { $this->position++; } } code-unit/README.md 0000644 00000002025 15111337760 0007715 0 ustar 00 [](https://packagist.org/packages/sebastian/code-unit) [](https://github.com/sebastianbergmann/code-unit/actions) [](https://shepherd.dev/github/sebastianbergmann/code-unit) [](https://codecov.io/gh/sebastianbergmann/code-unit) # sebastian/code-unit Collection of value objects that represent the PHP code units. ## Installation You can add this library as a local, per-project dependency to your project using [Composer](https://getcomposer.org/): ``` composer require sebastian/code-unit ``` If you only need this library during development, for instance to run your project's test suite, then you should add it as a development-time dependency: ``` composer require --dev sebastian/code-unit ``` code-unit/LICENSE 0000644 00000002773 15111337760 0007455 0 ustar 00 BSD 3-Clause License Copyright (c) 2020-2023, Sebastian Bergmann All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. code-unit/ChangeLog.md 0000644 00000004707 15111337760 0010620 0 ustar 00 # ChangeLog All notable changes are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles. ## [2.0.0] - 2023-02-03 ### Added * Added `SebastianBergmann\CodeUnit\FileUnit` value object that represents a sourcecode file ### Removed * `SebastianBergmann\CodeUnit\CodeUnitCollection::fromArray()` has been removed * `SebastianBergmann\CodeUnit\Mapper::stringToCodeUnits()` no longer supports `ClassName<*>` * This component is no longer supported on PHP 7.3, PHP 7.4, and PHP 8.0 ## [1.0.8] - 2020-10-26 ### Fixed * `SebastianBergmann\CodeUnit\Exception` now correctly extends `\Throwable` ## [1.0.7] - 2020-10-02 ### Fixed * `SebastianBergmann\CodeUnit\Mapper::stringToCodeUnits()` no longer attempts to create `CodeUnit` objects for code units that are not declared in userland ## [1.0.6] - 2020-09-28 ### Changed * Changed PHP version constraint in `composer.json` from `^7.3 || ^8.0` to `>=7.3` ## [1.0.5] - 2020-06-26 ### Fixed * [#3](https://github.com/sebastianbergmann/code-unit/issues/3): Regression in 1.0.4 ## [1.0.4] - 2020-06-26 ### Added * This component is now supported on PHP 8 ## [1.0.3] - 2020-06-15 ### Changed * Tests etc. are now ignored for archive exports ## [1.0.2] - 2020-04-30 ### Fixed * `Mapper::stringToCodeUnits()` raised the wrong exception for `Class::method` when a class named `Class` exists but does not have a method named `method` ## [1.0.1] - 2020-04-27 ### Fixed * [#2](https://github.com/sebastianbergmann/code-unit/issues/2): `Mapper::stringToCodeUnits()` breaks when `ClassName<extended>` is used for class that extends built-in class ## [1.0.0] - 2020-03-30 * Initial release [2.0.0]: https://github.com/sebastianbergmann/code-unit/compare/1.0.8...2.0.0 [1.0.8]: https://github.com/sebastianbergmann/code-unit/compare/1.0.7...1.0.8 [1.0.7]: https://github.com/sebastianbergmann/code-unit/compare/1.0.6...1.0.7 [1.0.6]: https://github.com/sebastianbergmann/code-unit/compare/1.0.5...1.0.6 [1.0.5]: https://github.com/sebastianbergmann/code-unit/compare/1.0.4...1.0.5 [1.0.4]: https://github.com/sebastianbergmann/code-unit/compare/1.0.3...1.0.4 [1.0.3]: https://github.com/sebastianbergmann/code-unit/compare/1.0.2...1.0.3 [1.0.2]: https://github.com/sebastianbergmann/code-unit/compare/1.0.1...1.0.2 [1.0.1]: https://github.com/sebastianbergmann/code-unit/compare/1.0.0...1.0.1 [1.0.0]: https://github.com/sebastianbergmann/code-unit/compare/530c3900e5db9bcb8516da545bef0d62536cedaa...1.0.0 code-unit/composer.json 0000644 00000002233 15111337760 0011161 0 ustar 00 { "name": "sebastian/code-unit", "description": "Collection of value objects that represent the PHP code units", "type": "library", "homepage": "https://github.com/sebastianbergmann/code-unit", "license": "BSD-3-Clause", "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "lead" } ], "support": { "issues": "https://github.com/sebastianbergmann/code-unit/issues" }, "prefer-stable": true, "require": { "php": ">=8.1" }, "require-dev": { "phpunit/phpunit": "^10.0" }, "config": { "platform": { "php": "8.1.0" }, "optimize-autoloader": true, "sort-packages": true }, "autoload": { "classmap": [ "src/" ] }, "autoload-dev": { "classmap": [ "tests/_fixture" ], "files": [ "tests/_fixture/file_with_multiple_code_units.php", "tests/_fixture/function.php" ] }, "extra": { "branch-alias": { "dev-main": "2.0-dev" } } } code-unit/SECURITY.md 0000644 00000001120 15111337760 0010222 0 ustar 00 # 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 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.** ## Security Contact Information After the above, if you still would like to report a security vulnerability, please email `sebastian@phpunit.de`. type/src/exception/Exception.php 0000644 00000000541 15111337760 0012765 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/type. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Type; use Throwable; interface Exception extends Throwable { } type/src/exception/RuntimeException.php 0000644 00000000567 15111337760 0014341 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/type. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Type; final class RuntimeException extends \RuntimeException implements Exception { } type/src/TypeName.php 0000644 00000003500 15111337760 0010551 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/type. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Type; use function array_pop; use function explode; use function implode; use function substr; use ReflectionClass; final class TypeName { private ?string $namespaceName; private string $simpleName; public static function fromQualifiedName(string $fullClassName): self { if ($fullClassName[0] === '\\') { $fullClassName = substr($fullClassName, 1); } $classNameParts = explode('\\', $fullClassName); $simpleName = array_pop($classNameParts); $namespaceName = implode('\\', $classNameParts); return new self($namespaceName, $simpleName); } public static function fromReflection(ReflectionClass $type): self { return new self( $type->getNamespaceName(), $type->getShortName() ); } public function __construct(?string $namespaceName, string $simpleName) { if ($namespaceName === '') { $namespaceName = null; } $this->namespaceName = $namespaceName; $this->simpleName = $simpleName; } public function namespaceName(): ?string { return $this->namespaceName; } public function simpleName(): string { return $this->simpleName; } public function qualifiedName(): string { return $this->namespaceName === null ? $this->simpleName : $this->namespaceName . '\\' . $this->simpleName; } public function isNamespaced(): bool { return $this->namespaceName !== null; } } type/src/type/NullType.php 0000644 00000001427 15111337760 0011572 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/type. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Type; final class NullType extends Type { public function isAssignable(Type $other): bool { return !($other instanceof VoidType); } public function name(): string { return 'null'; } public function asString(): string { return 'null'; } public function allowsNull(): bool { return true; } /** * @psalm-assert-if-true NullType $this */ public function isNull(): bool { return true; } } type/src/type/CallableType.php 0000644 00000010321 15111337760 0012350 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/type. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Type; use function assert; use function class_exists; use function count; use function explode; use function function_exists; use function is_array; use function is_object; use function is_string; use function str_contains; use Closure; use ReflectionClass; use ReflectionObject; final class CallableType extends Type { private bool $allowsNull; public function __construct(bool $nullable) { $this->allowsNull = $nullable; } public function isAssignable(Type $other): bool { if ($this->allowsNull && $other instanceof NullType) { return true; } if ($other instanceof self) { return true; } if ($other instanceof ObjectType) { if ($this->isClosure($other)) { return true; } if ($this->hasInvokeMethod($other)) { return true; } } if ($other instanceof SimpleType) { if ($this->isFunction($other)) { return true; } if ($this->isClassCallback($other)) { return true; } if ($this->isObjectCallback($other)) { return true; } } return false; } public function name(): string { return 'callable'; } public function allowsNull(): bool { return $this->allowsNull; } /** * @psalm-assert-if-true CallableType $this */ public function isCallable(): bool { return true; } private function isClosure(ObjectType $type): bool { return $type->className()->qualifiedName() === Closure::class; } private function hasInvokeMethod(ObjectType $type): bool { $className = $type->className()->qualifiedName(); assert(class_exists($className)); return (new ReflectionClass($className))->hasMethod('__invoke'); } private function isFunction(SimpleType $type): bool { if (!is_string($type->value())) { return false; } return function_exists($type->value()); } private function isObjectCallback(SimpleType $type): bool { if (!is_array($type->value())) { return false; } if (count($type->value()) !== 2) { return false; } if (!isset($type->value()[0], $type->value()[1])) { return false; } if (!is_object($type->value()[0]) || !is_string($type->value()[1])) { return false; } [$object, $methodName] = $type->value(); return (new ReflectionObject($object))->hasMethod($methodName); } private function isClassCallback(SimpleType $type): bool { if (!is_string($type->value()) && !is_array($type->value())) { return false; } if (is_string($type->value())) { if (!str_contains($type->value(), '::')) { return false; } [$className, $methodName] = explode('::', $type->value()); } if (is_array($type->value())) { if (count($type->value()) !== 2) { return false; } if (!isset($type->value()[0], $type->value()[1])) { return false; } if (!is_string($type->value()[0]) || !is_string($type->value()[1])) { return false; } [$className, $methodName] = $type->value(); } assert(isset($className) && is_string($className)); assert(isset($methodName) && is_string($methodName)); if (!class_exists($className)) { return false; } $class = new ReflectionClass($className); if (!$class->hasMethod($methodName)) { return false; } $method = $class->getMethod($methodName); return $method->isPublic() && $method->isStatic(); } } type/src/type/GenericObjectType.php 0000644 00000002025 15111337760 0013356 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/type. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Type; final class GenericObjectType extends Type { private bool $allowsNull; public function __construct(bool $nullable) { $this->allowsNull = $nullable; } public function isAssignable(Type $other): bool { if ($this->allowsNull && $other instanceof NullType) { return true; } if (!$other instanceof ObjectType) { return false; } return true; } public function name(): string { return 'object'; } public function allowsNull(): bool { return $this->allowsNull; } /** * @psalm-assert-if-true GenericObjectType $this */ public function isGenericObject(): bool { return true; } } type/src/type/FalseType.php 0000644 00000001560 15111337760 0011710 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/type. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Type; final class FalseType extends Type { public function isAssignable(Type $other): bool { if ($other instanceof self) { return true; } return $other instanceof SimpleType && $other->name() === 'bool' && $other->value() === false; } public function name(): string { return 'false'; } public function allowsNull(): bool { return false; } /** * @psalm-assert-if-true FalseType $this */ public function isFalse(): bool { return true; } } type/src/type/SimpleType.php 0000644 00000003466 15111337760 0012116 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/type. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Type; use function strtolower; final class SimpleType extends Type { private string $name; private bool $allowsNull; private mixed $value; public function __construct(string $name, bool $nullable, mixed $value = null) { $this->name = $this->normalize($name); $this->allowsNull = $nullable; $this->value = $value; } public function isAssignable(Type $other): bool { if ($this->allowsNull && $other instanceof NullType) { return true; } if ($this->name === 'bool' && $other->name() === 'true') { return true; } if ($this->name === 'bool' && $other->name() === 'false') { return true; } if ($other instanceof self) { return $this->name === $other->name; } return false; } public function name(): string { return $this->name; } public function allowsNull(): bool { return $this->allowsNull; } public function value(): mixed { return $this->value; } /** * @psalm-assert-if-true SimpleType $this */ public function isSimple(): bool { return true; } private function normalize(string $name): string { $name = strtolower($name); return match ($name) { 'boolean' => 'bool', 'real', 'double' => 'float', 'integer' => 'int', '[]' => 'array', default => $name, }; } } type/src/type/StaticType.php 0000644 00000002670 15111337760 0012110 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/type. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Type; use function is_subclass_of; use function strcasecmp; final class StaticType extends Type { private TypeName $className; private bool $allowsNull; public function __construct(TypeName $className, bool $allowsNull) { $this->className = $className; $this->allowsNull = $allowsNull; } public function isAssignable(Type $other): bool { if ($this->allowsNull && $other instanceof NullType) { return true; } if (!$other instanceof ObjectType) { return false; } if (0 === strcasecmp($this->className->qualifiedName(), $other->className()->qualifiedName())) { return true; } if (is_subclass_of($other->className()->qualifiedName(), $this->className->qualifiedName(), true)) { return true; } return false; } public function name(): string { return 'static'; } public function allowsNull(): bool { return $this->allowsNull; } /** * @psalm-assert-if-true StaticType $this */ public function isStatic(): bool { return true; } } type/src/type/ObjectType.php 0000644 00000003033 15111337760 0012061 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/type. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Type; use function is_subclass_of; use function strcasecmp; final class ObjectType extends Type { private TypeName $className; private bool $allowsNull; public function __construct(TypeName $className, bool $allowsNull) { $this->className = $className; $this->allowsNull = $allowsNull; } public function isAssignable(Type $other): bool { if ($this->allowsNull && $other instanceof NullType) { return true; } if ($other instanceof self) { if (0 === strcasecmp($this->className->qualifiedName(), $other->className->qualifiedName())) { return true; } if (is_subclass_of($other->className->qualifiedName(), $this->className->qualifiedName(), true)) { return true; } } return false; } public function name(): string { return $this->className->qualifiedName(); } public function allowsNull(): bool { return $this->allowsNull; } public function className(): TypeName { return $this->className; } /** * @psalm-assert-if-true ObjectType $this */ public function isObject(): bool { return true; } } type/src/type/IterableType.php 0000644 00000002743 15111337760 0012411 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/type. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Type; use function assert; use function class_exists; use function is_iterable; use ReflectionClass; final class IterableType extends Type { private bool $allowsNull; public function __construct(bool $nullable) { $this->allowsNull = $nullable; } /** * @throws RuntimeException */ public function isAssignable(Type $other): bool { if ($this->allowsNull && $other instanceof NullType) { return true; } if ($other instanceof self) { return true; } if ($other instanceof SimpleType) { return is_iterable($other->value()); } if ($other instanceof ObjectType) { $className = $other->className()->qualifiedName(); assert(class_exists($className)); return (new ReflectionClass($className))->isIterable(); } return false; } public function name(): string { return 'iterable'; } public function allowsNull(): bool { return $this->allowsNull; } /** * @psalm-assert-if-true IterableType $this */ public function isIterable(): bool { return true; } } type/src/type/UnknownType.php 0000644 00000001413 15111337760 0012312 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/type. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Type; final class UnknownType extends Type { public function isAssignable(Type $other): bool { return true; } public function name(): string { return 'unknown type'; } public function asString(): string { return ''; } public function allowsNull(): bool { return true; } /** * @psalm-assert-if-true UnknownType $this */ public function isUnknown(): bool { return true; } } type/src/type/VoidType.php 0000644 00000001306 15111337760 0011555 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/type. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Type; final class VoidType extends Type { public function isAssignable(Type $other): bool { return $other instanceof self; } public function name(): string { return 'void'; } public function allowsNull(): bool { return false; } /** * @psalm-assert-if-true VoidType $this */ public function isVoid(): bool { return true; } } type/src/type/NeverType.php 0000644 00000001312 15111337760 0011730 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/type. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Type; final class NeverType extends Type { public function isAssignable(Type $other): bool { return $other instanceof self; } public function name(): string { return 'never'; } public function allowsNull(): bool { return false; } /** * @psalm-assert-if-true NeverType $this */ public function isNever(): bool { return true; } } type/src/type/UnionType.php 0000644 00000005617 15111337760 0011755 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/type. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Type; use function count; use function implode; use function sort; final class UnionType extends Type { /** * @psalm-var non-empty-list<Type> */ private array $types; /** * @throws RuntimeException */ public function __construct(Type ...$types) { $this->ensureMinimumOfTwoTypes(...$types); $this->ensureOnlyValidTypes(...$types); $this->types = $types; } public function isAssignable(Type $other): bool { foreach ($this->types as $type) { if ($type->isAssignable($other)) { return true; } } return false; } public function asString(): string { return $this->name(); } public function name(): string { $types = []; foreach ($this->types as $type) { if ($type->isIntersection()) { $types[] = '(' . $type->name() . ')'; continue; } $types[] = $type->name(); } sort($types); return implode('|', $types); } public function allowsNull(): bool { foreach ($this->types as $type) { if ($type instanceof NullType) { return true; } } return false; } /** * @psalm-assert-if-true UnionType $this */ public function isUnion(): bool { return true; } public function containsIntersectionTypes(): bool { foreach ($this->types as $type) { if ($type->isIntersection()) { return true; } } return false; } /** * @psalm-return non-empty-list<Type> */ public function types(): array { return $this->types; } /** * @throws RuntimeException */ private function ensureMinimumOfTwoTypes(Type ...$types): void { if (count($types) < 2) { throw new RuntimeException( 'A union type must be composed of at least two types' ); } } /** * @throws RuntimeException */ private function ensureOnlyValidTypes(Type ...$types): void { foreach ($types as $type) { if ($type instanceof UnknownType) { throw new RuntimeException( 'A union type must not be composed of an unknown type' ); } if ($type instanceof VoidType) { throw new RuntimeException( 'A union type must not be composed of a void type' ); } } } } type/src/type/TrueType.php 0000644 00000001553 15111337760 0011577 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/type. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Type; final class TrueType extends Type { public function isAssignable(Type $other): bool { if ($other instanceof self) { return true; } return $other instanceof SimpleType && $other->name() === 'bool' && $other->value() === true; } public function name(): string { return 'true'; } public function allowsNull(): bool { return false; } /** * @psalm-assert-if-true TrueType $this */ public function isTrue(): bool { return true; } } type/src/type/IntersectionType.php 0000644 00000005353 15111337760 0013330 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/type. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Type; use function assert; use function count; use function implode; use function in_array; use function sort; final class IntersectionType extends Type { /** * @psalm-var non-empty-list<Type> */ private array $types; /** * @throws RuntimeException */ public function __construct(Type ...$types) { $this->ensureMinimumOfTwoTypes(...$types); $this->ensureOnlyValidTypes(...$types); $this->ensureNoDuplicateTypes(...$types); $this->types = $types; } public function isAssignable(Type $other): bool { return $other->isObject(); } public function asString(): string { return $this->name(); } public function name(): string { $types = []; foreach ($this->types as $type) { $types[] = $type->name(); } sort($types); return implode('&', $types); } public function allowsNull(): bool { return false; } /** * @psalm-assert-if-true IntersectionType $this */ public function isIntersection(): bool { return true; } /** * @psalm-return non-empty-list<Type> */ public function types(): array { return $this->types; } /** * @throws RuntimeException */ private function ensureMinimumOfTwoTypes(Type ...$types): void { if (count($types) < 2) { throw new RuntimeException( 'An intersection type must be composed of at least two types' ); } } /** * @throws RuntimeException */ private function ensureOnlyValidTypes(Type ...$types): void { foreach ($types as $type) { if (!$type->isObject()) { throw new RuntimeException( 'An intersection type can only be composed of interfaces and classes' ); } } } /** * @throws RuntimeException */ private function ensureNoDuplicateTypes(Type ...$types): void { $names = []; foreach ($types as $type) { assert($type instanceof ObjectType); $classQualifiedName = $type->className()->qualifiedName(); if (in_array($classQualifiedName, $names, true)) { throw new RuntimeException('An intersection type must not contain duplicate types'); } $names[] = $classQualifiedName; } } } type/src/type/MixedType.php 0000644 00000001432 15111337760 0011722 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/type. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Type; final class MixedType extends Type { public function isAssignable(Type $other): bool { return !$other instanceof VoidType; } public function asString(): string { return 'mixed'; } public function name(): string { return 'mixed'; } public function allowsNull(): bool { return true; } /** * @psalm-assert-if-true MixedType $this */ public function isMixed(): bool { return true; } } type/src/type/Type.php 0000644 00000010251 15111337760 0010732 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/type. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Type; use function gettype; use function strtolower; abstract class Type { public static function fromValue(mixed $value, bool $allowsNull): self { if ($allowsNull === false) { if ($value === true) { return new TrueType; } if ($value === false) { return new FalseType; } } $typeName = gettype($value); if ($typeName === 'object') { return new ObjectType(TypeName::fromQualifiedName($value::class), $allowsNull); } $type = self::fromName($typeName, $allowsNull); if ($type instanceof SimpleType) { $type = new SimpleType($typeName, $allowsNull, $value); } return $type; } public static function fromName(string $typeName, bool $allowsNull): self { return match (strtolower($typeName)) { 'callable' => new CallableType($allowsNull), 'true' => new TrueType, 'false' => new FalseType, 'iterable' => new IterableType($allowsNull), 'never' => new NeverType, 'null' => new NullType, 'object' => new GenericObjectType($allowsNull), 'unknown type' => new UnknownType, 'void' => new VoidType, 'array', 'bool', 'boolean', 'double', 'float', 'int', 'integer', 'real', 'resource', 'resource (closed)', 'string' => new SimpleType($typeName, $allowsNull), 'mixed' => new MixedType, default => new ObjectType(TypeName::fromQualifiedName($typeName), $allowsNull), }; } public function asString(): string { return ($this->allowsNull() ? '?' : '') . $this->name(); } /** * @psalm-assert-if-true CallableType $this */ public function isCallable(): bool { return false; } /** * @psalm-assert-if-true TrueType $this */ public function isTrue(): bool { return false; } /** * @psalm-assert-if-true FalseType $this */ public function isFalse(): bool { return false; } /** * @psalm-assert-if-true GenericObjectType $this */ public function isGenericObject(): bool { return false; } /** * @psalm-assert-if-true IntersectionType $this */ public function isIntersection(): bool { return false; } /** * @psalm-assert-if-true IterableType $this */ public function isIterable(): bool { return false; } /** * @psalm-assert-if-true MixedType $this */ public function isMixed(): bool { return false; } /** * @psalm-assert-if-true NeverType $this */ public function isNever(): bool { return false; } /** * @psalm-assert-if-true NullType $this */ public function isNull(): bool { return false; } /** * @psalm-assert-if-true ObjectType $this */ public function isObject(): bool { return false; } /** * @psalm-assert-if-true SimpleType $this */ public function isSimple(): bool { return false; } /** * @psalm-assert-if-true StaticType $this */ public function isStatic(): bool { return false; } /** * @psalm-assert-if-true UnionType $this */ public function isUnion(): bool { return false; } /** * @psalm-assert-if-true UnknownType $this */ public function isUnknown(): bool { return false; } /** * @psalm-assert-if-true VoidType $this */ public function isVoid(): bool { return false; } abstract public function isAssignable(self $other): bool; abstract public function name(): string; abstract public function allowsNull(): bool; } type/src/Parameter.php 0000644 00000001370 15111337760 0010752 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/type. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Type; final class Parameter { /** * @psalm-var non-empty-string */ private string $name; private Type $type; /** * @psalm-param non-empty-string $name */ public function __construct(string $name, Type $type) { $this->name = $name; $this->type = $type; } public function name(): string { return $this->name; } public function type(): Type { return $this->type; } } type/src/ReflectionMapper.php 0000644 00000012456 15111337760 0012300 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/type. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Type; use function assert; use ReflectionFunction; use ReflectionIntersectionType; use ReflectionMethod; use ReflectionNamedType; use ReflectionType; use ReflectionUnionType; final class ReflectionMapper { /** * @psalm-return list<Parameter> */ public function fromParameterTypes(ReflectionFunction|ReflectionMethod $functionOrMethod): array { $parameters = []; foreach ($functionOrMethod->getParameters() as $parameter) { $name = $parameter->getName(); assert($name !== ''); if (!$parameter->hasType()) { $parameters[] = new Parameter($name, new UnknownType); continue; } $type = $parameter->getType(); if ($type instanceof ReflectionNamedType) { $parameters[] = new Parameter( $name, $this->mapNamedType($type, $functionOrMethod) ); continue; } if ($type instanceof ReflectionUnionType) { $parameters[] = new Parameter( $name, $this->mapUnionType($type, $functionOrMethod) ); continue; } if ($type instanceof ReflectionIntersectionType) { $parameters[] = new Parameter( $name, $this->mapIntersectionType($type, $functionOrMethod) ); } } return $parameters; } public function fromReturnType(ReflectionFunction|ReflectionMethod $functionOrMethod): Type { if (!$this->hasReturnType($functionOrMethod)) { return new UnknownType; } $returnType = $this->returnType($functionOrMethod); assert($returnType instanceof ReflectionNamedType || $returnType instanceof ReflectionUnionType || $returnType instanceof ReflectionIntersectionType); if ($returnType instanceof ReflectionNamedType) { return $this->mapNamedType($returnType, $functionOrMethod); } if ($returnType instanceof ReflectionUnionType) { return $this->mapUnionType($returnType, $functionOrMethod); } if ($returnType instanceof ReflectionIntersectionType) { return $this->mapIntersectionType($returnType, $functionOrMethod); } } private function mapNamedType(ReflectionNamedType $type, ReflectionFunction|ReflectionMethod $functionOrMethod): Type { if ($functionOrMethod instanceof ReflectionMethod && $type->getName() === 'self') { return ObjectType::fromName( $functionOrMethod->getDeclaringClass()->getName(), $type->allowsNull() ); } if ($functionOrMethod instanceof ReflectionMethod && $type->getName() === 'static') { return new StaticType( TypeName::fromReflection($functionOrMethod->getDeclaringClass()), $type->allowsNull() ); } if ($type->getName() === 'mixed') { return new MixedType; } if ($functionOrMethod instanceof ReflectionMethod && $type->getName() === 'parent') { return ObjectType::fromName( $functionOrMethod->getDeclaringClass()->getParentClass()->getName(), $type->allowsNull() ); } return Type::fromName( $type->getName(), $type->allowsNull() ); } private function mapUnionType(ReflectionUnionType $type, ReflectionFunction|ReflectionMethod $functionOrMethod): Type { $types = []; foreach ($type->getTypes() as $_type) { assert($_type instanceof ReflectionNamedType || $_type instanceof ReflectionIntersectionType); if ($_type instanceof ReflectionNamedType) { $types[] = $this->mapNamedType($_type, $functionOrMethod); continue; } $types[] = $this->mapIntersectionType($_type, $functionOrMethod); } return new UnionType(...$types); } private function mapIntersectionType(ReflectionIntersectionType $type, ReflectionFunction|ReflectionMethod $functionOrMethod): Type { $types = []; foreach ($type->getTypes() as $_type) { assert($_type instanceof ReflectionNamedType); $types[] = $this->mapNamedType($_type, $functionOrMethod); } return new IntersectionType(...$types); } private function hasReturnType(ReflectionFunction|ReflectionMethod $functionOrMethod): bool { if ($functionOrMethod->hasReturnType()) { return true; } return $functionOrMethod->hasTentativeReturnType(); } private function returnType(ReflectionFunction|ReflectionMethod $functionOrMethod): ?ReflectionType { if ($functionOrMethod->hasReturnType()) { return $functionOrMethod->getReturnType(); } return $functionOrMethod->getTentativeReturnType(); } } type/README.md 0000644 00000001754 15111337760 0007017 0 ustar 00 [](https://packagist.org/packages/sebastian/type) [](https://github.com/sebastianbergmann/type/actions) [](https://shepherd.dev/github/sebastianbergmann/type) [](https://codecov.io/gh/sebastianbergmann/type) # sebastian/type Collection of value objects that represent the types of the PHP type system. ## Installation You can add this library as a local, per-project dependency to your project using [Composer](https://getcomposer.org/): ``` composer require sebastian/type ``` If you only need this library during development, for instance to run your project's test suite, then you should add it as a development-time dependency: ``` composer require --dev sebastian/type ``` type/LICENSE 0000644 00000002773 15111337760 0006547 0 ustar 00 BSD 3-Clause License Copyright (c) 2019-2023, Sebastian Bergmann All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. type/ChangeLog.md 0000644 00000013217 15111337760 0007706 0 ustar 00 # ChangeLog All notable changes are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles. ## [4.0.0] - 2023-02-03 ### Removed * This component is no longer supported on PHP 7.3, PHP 7.4 and PHP 8.0 ## [3.2.1] - 2023-02-03 ### Fixed * [#28](https://github.com/sebastianbergmann/type/pull/28): Potential undefined offset warning/notice ## [3.2.0] - 2022-09-12 ### Added * [#25](https://github.com/sebastianbergmann/type/issues/25): Support Disjunctive Normal Form types * Added `ReflectionMapper::fromParameterTypes()` * Added `IntersectionType::types()` and `UnionType::types()` * Added `UnionType::containsIntersectionTypes()` ## [3.1.0] - 2022-08-29 ### Added * [#21](https://github.com/sebastianbergmann/type/issues/21): Support `true` as stand-alone type ## [3.0.0] - 2022-03-15 ### Added * Support for intersection types introduced in PHP 8.1 * Support for the `never` return type introduced in PHP 8.1 * Added `Type::isCallable()`, `Type::isGenericObject()`, `Type::isIterable()`, `Type::isMixed()`, `Type::isNever()`, `Type::isNull()`, `Type::isObject()`, `Type::isSimple()`, `Type::isStatic()`, `Type::isUnion()`, `Type::isUnknown()`, and `Type::isVoid()` ### Changed * Renamed `ReflectionMapper::fromMethodReturnType(ReflectionMethod $method)` to `ReflectionMapper::fromReturnType(ReflectionFunctionAbstract $functionOrMethod)` ### Removed * Removed `Type::getReturnTypeDeclaration()` (use `Type::asString()` instead and prefix its result with `': '`) * Removed `TypeName::getNamespaceName()` (use `TypeName::namespaceName()` instead) * Removed `TypeName::getSimpleName()` (use `TypeName::simpleName()` instead) * Removed `TypeName::getQualifiedName()` (use `TypeName::qualifiedName()` instead) ## [2.3.4] - 2021-06-15 ### Fixed * Fixed regression introduced in 2.3.3 ## [2.3.3] - 2021-06-15 [YANKED] ### Fixed * [#15](https://github.com/sebastianbergmann/type/issues/15): "false" pseudo type is not handled properly ## [2.3.2] - 2021-06-04 ### Fixed * Fixed handling of tentatively declared return types ## [2.3.1] - 2020-10-26 ### Fixed * `SebastianBergmann\Type\Exception` now correctly extends `\Throwable` ## [2.3.0] - 2020-10-06 ### Added * [#14](https://github.com/sebastianbergmann/type/issues/14): Support for `static` return type that is introduced in PHP 8 ## [2.2.2] - 2020-09-28 ### Changed * Changed PHP version constraint in `composer.json` from `^7.3 || ^8.0` to `>=7.3` ## [2.2.1] - 2020-07-05 ### Fixed * Fixed handling of `mixed` type in `ReflectionMapper::fromMethodReturnType()` ## [2.2.0] - 2020-07-05 ### Added * Added `MixedType` object for representing PHP 8's `mixed` type ## [2.1.1] - 2020-06-26 ### Added * This component is now supported on PHP 8 ## [2.1.0] - 2020-06-01 ### Added * Added `UnionType` object for representing PHP 8's Union Types * Added `ReflectionMapper::fromMethodReturnType()` for mapping `\ReflectionMethod::getReturnType()` to a `Type` object * Added `Type::name()` for retrieving the name of a type * Added `Type::asString()` for retrieving a textual representation of a type ### Changed * Deprecated `Type::getReturnTypeDeclaration()` (use `Type::asString()` instead and prefix its result with `': '`) * Deprecated `TypeName::getNamespaceName()` (use `TypeName::namespaceName()` instead) * Deprecated `TypeName::getSimpleName()` (use `TypeName::simpleName()` instead) * Deprecated `TypeName::getQualifiedName()` (use `TypeName::qualifiedName()` instead) ## [2.0.0] - 2020-02-07 ### Removed * This component is no longer supported on PHP 7.2 ## [1.1.3] - 2019-07-02 ### Fixed * Fixed class name comparison in `ObjectType` to be case-insensitive ## [1.1.2] - 2019-06-19 ### Fixed * Fixed handling of `object` type ## [1.1.1] - 2019-06-08 ### Fixed * Fixed autoloading of `callback_function.php` fixture file ## [1.1.0] - 2019-06-07 ### Added * Added support for `callable` type * Added support for `iterable` type ## [1.0.0] - 2019-06-06 * Initial release based on [code contributed by Michel Hartmann to PHPUnit](https://github.com/sebastianbergmann/phpunit/pull/3673) [4.0.0]: https://github.com/sebastianbergmann/type/compare/3.2.1...4.0.0 [3.2.1]: https://github.com/sebastianbergmann/type/compare/3.2.0...3.2.1 [3.2.0]: https://github.com/sebastianbergmann/type/compare/3.1.0...3.2.0 [3.1.0]: https://github.com/sebastianbergmann/type/compare/3.0.0...3.1.0 [3.0.0]: https://github.com/sebastianbergmann/type/compare/2.3.4...3.0.0 [2.3.4]: https://github.com/sebastianbergmann/type/compare/ca39369c41313ed12c071ed38ecda8fcdb248859...2.3.4 [2.3.3]: https://github.com/sebastianbergmann/type/compare/2.3.2...ca39369c41313ed12c071ed38ecda8fcdb248859 [2.3.2]: https://github.com/sebastianbergmann/type/compare/2.3.1...2.3.2 [2.3.1]: https://github.com/sebastianbergmann/type/compare/2.3.0...2.3.1 [2.3.0]: https://github.com/sebastianbergmann/type/compare/2.2.2...2.3.0 [2.2.2]: https://github.com/sebastianbergmann/type/compare/2.2.1...2.2.2 [2.2.1]: https://github.com/sebastianbergmann/type/compare/2.2.0...2.2.1 [2.2.0]: https://github.com/sebastianbergmann/type/compare/2.1.1...2.2.0 [2.1.1]: https://github.com/sebastianbergmann/type/compare/2.1.0...2.1.1 [2.1.0]: https://github.com/sebastianbergmann/type/compare/2.0.0...2.1.0 [2.0.0]: https://github.com/sebastianbergmann/type/compare/1.1.3...2.0.0 [1.1.3]: https://github.com/sebastianbergmann/type/compare/1.1.2...1.1.3 [1.1.2]: https://github.com/sebastianbergmann/type/compare/1.1.1...1.1.2 [1.1.1]: https://github.com/sebastianbergmann/type/compare/1.1.0...1.1.1 [1.1.0]: https://github.com/sebastianbergmann/type/compare/1.0.0...1.1.0 [1.0.0]: https://github.com/sebastianbergmann/type/compare/ff74aa41746bd8d10e931843ebf37d42da513ede...1.0.0 type/composer.json 0000644 00000002251 15111337760 0010253 0 ustar 00 { "name": "sebastian/type", "description": "Collection of value objects that represent the types of the PHP type system", "type": "library", "homepage": "https://github.com/sebastianbergmann/type", "license": "BSD-3-Clause", "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "lead" } ], "support": { "issues": "https://github.com/sebastianbergmann/type/issues" }, "prefer-stable": true, "require": { "php": ">=8.1" }, "require-dev": { "phpunit/phpunit": "^10.0" }, "config": { "platform": { "php": "8.1.0" }, "optimize-autoloader": true, "sort-packages": true }, "autoload": { "classmap": [ "src/" ] }, "autoload-dev": { "classmap": [ "tests/_fixture" ], "files": [ "tests/_fixture/callback_function.php", "tests/_fixture/functions_that_declare_return_types.php" ] }, "extra": { "branch-alias": { "dev-main": "4.0-dev" } } } type/SECURITY.md 0000644 00000001120 15111337760 0007314 0 ustar 00 # 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 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.** ## Security Contact Information After the above, if you still would like to report a security vulnerability, please email `sebastian@phpunit.de`. type/infection.json 0000644 00000000256 15111337760 0010405 0 ustar 00 { "source": { "directories": [ "src" ] }, "mutators": { "@default": true }, "minMsi": 100, "minCoveredMsi": 100 } lines-of-code/src/Exception/Exception.php 0000644 00000000561 15111337760 0014372 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/lines-of-code. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\LinesOfCode; use Throwable; interface Exception extends Throwable { } lines-of-code/src/Exception/NegativeValueException.php 0000644 00000000663 15111337760 0017055 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/lines-of-code. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\LinesOfCode; use InvalidArgumentException; final class NegativeValueException extends InvalidArgumentException implements Exception { } lines-of-code/src/Exception/RuntimeException.php 0000644 00000000607 15111337760 0015737 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/lines-of-code. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\LinesOfCode; final class RuntimeException extends \RuntimeException implements Exception { } lines-of-code/src/Exception/IllogicalValuesException.php 0000644 00000000641 15111337760 0017371 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/lines-of-code. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\LinesOfCode; use LogicException; final class IllogicalValuesException extends LogicException implements Exception { } lines-of-code/src/LinesOfCode.php 0000644 00000006536 15111337760 0012640 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/lines-of-code. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\LinesOfCode; /** * @psalm-immutable */ final class LinesOfCode { /** * @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'); } if ($linesOfCode - $commentLinesOfCode !== $nonCommentLinesOfCode) { throw new IllogicalValuesException('$linesOfCode !== $commentLinesOfCode + $nonCommentLinesOfCode'); } $this->linesOfCode = $linesOfCode; $this->commentLinesOfCode = $commentLinesOfCode; $this->nonCommentLinesOfCode = $nonCommentLinesOfCode; $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; } public function plus(self $other): self { return new self( $this->linesOfCode() + $other->linesOfCode(), $this->commentLinesOfCode() + $other->commentLinesOfCode(), $this->nonCommentLinesOfCode() + $other->nonCommentLinesOfCode(), $this->logicalLinesOfCode() + $other->logicalLinesOfCode(), ); } } lines-of-code/src/LineCountingVisitor.php 0000644 00000004434 15111337760 0014457 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/lines-of-code. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\LinesOfCode; use function array_merge; use function array_unique; use function assert; use function count; use PhpParser\Comment; use PhpParser\Node; use PhpParser\Node\Expr; use PhpParser\NodeVisitorAbstract; final class LineCountingVisitor extends NodeVisitorAbstract { /** * @psalm-var non-negative-int */ private readonly int $linesOfCode; /** * @var Comment[] */ private array $comments = []; /** * @var int[] */ private array $linesWithStatements = []; /** * @psalm-param non-negative-int $linesOfCode */ public function __construct(int $linesOfCode) { $this->linesOfCode = $linesOfCode; } public function enterNode(Node $node): void { $this->comments = array_merge($this->comments, $node->getComments()); if (!$node instanceof Expr) { return; } $this->linesWithStatements[] = $node->getStartLine(); } public function result(): LinesOfCode { $commentLinesOfCode = 0; foreach ($this->comments() as $comment) { $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, $nonCommentLinesOfCode, $logicalLinesOfCode, ); } /** * @return Comment[] */ private function comments(): array { $comments = []; foreach ($this->comments as $comment) { $comments[$comment->getStartLine() . '_' . $comment->getStartTokenPos() . '_' . $comment->getEndLine() . '_' . $comment->getEndTokenPos()] = $comment; } return $comments; } } lines-of-code/src/Counter.php 0000644 00000004653 15111337760 0012123 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/lines-of-code. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\LinesOfCode; 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 { /** * @throws RuntimeException */ public function countInSourceFile(string $sourceFile): LinesOfCode { return $this->countInSourceString(file_get_contents($sourceFile)); } /** * @throws RuntimeException */ public function countInSourceString(string $source): LinesOfCode { $linesOfCode = substr_count($source, "\n"); if ($linesOfCode === 0 && !empty($source)) { $linesOfCode = 1; } assert($linesOfCode >= 0); try { $nodes = $this->parser()->parse($source); assert($nodes !== null); return $this->countInAbstractSyntaxTree($linesOfCode, $nodes); // @codeCoverageIgnoreStart } catch (Error $error) { throw new RuntimeException( $error->getMessage(), $error->getCode(), $error, ); } // @codeCoverageIgnoreEnd } /** * @psalm-param non-negative-int $linesOfCode * * @param Node[] $nodes * * @throws RuntimeException */ public function countInAbstractSyntaxTree(int $linesOfCode, array $nodes): LinesOfCode { $traverser = new NodeTraverser; $visitor = new LineCountingVisitor($linesOfCode); $traverser->addVisitor($visitor); try { /* @noinspection UnusedFunctionResultInspection */ $traverser->traverse($nodes); // @codeCoverageIgnoreStart } catch (Error $error) { throw new RuntimeException( $error->getMessage(), $error->getCode(), $error, ); } // @codeCoverageIgnoreEnd return $visitor->result(); } private function parser(): Parser { return (new ParserFactory)->create(ParserFactory::PREFER_PHP7, new Lexer); } } lines-of-code/src/error_log 0000644 00000001272 15111337760 0011702 0 ustar 00 [19-Nov-2025 01:14:08 UTC] PHP Fatal error: Uncaught Error: Class "PhpParser\NodeVisitorAbstract" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/lines-of-code/src/LineCountingVisitor.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/lines-of-code/src/LineCountingVisitor.php on line 21 [19-Nov-2025 09:04:49 UTC] PHP Fatal error: Uncaught Error: Class "PhpParser\NodeVisitorAbstract" not found in /home/fluxyjvi/public_html/project/vendor/sebastian/lines-of-code/src/LineCountingVisitor.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/sebastian/lines-of-code/src/LineCountingVisitor.php on line 21 lines-of-code/README.md 0000644 00000002075 15111337760 0010457 0 ustar 00 [](https://packagist.org/packages/sebastian/lines-of-code) [](https://github.com/sebastianbergmann/lines-of-code/actions) [](https://shepherd.dev/github/sebastianbergmann/lines-of-code) [](https://codecov.io/gh/sebastianbergmann/lines-of-code) # sebastian/lines-of-code Library for counting the lines of code in PHP source code. ## Installation You can add this library as a local, per-project dependency to your project using [Composer](https://getcomposer.org/): ``` composer require sebastian/lines-of-code ``` If you only need this library during development, for instance to run your project's test suite, then you should add it as a development-time dependency: ``` composer require --dev sebastian/lines-of-code ``` lines-of-code/LICENSE 0000644 00000002773 15111337760 0010212 0 ustar 00 BSD 3-Clause License Copyright (c) 2020-2023, Sebastian Bergmann All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. lines-of-code/ChangeLog.md 0000644 00000002477 15111337760 0011357 0 ustar 00 # ChangeLog All notable changes are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles. ## [2.0.1] - 2023-08-31 ### Changed * Improved type information ## [2.0.0] - 2023-02-03 ### Removed * This component is no longer supported on PHP 7.3, PHP 7.4 and PHP 8.0 ## [1.0.3] - 2020-11-28 ### Fixed * Files that do not contain a newline were not handled correctly ### Changed * A line of code is no longer considered to be a Logical Line of Code if it does not contain an `Expr` node ## [1.0.2] - 2020-10-26 ### Fixed * `SebastianBergmann\LinesOfCode\Exception` now correctly extends `\Throwable` ## [1.0.1] - 2020-09-28 ### Changed * Changed PHP version constraint in `composer.json` from `^7.3 || ^8.0` to `>=7.3` ## [1.0.0] - 2020-07-22 * Initial release [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 [1.0.1]: https://github.com/sebastianbergmann/lines-of-code/compare/1.0.0...1.0.1 [1.0.0]: https://github.com/sebastianbergmann/lines-of-code/compare/f959e71f00e591288acc024afe9cb966c6cf9bd6...1.0.0 lines-of-code/composer.json 0000644 00000002076 15111337760 0011723 0 ustar 00 { "name": "sebastian/lines-of-code", "description": "Library for counting the lines of code in PHP source code", "type": "library", "homepage": "https://github.com/sebastianbergmann/lines-of-code", "license": "BSD-3-Clause", "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "lead" } ], "support": { "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" }, "require-dev": { "phpunit/phpunit": "^10.0" }, "config": { "platform": { "php": "8.1" }, "optimize-autoloader": true, "sort-packages": true }, "autoload": { "classmap": [ "src/" ] }, "extra": { "branch-alias": { "dev-main": "2.0-dev" } } } lines-of-code/SECURITY.md 0000644 00000003565 15111337760 0010776 0 ustar 00 # Security Policy 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. **Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.** 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. complexity/src/Visitor/CyclomaticComplexityCalculatingVisitor.php 0000644 00000003205 15111337760 0021600 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/complexity. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Complexity; use PhpParser\Node; use PhpParser\Node\Expr\BinaryOp\BooleanAnd; use PhpParser\Node\Expr\BinaryOp\BooleanOr; use PhpParser\Node\Expr\BinaryOp\LogicalAnd; use PhpParser\Node\Expr\BinaryOp\LogicalOr; use PhpParser\Node\Expr\Ternary; use PhpParser\Node\Stmt\Case_; use PhpParser\Node\Stmt\Catch_; use PhpParser\Node\Stmt\ElseIf_; use PhpParser\Node\Stmt\For_; use PhpParser\Node\Stmt\Foreach_; use PhpParser\Node\Stmt\If_; use PhpParser\Node\Stmt\While_; use PhpParser\NodeVisitorAbstract; final class CyclomaticComplexityCalculatingVisitor extends NodeVisitorAbstract { /** * @psalm-var positive-int */ private int $cyclomaticComplexity = 1; public function enterNode(Node $node): void { switch ($node::class) { case BooleanAnd::class: case BooleanOr::class: case Case_::class: case Catch_::class: case ElseIf_::class: case For_::class: case Foreach_::class: case If_::class: case LogicalAnd::class: case LogicalOr::class: case Ternary::class: case While_::class: $this->cyclomaticComplexity++; } } /** * @psalm-return positive-int */ public function cyclomaticComplexity(): int { return $this->cyclomaticComplexity; } } complexity/src/Visitor/ComplexityCalculatingVisitor.php 0000644 00000006670 15111337760 0017601 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/complexity. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ 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; final class ComplexityCalculatingVisitor extends NodeVisitorAbstract { /** * @psalm-var list<Complexity> */ private array $result = []; private bool $shortCircuitTraversal; public function __construct(bool $shortCircuitTraversal) { $this->shortCircuitTraversal = $shortCircuitTraversal; } public function enterNode(Node $node): ?int { if (!$node instanceof ClassMethod && !$node instanceof Function_) { return null; } 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); } $statements = $node->getStmts(); assert(is_array($statements)); $this->result[] = new Complexity( $name, $this->cyclomaticComplexity($statements), ); if ($this->shortCircuitTraversal) { return NodeTraverser::DONT_TRAVERSE_CHILDREN; } return null; } public function result(): ComplexityCollection { return ComplexityCollection::fromList(...$this->result); } /** * @param Stmt[] $statements * * @psalm-return positive-int */ private function cyclomaticComplexity(array $statements): int { $traverser = new NodeTraverser; $cyclomaticComplexityCalculatingVisitor = new CyclomaticComplexityCalculatingVisitor; $traverser->addVisitor($cyclomaticComplexityCalculatingVisitor); /* @noinspection UnusedFunctionResultInspection */ $traverser->traverse($statements); 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); $functionName = $node->namespacedName->toString(); assert($functionName !== ''); return $functionName; } } complexity/src/Complexity/ComplexityCollectionIterator.php 0000644 00000002027 15111337760 0020266 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/complexity. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Complexity; use Iterator; final class ComplexityCollectionIterator implements Iterator { /** * @psalm-var list<Complexity> */ private readonly array $items; private int $position = 0; public function __construct(ComplexityCollection $items) { $this->items = $items->asArray(); } public function rewind(): void { $this->position = 0; } public function valid(): bool { return isset($this->items[$this->position]); } public function key(): int { return $this->position; } public function current(): Complexity { return $this->items[$this->position]; } public function next(): void { $this->position++; } } complexity/src/Complexity/Complexity.php 0000644 00000002473 15111337760 0014545 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/complexity. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Complexity; use function str_contains; /** * @psalm-immutable */ final class Complexity { /** * @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, '::'); } } complexity/src/Complexity/ComplexityCollection.php 0000644 00000004701 15111337760 0016555 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/complexity. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Complexity; use function array_filter; use function array_merge; use function array_values; use function count; use Countable; use IteratorAggregate; /** * @psalm-immutable */ final class ComplexityCollection implements Countable, IteratorAggregate { /** * @psalm-var list<Complexity> */ private readonly array $items; public static function fromList(Complexity ...$items): self { return new self($items); } /** * @psalm-param list<Complexity> $items */ private function __construct(array $items) { $this->items = $items; } /** * @psalm-return list<Complexity> */ public function asArray(): array { return $this->items; } public function getIterator(): ComplexityCollectionIterator { return new ComplexityCollectionIterator($this); } /** * @psalm-return non-negative-int */ public function count(): int { return count($this->items); } public function isEmpty(): bool { return empty($this->items); } /** * @psalm-return non-negative-int */ public function cyclomaticComplexity(): int { $cyclomaticComplexity = 0; foreach ($this as $item) { $cyclomaticComplexity += $item->cyclomaticComplexity(); } 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(), ), ); } } complexity/src/Exception/Exception.php 0000644 00000000555 15111337760 0014146 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/complexity. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Complexity; use Throwable; interface Exception extends Throwable { } complexity/src/Exception/RuntimeException.php 0000644 00000000603 15111337760 0015504 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/complexity. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Complexity; final class RuntimeException extends \RuntimeException implements Exception { } complexity/src/Calculator.php 0000644 00000004716 15111337760 0012346 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of sebastian/complexity. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ 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 { /** * @throws RuntimeException */ public function calculateForSourceFile(string $sourceFile): ComplexityCollection { return $this->calculateForSourceString(file_get_contents($sourceFile)); } /** * @throws RuntimeException */ public function calculateForSourceString(string $source): ComplexityCollection { try { $nodes = $this->parser()->parse($source); assert($nodes !== null); return $this->calculateForAbstractSyntaxTree($nodes); // @codeCoverageIgnoreStart } catch (Error $error) { throw new RuntimeException( $error->getMessage(), $error->getCode(), $error, ); } // @codeCoverageIgnoreEnd } /** * @param Node[] $nodes * * @throws RuntimeException */ public function calculateForAbstractSyntaxTree(array $nodes): ComplexityCollection { $traverser = new NodeTraverser; $complexityCalculatingVisitor = new ComplexityCalculatingVisitor(true); $traverser->addVisitor(new NameResolver); $traverser->addVisitor(new ParentConnectingVisitor); $traverser->addVisitor($complexityCalculatingVisitor); try { /* @noinspection UnusedFunctionResultInspection */ $traverser->traverse($nodes); // @codeCoverageIgnoreStart } catch (Error $error) { throw new RuntimeException( $error->getMessage(), $error->getCode(), $error, ); } // @codeCoverageIgnoreEnd return $complexityCalculatingVisitor->result(); } private function parser(): Parser { return (new ParserFactory)->create(ParserFactory::PREFER_PHP7, new Lexer); } } complexity/README.md 0000644 00000002033 15111337760 0010222 0 ustar 00 [](https://packagist.org/packages/sebastian/complexity) [](https://github.com/sebastianbergmann/complexity/actions) [](https://shepherd.dev/github/sebastianbergmann/complexity) [](https://codecov.io/gh/sebastianbergmann/complexity) # sebastian/complexity Library for calculating the complexity of PHP code units. ## Installation You can add this library as a local, per-project dependency to your project using [Composer](https://getcomposer.org/): ``` composer require sebastian/complexity ``` If you only need this library during development, for instance to run your project's test suite, then you should add it as a development-time dependency: ``` composer require --dev sebastian/complexity ``` complexity/LICENSE 0000644 00000002773 15111337760 0007763 0 ustar 00 BSD 3-Clause License Copyright (c) 2020-2023, Sebastian Bergmann All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. complexity/ChangeLog.md 0000644 00000003222 15111337760 0011115 0 ustar 00 # ChangeLog All notable changes are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles. ## [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 * This component is no longer supported on PHP 7.3, PHP 7.4 and PHP 8.0 ## [2.0.2] - 2020-10-26 ### Fixed * `SebastianBergmann\Complexity\Exception` now correctly extends `\Throwable` ## [2.0.1] - 2020-09-28 ### Changed * Changed PHP version constraint in `composer.json` from `^7.3 || ^8.0` to `>=7.3` ## [2.0.0] - 2020-07-25 ### Removed * The `ParentConnectingVisitor` has been removed (it should have been marked as `@internal`) ## [1.0.0] - 2020-07-22 * Initial release [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 [2.0.0]: https://github.com/sebastianbergmann/complexity/compare/1.0.0...2.0.0 [1.0.0]: https://github.com/sebastianbergmann/complexity/compare/70ee0ad32d9e2be3f85beffa3e2eb474193f2487...1.0.0 complexity/composer.json 0000644 00000002063 15111337760 0011470 0 ustar 00 { "name": "sebastian/complexity", "description": "Library for calculating the complexity of PHP code units", "type": "library", "homepage": "https://github.com/sebastianbergmann/complexity", "license": "BSD-3-Clause", "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "lead" } ], "support": { "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" }, "require-dev": { "phpunit/phpunit": "^10.0" }, "config": { "platform": { "php": "8.1.0" }, "optimize-autoloader": true, "sort-packages": true }, "autoload": { "classmap": [ "src/" ] }, "extra": { "branch-alias": { "dev-main": "3.1-dev" } } } complexity/SECURITY.md 0000644 00000003565 15111337760 0010547 0 ustar 00 # Security Policy 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. **Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.** 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.