From b9a58dde95004b80c6c4bc827b8c6d085f341352 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 21 Jan 2025 15:00:20 +0300 Subject: [PATCH 1/5] 1 --- composer.json | 2 +- .../Stream/FilesystemStreamProxy.php | 4 +- src/Collector/Stream/HttpStreamProxy.php | 7 ++- src/Debugger.php | 3 - src/Helper/BacktraceIgnoreMatcher.php | 54 ++++++++---------- .../Helper/BacktraceIgnoreMatcherTest.php | 57 ++++--------------- 6 files changed, 43 insertions(+), 84 deletions(-) diff --git a/composer.json b/composer.json index fa8af63c..b9752ef5 100644 --- a/composer.json +++ b/composer.json @@ -40,7 +40,7 @@ "yiisoft/files": "^2.0", "yiisoft/profiler": "^3.0", "yiisoft/proxy": "^1.0.1", - "yiisoft/strings": "^2.2", + "yiisoft/strings": "^2.5", "yiisoft/var-dumper": "^1.7" }, "require-dev": { diff --git a/src/Collector/Stream/FilesystemStreamProxy.php b/src/Collector/Stream/FilesystemStreamProxy.php index 528c9321..11cb9b28 100644 --- a/src/Collector/Stream/FilesystemStreamProxy.php +++ b/src/Collector/Stream/FilesystemStreamProxy.php @@ -105,8 +105,8 @@ public static function unregister(): void private function isIgnored(): bool { $backtrace = debug_backtrace(); - return BacktraceIgnoreMatcher::isIgnoredByClass($backtrace, self::$ignoredClasses) - || BacktraceIgnoreMatcher::isIgnoredByFile($backtrace, self::$ignoredPathPatterns); + return BacktraceIgnoreMatcher::matchesClass($backtrace[3], self::$ignoredClasses) + || BacktraceIgnoreMatcher::matchesFile($backtrace[3], self::$ignoredPathPatterns); } public function stream_open(string $path, string $mode, int $options, ?string &$opened_path): bool diff --git a/src/Collector/Stream/HttpStreamProxy.php b/src/Collector/Stream/HttpStreamProxy.php index eea15bd9..f2e96339 100644 --- a/src/Collector/Stream/HttpStreamProxy.php +++ b/src/Collector/Stream/HttpStreamProxy.php @@ -5,6 +5,7 @@ namespace Yiisoft\Yii\Debug\Collector\Stream; use Yiisoft\Strings\CombinedRegexp; +use Yiisoft\Strings\StringHelper; use Yiisoft\Yii\Debug\Helper\BacktraceIgnoreMatcher; use Yiisoft\Yii\Debug\Helper\StreamWrapper\StreamWrapper; use Yiisoft\Yii\Debug\Helper\StreamWrapper\StreamWrapperInterface; @@ -303,12 +304,12 @@ public function url_stat(string $path, int $flags): array|false private function isIgnored(string $url): bool { - if (BacktraceIgnoreMatcher::doesStringMatchPattern($url, self::$ignoredUrls)) { + if (StringHelper::matchAnyRegex($url, self::$ignoredUrls)) { return true; } $backtrace = debug_backtrace(); - return BacktraceIgnoreMatcher::isIgnoredByClass($backtrace, self::$ignoredClasses) - || BacktraceIgnoreMatcher::isIgnoredByFile($backtrace, self::$ignoredPathPatterns); + return BacktraceIgnoreMatcher::matchesClass($backtrace[3], self::$ignoredClasses) + || BacktraceIgnoreMatcher::matchesFile($backtrace[3], self::$ignoredPathPatterns); } } diff --git a/src/Debugger.php b/src/Debugger.php index 38cf267f..f9c0795c 100644 --- a/src/Debugger.php +++ b/src/Debugger.php @@ -13,9 +13,6 @@ use Yiisoft\Yii\Debug\StartupPolicy\Debugger\DebuggerStartupPolicyInterface; use Yiisoft\Yii\Debug\Storage\StorageInterface; -/** - * @psalm-type BacktraceType = list - */ final class Debugger { /** diff --git a/src/Helper/BacktraceIgnoreMatcher.php b/src/Helper/BacktraceIgnoreMatcher.php index 59f0dc9d..121feb82 100644 --- a/src/Helper/BacktraceIgnoreMatcher.php +++ b/src/Helper/BacktraceIgnoreMatcher.php @@ -4,50 +4,44 @@ namespace Yiisoft\Yii\Debug\Helper; -use Yiisoft\Strings\CombinedRegexp; -use Yiisoft\Yii\Debug\Debugger; +use Yiisoft\Strings\StringHelper; + +use function in_array; /** - * All backtrace parameters should contain at least 4 elements in the following order: - * 0 – Called method - * 1 – Proxy - * 2 – Real using place / Composer\ClassLoader include function - * 3 – Whatever / Composer\ClassLoader + * `BacktraceMatcher` provides methods to match backtrace items returned by the PHP function `debug_backtrace()`. + * + * @see https://www.php.net/manual/function.debug-backtrace.php * - * @psalm-import-type BacktraceType from Debugger + * @psalm-type TBacktraceItem = array{ + * file?: string, + * line?: int, + * function?: string, + * class?: class-string, + * object?: object, + * type?: string, + * args?:array, + * } */ final class BacktraceIgnoreMatcher { /** * @param string[] $patterns - * @psalm-param BacktraceType $backtrace + * @psalm-param TBacktraceItem $backtraceItem */ - public static function isIgnoredByFile(array $backtrace, array $patterns): bool + public static function matchesFile(array $backtraceItem, array $patterns): bool { - if (!isset($backtrace[2]['file'])) { - return false; - } - $path = $backtrace[2]['file']; - - return self::doesStringMatchPattern($path, $patterns); + $path = $backtraceItem['file'] ?? null; + return $path !== null && StringHelper::matchAnyRegex($path, $patterns); } /** - * @psalm-param BacktraceType $backtrace - */ - public static function isIgnoredByClass(array $backtrace, array $classes): bool - { - return isset($backtrace[3]['class']) && in_array($backtrace[3]['class'], $classes, true); - } - - /** - * @param string[] $patterns + * @param string[] $classes + * @psalm-param TBacktraceItem $backtraceItem */ - public static function doesStringMatchPattern(string $string, array $patterns): bool + public static function matchesClass(array $backtraceItem, array $classes): bool { - if (empty($patterns)) { - return false; - } - return (new CombinedRegexp($patterns))->matches($string); + $class = $backtraceItem['class'] ?? null; + return $class !== null && in_array($class, $classes, true); } } diff --git a/tests/Unit/Helper/BacktraceIgnoreMatcherTest.php b/tests/Unit/Helper/BacktraceIgnoreMatcherTest.php index 8176a5eb..44633453 100644 --- a/tests/Unit/Helper/BacktraceIgnoreMatcherTest.php +++ b/tests/Unit/Helper/BacktraceIgnoreMatcherTest.php @@ -15,13 +15,11 @@ public function testClassIgnorance(): void { $backtrace = debug_backtrace(); - $this->assertFalse(BacktraceIgnoreMatcher::isIgnoredByClass($backtrace, [self::class])); - $this->assertFalse(BacktraceIgnoreMatcher::isIgnoredByClass($backtrace, [stdClass::class])); + $this->assertFalse(BacktraceIgnoreMatcher::matchesClass($backtrace[3], [self::class])); + $this->assertFalse(BacktraceIgnoreMatcher::matchesClass($backtrace[3], [stdClass::class])); - $backtrace[3] = $backtrace[0]; - - $this->assertTrue(BacktraceIgnoreMatcher::isIgnoredByClass($backtrace, [self::class])); - $this->assertFalse(BacktraceIgnoreMatcher::isIgnoredByClass($backtrace, [stdClass::class])); + $this->assertTrue(BacktraceIgnoreMatcher::matchesClass($backtrace[0], [self::class])); + $this->assertFalse(BacktraceIgnoreMatcher::matchesClass($backtrace[0], [stdClass::class])); } public function testFileIgnorance(): void @@ -30,53 +28,22 @@ public function testFileIgnorance(): void $reflection = new ReflectionClass(TestCase::class); $file = $reflection->getFileName(); - $this->assertFalse(BacktraceIgnoreMatcher::isIgnoredByFile($backtrace, [preg_quote($file)])); - $this->assertFalse(BacktraceIgnoreMatcher::isIgnoredByFile($backtrace, [preg_quote(__FILE__)])); - - $backtrace[2] = $backtrace[0]; + $this->assertFalse(BacktraceIgnoreMatcher::matchesFile($backtrace[2], [preg_quote($file)])); + $this->assertFalse(BacktraceIgnoreMatcher::matchesFile($backtrace[2], [preg_quote(__FILE__)])); - $this->assertTrue(BacktraceIgnoreMatcher::isIgnoredByFile($backtrace, [preg_quote($file)])); + $this->assertTrue(BacktraceIgnoreMatcher::matchesFile($backtrace[0], [preg_quote($file)])); $this->assertTrue( - BacktraceIgnoreMatcher::isIgnoredByFile( - $backtrace, + BacktraceIgnoreMatcher::matchesFile( + $backtrace[0], [preg_quote(dirname($file) . DIRECTORY_SEPARATOR) . '*'] ) ); - $this->assertFalse(BacktraceIgnoreMatcher::isIgnoredByFile($backtrace, [preg_quote(__FILE__)])); - } - - public function testStringMatches(): void - { - $this->assertTrue( - BacktraceIgnoreMatcher::doesStringMatchPattern( - 'dev/123/456', - ['dev/123/456'] - ) - ); - $this->assertTrue( - BacktraceIgnoreMatcher::doesStringMatchPattern( - 'dev/123/456', - ['456'] - ) - ); - $this->assertTrue( - BacktraceIgnoreMatcher::doesStringMatchPattern( - 'dev/123/456', - ['dev/.*/456'] - ) - ); - $this->assertTrue( - BacktraceIgnoreMatcher::doesStringMatchPattern( - 'dev/123/456', - ['dev*/456', 'dev/123/*'] - ) - ); + $this->assertFalse(BacktraceIgnoreMatcher::matchesFile($backtrace[0], [preg_quote(__FILE__)])); } public function testEmptyBacktrace(): void { - $this->assertFalse(BacktraceIgnoreMatcher::doesStringMatchPattern('dev/123/456', [])); - $this->assertFalse(BacktraceIgnoreMatcher::isIgnoredByFile([], ['dev/123/456'])); - $this->assertFalse(BacktraceIgnoreMatcher::isIgnoredByClass([], ['dev/123/456'])); + $this->assertFalse(BacktraceIgnoreMatcher::matchesFile([], ['dev/123/456'])); + $this->assertFalse(BacktraceIgnoreMatcher::matchesClass([], ['dev/123/456'])); } } From eb0e57a1e21eced6033d5d3e13573afe507858e1 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 21 Jan 2025 12:00:32 +0000 Subject: [PATCH 2/5] 2 --- .../{BacktraceIgnoreMatcherTest.php => BacktraceMatcherTest.php} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/Unit/Helper/{BacktraceIgnoreMatcherTest.php => BacktraceMatcherTest.php} (100%) diff --git a/tests/Unit/Helper/BacktraceIgnoreMatcherTest.php b/tests/Unit/Helper/BacktraceMatcherTest.php similarity index 100% rename from tests/Unit/Helper/BacktraceIgnoreMatcherTest.php rename to tests/Unit/Helper/BacktraceMatcherTest.php From 1db73aa8800fb605293e7e531bb1464b5bcb29c5 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 21 Jan 2025 15:02:26 +0300 Subject: [PATCH 3/5] 2 --- src/Helper/{BacktraceIgnoreMatcher.php => BacktraceMatcher.php} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Helper/{BacktraceIgnoreMatcher.php => BacktraceMatcher.php} (100%) diff --git a/src/Helper/BacktraceIgnoreMatcher.php b/src/Helper/BacktraceMatcher.php similarity index 100% rename from src/Helper/BacktraceIgnoreMatcher.php rename to src/Helper/BacktraceMatcher.php From 9ccf81318fe9c3f9c7400a1956a0ebda76dfc730 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 21 Jan 2025 15:04:20 +0300 Subject: [PATCH 4/5] 3 --- .../Stream/FilesystemStreamProxy.php | 8 +++--- src/Collector/Stream/HttpStreamProxy.php | 8 +++--- src/Helper/BacktraceMatcher.php | 2 +- tests/Unit/Helper/BacktraceMatcherTest.php | 26 +++++++++---------- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/Collector/Stream/FilesystemStreamProxy.php b/src/Collector/Stream/FilesystemStreamProxy.php index 11cb9b28..82c08335 100644 --- a/src/Collector/Stream/FilesystemStreamProxy.php +++ b/src/Collector/Stream/FilesystemStreamProxy.php @@ -5,7 +5,7 @@ namespace Yiisoft\Yii\Debug\Collector\Stream; use Yiisoft\Strings\CombinedRegexp; -use Yiisoft\Yii\Debug\Helper\BacktraceIgnoreMatcher; +use Yiisoft\Yii\Debug\Helper\BacktraceMatcher; use Yiisoft\Yii\Debug\Helper\StreamWrapper\StreamWrapper; use Yiisoft\Yii\Debug\Helper\StreamWrapper\StreamWrapperInterface; @@ -85,7 +85,7 @@ public static function register(): void /** * It's important to trigger autoloader before unregistering the file stream handler */ - class_exists(BacktraceIgnoreMatcher::class); + class_exists(BacktraceMatcher::class); class_exists(StreamWrapper::class); class_exists(CombinedRegexp::class); stream_wrapper_unregister('file'); @@ -105,8 +105,8 @@ public static function unregister(): void private function isIgnored(): bool { $backtrace = debug_backtrace(); - return BacktraceIgnoreMatcher::matchesClass($backtrace[3], self::$ignoredClasses) - || BacktraceIgnoreMatcher::matchesFile($backtrace[3], self::$ignoredPathPatterns); + return BacktraceMatcher::matchesClass($backtrace[3], self::$ignoredClasses) + || BacktraceMatcher::matchesFile($backtrace[3], self::$ignoredPathPatterns); } public function stream_open(string $path, string $mode, int $options, ?string &$opened_path): bool diff --git a/src/Collector/Stream/HttpStreamProxy.php b/src/Collector/Stream/HttpStreamProxy.php index f2e96339..046b0a12 100644 --- a/src/Collector/Stream/HttpStreamProxy.php +++ b/src/Collector/Stream/HttpStreamProxy.php @@ -6,7 +6,7 @@ use Yiisoft\Strings\CombinedRegexp; use Yiisoft\Strings\StringHelper; -use Yiisoft\Yii\Debug\Helper\BacktraceIgnoreMatcher; +use Yiisoft\Yii\Debug\Helper\BacktraceMatcher; use Yiisoft\Yii\Debug\Helper\StreamWrapper\StreamWrapper; use Yiisoft\Yii\Debug\Helper\StreamWrapper\StreamWrapperInterface; @@ -95,7 +95,7 @@ public static function register(): void /** * It's important to trigger autoloader before unregistering the file stream handler */ - class_exists(BacktraceIgnoreMatcher::class); + class_exists(BacktraceMatcher::class); class_exists(StreamWrapper::class); class_exists(CombinedRegexp::class); stream_wrapper_unregister('http'); @@ -309,7 +309,7 @@ private function isIgnored(string $url): bool } $backtrace = debug_backtrace(); - return BacktraceIgnoreMatcher::matchesClass($backtrace[3], self::$ignoredClasses) - || BacktraceIgnoreMatcher::matchesFile($backtrace[3], self::$ignoredPathPatterns); + return BacktraceMatcher::matchesClass($backtrace[3], self::$ignoredClasses) + || BacktraceMatcher::matchesFile($backtrace[3], self::$ignoredPathPatterns); } } diff --git a/src/Helper/BacktraceMatcher.php b/src/Helper/BacktraceMatcher.php index 121feb82..7b22be2d 100644 --- a/src/Helper/BacktraceMatcher.php +++ b/src/Helper/BacktraceMatcher.php @@ -23,7 +23,7 @@ * args?:array, * } */ -final class BacktraceIgnoreMatcher +final class BacktraceMatcher { /** * @param string[] $patterns diff --git a/tests/Unit/Helper/BacktraceMatcherTest.php b/tests/Unit/Helper/BacktraceMatcherTest.php index 44633453..9fc72c59 100644 --- a/tests/Unit/Helper/BacktraceMatcherTest.php +++ b/tests/Unit/Helper/BacktraceMatcherTest.php @@ -7,19 +7,19 @@ use PHPUnit\Framework\TestCase; use ReflectionClass; use stdClass; -use Yiisoft\Yii\Debug\Helper\BacktraceIgnoreMatcher; +use Yiisoft\Yii\Debug\Helper\BacktraceMatcher; -final class BacktraceIgnoreMatcherTest extends TestCase +final class BacktraceMatcherTest extends TestCase { public function testClassIgnorance(): void { $backtrace = debug_backtrace(); - $this->assertFalse(BacktraceIgnoreMatcher::matchesClass($backtrace[3], [self::class])); - $this->assertFalse(BacktraceIgnoreMatcher::matchesClass($backtrace[3], [stdClass::class])); + $this->assertFalse(BacktraceMatcher::matchesClass($backtrace[3], [self::class])); + $this->assertFalse(BacktraceMatcher::matchesClass($backtrace[3], [stdClass::class])); - $this->assertTrue(BacktraceIgnoreMatcher::matchesClass($backtrace[0], [self::class])); - $this->assertFalse(BacktraceIgnoreMatcher::matchesClass($backtrace[0], [stdClass::class])); + $this->assertTrue(BacktraceMatcher::matchesClass($backtrace[0], [self::class])); + $this->assertFalse(BacktraceMatcher::matchesClass($backtrace[0], [stdClass::class])); } public function testFileIgnorance(): void @@ -28,22 +28,22 @@ public function testFileIgnorance(): void $reflection = new ReflectionClass(TestCase::class); $file = $reflection->getFileName(); - $this->assertFalse(BacktraceIgnoreMatcher::matchesFile($backtrace[2], [preg_quote($file)])); - $this->assertFalse(BacktraceIgnoreMatcher::matchesFile($backtrace[2], [preg_quote(__FILE__)])); + $this->assertFalse(BacktraceMatcher::matchesFile($backtrace[2], [preg_quote($file)])); + $this->assertFalse(BacktraceMatcher::matchesFile($backtrace[2], [preg_quote(__FILE__)])); - $this->assertTrue(BacktraceIgnoreMatcher::matchesFile($backtrace[0], [preg_quote($file)])); + $this->assertTrue(BacktraceMatcher::matchesFile($backtrace[0], [preg_quote($file)])); $this->assertTrue( - BacktraceIgnoreMatcher::matchesFile( + BacktraceMatcher::matchesFile( $backtrace[0], [preg_quote(dirname($file) . DIRECTORY_SEPARATOR) . '*'] ) ); - $this->assertFalse(BacktraceIgnoreMatcher::matchesFile($backtrace[0], [preg_quote(__FILE__)])); + $this->assertFalse(BacktraceMatcher::matchesFile($backtrace[0], [preg_quote(__FILE__)])); } public function testEmptyBacktrace(): void { - $this->assertFalse(BacktraceIgnoreMatcher::matchesFile([], ['dev/123/456'])); - $this->assertFalse(BacktraceIgnoreMatcher::matchesClass([], ['dev/123/456'])); + $this->assertFalse(BacktraceMatcher::matchesFile([], ['dev/123/456'])); + $this->assertFalse(BacktraceMatcher::matchesClass([], ['dev/123/456'])); } } From c5294fe0f1f54239598b579fd8b68e5fd4a6c536 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 21 Jan 2025 17:13:15 +0300 Subject: [PATCH 5/5] fix --- src/Collector/Stream/FilesystemStreamProxy.php | 2 ++ src/Collector/Stream/HttpStreamProxy.php | 1 + 2 files changed, 3 insertions(+) diff --git a/src/Collector/Stream/FilesystemStreamProxy.php b/src/Collector/Stream/FilesystemStreamProxy.php index 82c08335..496b3486 100644 --- a/src/Collector/Stream/FilesystemStreamProxy.php +++ b/src/Collector/Stream/FilesystemStreamProxy.php @@ -5,6 +5,7 @@ namespace Yiisoft\Yii\Debug\Collector\Stream; use Yiisoft\Strings\CombinedRegexp; +use Yiisoft\Strings\StringHelper; use Yiisoft\Yii\Debug\Helper\BacktraceMatcher; use Yiisoft\Yii\Debug\Helper\StreamWrapper\StreamWrapper; use Yiisoft\Yii\Debug\Helper\StreamWrapper\StreamWrapperInterface; @@ -88,6 +89,7 @@ public static function register(): void class_exists(BacktraceMatcher::class); class_exists(StreamWrapper::class); class_exists(CombinedRegexp::class); + class_exists(StringHelper::class); stream_wrapper_unregister('file'); stream_wrapper_register('file', self::class, STREAM_IS_URL); self::$registered = true; diff --git a/src/Collector/Stream/HttpStreamProxy.php b/src/Collector/Stream/HttpStreamProxy.php index 046b0a12..af0f9bc5 100644 --- a/src/Collector/Stream/HttpStreamProxy.php +++ b/src/Collector/Stream/HttpStreamProxy.php @@ -98,6 +98,7 @@ public static function register(): void class_exists(BacktraceMatcher::class); class_exists(StreamWrapper::class); class_exists(CombinedRegexp::class); + class_exists(StringHelper::class); stream_wrapper_unregister('http'); stream_wrapper_register('http', self::class, STREAM_IS_URL);