ju1ius / footprints
PHP 的可过滤回溯
0.2
2023-01-17 16:00 UTC
Requires
- php: >=8.1
README
PHP 的可过滤回溯
安装
composer require ju1ius/footprints
使用
捕获堆栈跟踪
use ju1ius\Footprints\Backtrace; // Capture the current stack trace $trace = Backtrace::capture(); // retrieve the array of stack frames $frames = $trace->frames(); // Capture the current stack trace, skipping the current stack frame $trace = Backtrace::capture(1); // Second argument is the flags for \debug_backtrace() $trace = Backtrace::capture(0, Backtrace::PROVIDE_OBJECT|Backtrace::IGNORE_ARGS); // You can capture error/exception traces too try { // ... } catch (\Throwable $err) { // Capture the exception trace, skipping the two topmost frames $trace = Backtrace::captureThrowable($err, 2); }
过滤堆栈跟踪
要过滤回溯,提供了 Backtrace::accept()
和 Backtrace::reject()
方法,这两个方法都接受一个 callable
断言并返回一个过滤后的 Backtrace
对象。
$predicate
参数具有以下签名: callable(Frame, int, Frame[]): bool
:它接收一个 Frame,它的索引和整个帧数组,并返回一个布尔值,表示断言是否匹配。
Backtrace::accept()
将接受(保留)返回真值的结果的帧,而 Backtrace::reject()
将拒绝(过滤掉)返回真值的结果的帧。
use ju1ius\Footprints\Backtrace; use ju1ius\Footprints\Frame; // Keep only frames for: // * the top-level foo() function // * any method named foo() regardless of it's class. $trace = Backtrace::capture() ->accept(fn(Frame $frame) => $frame->function === 'foo'); // Filters out frames for: // * the top-level foo() function // * any method named foo() regardless of it's class. $trace = Backtrace::capture() ->reject(fn(Frame $frame) => $frame->function === 'foo');
为了方便,这个库提供了一些内置的断言。
内置断言
isFunction(string ...$functionNames)
use ju1ius\Footprints\Backtrace; use ju1ius\Footprints\Predicate; $trace = Backtrace::capture()->reject(Predicate::isFunction( 'foo', 'Acme\\foobar', ));
isClass(string ...$classNames)
use ju1ius\Footprints\Backtrace; use ju1ius\Footprints\Predicate; $trace = Backtrace::capture()->reject(Predicate::isClass( 'Foo', 'Acme\\FooBar', ));
isMethod(string ...$methodNames)
use ju1ius\Footprints\Backtrace; use ju1ius\Footprints\Predicate; $trace = Backtrace::capture()->reject(Predicate::isMethod( // rejects method `bar` of class `Foo` 'Foo->bar', // rejects static method `baz` of class `Acme\FooBar` 'Acme\\FooBar::baz', ));
isNamespace(string ...$namespaces)
use ju1ius\Footprints\Backtrace; use ju1ius\Footprints\Predicate; $trace = Backtrace::capture()->reject(Predicate::isNamespace( // rejects everything in namespace `Acme\Foo` and all it's sub-namespaces. 'Acme\\Foo', ));
isFile(string ...$globPatterns)
IsFile
断言接受 fnmatch
语法接受的 glob 模式。
use ju1ius\Footprints\Backtrace; use ju1ius\Footprints\Predicate; $trace = Backtrace::capture()->reject(Predicate::isFile( // rejects everything in `/src/foo.php` '/src/foo.php', // rejects everything in the `/vendor` directory '/vendor/*', // rejects files having a `.inc.php` extension '*.inc.php', ));
断言组合
可以使用 Predicate::and()
、Predicate::or()
和 Predicate::not()
断言组合断言。
use ju1ius\Footprints\Backtrace; use ju1ius\Footprints\Frame; use ju1ius\Footprints\Predicate; // The following filters out: // * Foo::bar() and Bar::bar() methods (whether static or not) // * top-level baz() and qux() functions $trace = Backtrace::capture()->reject(Predicate::or( Predicate::and( fn(Frame $frame) => \in_array($frame->class, ['Foo', 'Bar']), fn(Frame $frame) => $frame->function === 'bar', ), Predicate::isFunction('baz', 'qux'), ));